记笔记
俗话说:好记性不如烂笔头。当然,这并不是说我们的脑子不好使,也不是叫我们不要用脑子记东西,而是提醒我们解放脑力,让大脑从事更有价值的思考。因此,这节课我们将会创建一个笔记本,用来记录课堂重点,但是,我们需要什么样的笔记本呢?我曾经在《你的灯亮着吗?》里读到这样一句话:如果某人能够解决这个问题,但是他本人却不会遇到这一问题时,那么你们首先要做的就是让他也感受到这个问题。最近公司来了一批校招生,我找了个机会混进去听了一节入职前的技术培训,我想知道在课堂上把手机掏出来记笔记是一种什么样的感觉。
在课堂上,每当我想记点什么时,就会不自觉地拿起纸笔而不是手机,而且,用手机记笔记远没用纸笔来得随意自如。随后,我找了一些大学生和中学生,分别了解一下他们记笔记的情况,结果发现,他们记笔记的方式真是多种多样,有的直接记在书上,有的记在专门的笔记本上,有的记在练习册上,有的记在卷子上,有的甚至用手机把老师的板书直接拍下来……不难看出,他们的做法是怎么方便就怎么记,就目前而言,企图用一个手机应用来取代他们现有的做法显然是不现实的,也没必要,用户有权选择他们认为适合的做法,而我们的职责只是提供必要的帮助和支持。
那么,我们可以提供什么样的帮助和支持呢?想想看,现有的自由零散的做法会导致什么问题呢?最直接的影响是很难快速找到想要的内容,因为它们可能遍布各处,这种时候要是有个索引或者目录什么的就好了……Bingo!我们可以创建一个应用,帮助用户建立这个索引,虽然用户也可以另外找本小册子建立索引,但我们可以通过一个标签系统帮助用户快速找到相关的内容。这样,用户既可以保留现有的自由的记笔记习惯,又可以获得新的有序的管理效果。那么,用户应该在何时以及如何建立这个索引呢?
当然是越早越好!比如说,用户可以在每晚做完作业之后稍稍整理一下笔记,然后为它们创建一些条目并贴上标签。用户不必为所有笔记创建条目,可以挑选重要的来创建,这个过程本身就可以加深对知识的理解和巩固对知识的记忆。至于条目的内容,用户可以引用课本或者老师板书的原话,也可以用自己的话来概括复述,还可以直接引用课本或者练习册的页码和位置(段落、题号或者标记)等等,这个过程可以帮助用户熟悉如何根据条目的内容找到对应的笔记。
现在,用Visual Studio打开项目,在Models文件夹里创建一个Note类,并让它继承NotificationObject类:
代码 1
根据前面的讨论,Note类应该包含以下三个属性:
属性名字 |
属性类型 |
属性描述 |
Id |
Guid |
唯一标识 |
Course |
string |
课程名称 |
Content |
string |
笔记内容 |
Tags |
string |
笔记标签 |
表 1
其中,Id是只读属性,根据上节课的经验,我们需要给它创建以下两个构造函数:
代码 2
它们分别用于新建和编辑两种情景。Course、Content和Tags三个属性的set访问器均需调用RaisePropertyChanged方法,此方法是从NotificationObject类继承过来的。Tags属性可以包含一个或多个标签,当Tags属性包含多个标签时,标签与标签之间将会使用逗号(,)进行分隔。
数据存储方面,我们将会直接使用上节课重构的结果——JsonDataStore类。打开App.xaml.cs文件,在App类里创建一个NoteStore静态属性:
代码 3
接下来,是时候考虑一下用户体验了。
设计用户体验
我们知道,每门课都有自己的笔记,就像每门课都有自己的作业一样,所以这里将会仿效作业本的做法,利用Pivot控件的特点,让每个Pivot项显示一门课程的笔记。现在,切换到Expression Blend,创建一个Windows Phone Pivot Page,并把它命名为NoteBookPage.xaml,完了之后把Pivot控件的Title属性设为"笔记本",把两个Pivot项的Header属性分别设为"销售心理学"和"行为金融学":
图 1
需要说明的是,Application Bar上的按钮没有设置图标,这是因为我没有找到合适的,下次有时间我自己设计一个放上去。那么,标题下面这么大的一块空位应该怎么安排呢?
首先,有两点我们是明确的,第一,我们需要列出笔记,第二,我们需要提供某种方式让用户切换标签。根据以往的经验,ListBox最适合用来列出笔记,至于切换标签的方式,我觉得SL for WP Toolkit的ListPicker也是一个不错的选择。此时,我的脑子里浮现出第一个设计:
图 2
然而,很遗憾,我对这个设计并未感到满意。第一,在手机屏幕这样的有限空间里,我们应该始终坚持把尽可能多的空间留给最重要的内容,ListPicker作为一个辅助元素应该只在用户需要切换标签的时候才显示,否则把空间腾出来,这样可以显示更多笔记。第二,笔记本和作业本、课程表有着类似的布局设计,但ListPicker的存在破坏了布局设计的一致性,这点我实在无法容忍。那么,怎样才能让ListPicker"呼之则来挥之则去"?
我们可以调整ListBox的大小,使之充满整个Pivot项,并把ListPicker藏在屏幕下方外面,然后在Application Bar上放置一个按钮,当用户单击这个按钮时,ListPicker将会从屏幕下方外面向上平移,直至屏幕底部:
图 3
这样,用户就可以通过ListPicker切换标签了。此时,我的脑子里冒出一个问题,为什么不直接以这种方式显示标签列表,而是大费周章地通过ListPicker打开一个新的页面呢?显然,我找不到合适的理由说服自己把ListPicker留下,同时,这个问题也给我带来了新的灵感。我们可以让显示标签的ListBox取代ListPicker,当用户单击Application Bar上的按钮时,ListBox将会从屏幕下方外面向上平移,直至覆盖显示笔记的ListBox为止,当用户选好标签之后,显示标签的ListBox将会向下平移,直至屏幕下方外面为止。
现在,把ListPicker删除,然后把一个ListBox添加到LayoutRoot,并调整它的大小,使之充满整个屏幕(覆盖后面的Pivot控件)。此时,Objects and Timeline面板上面的对象应该是这样的:
图 4
接着,把它向下平移,直至它的顶部和Pivot控件的底部重叠为止:
图 5
此时,它的Height、VerticalAlignment和Margin三个属性都会自动做出相应的调整:
图 6
接下来,我们将会为它创建动画。
单击Objects and Timeline面板上的+按钮:
图 7
在弹出的Create Storyboard Resource对话框里输入一个名称,然后按OK关闭对话框:
图 8
此时,Objects and Timeline面板将会变成这样:
图 9
确保ListBox处于选中状态,把播放指针拖到0.5秒的为止,然后把ListBox向上平移,直至和Pivot控件完全重叠为止。此时,Objects and Timeline面板将会变成这样:
图 10
看到这里,你可能会问,为什么只有结束时间的关键帧?你也可以手动设置开始时间的关键帧,如果没有设置,那么对象原本的状态将会默认为开始时间的关键帧。
当用户选好标签之后,我们需要把ListBox隐藏起来,不难想象,隐藏动画其实是显示动画的反转,那么,如何创建反转动画呢?非常简单,单击+按钮旁边的箭头,然后选择Duplicate:
图 11
此时,Expression Blend会为你创建一个ShowTagsStoryboard_Copy1动画。单击+按钮旁边的箭头,然后选择Rename把它重命名为HideTagsStoryboard。接着,再次单击+按钮旁边的箭头,然后选择Reverse反转动画。好了之后单击+按钮旁边的X按钮关闭Storyboard。