第 8 章 深入学习UI设计

请参考教材,全面理解和完成本章节内容... ...

复制第七章的工程ch7,将工程目录改名为ch8。

本章,我们开始为「陋习手记」应用添加「陋习」的记录时间和处理状态。同时我们还将设计更丰富的UI,学习到更多使用布局与组件创建UI的知识和技巧。

8.1 升级 Crime 类

打开Crime.java文件,新增两个实例变量。Date变量表示crime发生的时间,Boolean变量表示crime是否已得到处理,如代码清单8-1所示。

代码清单8-1 添加更多变量到Crime(Crime.java)

image

代码中,使用默认的Date构造方法初始化mData变量,变量值为当前日期。该日期将作为crime默认的发生时间。(注意要import java.util. Date)

接下来,为新增变量生成getter与setter方法,如代码清单8-2所示。

代码清单8-2 已产生的getter与setter方法(Crime.java)

image

接下来,使用新组件更新fragment_crime.xml文件中的布局,然后在CrimeFragment.java文件中生成并使用这些组件。

8.2 更新布局

本章结束时,完成后的CrimeFragment视图应如图8-1所示。

image

图8-1 CriminalIntent应用界面(本章完成部分)

提示:有时,信息的录入和显示都可以用同一个界面

要得到图 8-1 所示的用户界面,还需为CrimeFragment的布局添加四个组件,即两个TextView组件、一个Button组件以及一个CheckBox组件。

打开fragment_crime.xml文件,如代码清单8-3所示添加四个组件的定义。可能会出现缺少字符串资源的错误提示,我们稍后会创建这些字符串资源。

代码清单8-3 添加新组件(fragment_crime.xml)

image

注意,Button组件定义中没有android:text属性。该按钮将用于显示Crime的发生日期,显示的日期文字内容将通过代码的方式进行设置。

为什么要在Button上显示日期呢?这是在为应用的后续开发做准备。目前,crime的发生日期默认为当前日期且不可更改。第12章,我们将启用按钮组件,通过单击按钮弹出DatePicker组件以供用户设置自定义日期。

布局定义中还有一些新的知识点可供探讨,如style及margin属性。不过首先还是先把添加了新组件的CriminalIntent运行起来吧。

回到app\res\values\strings.xml文件中,添加必需的字符串资源,如代码清单8-4所示。

代码清单8-4 添加字符串资源(strings.xml)

image

保存修改过的文件,检查确认无拼写错误发生。

8.3 生成并使用组件

CheckBox需显示Crime是否已得到处理。用户勾选清除CheckBox时,Crime的mSolved变量的状态值也需得到相应的更新。

目前,新增Button要做的就是显示Crime类中mDate变量的日期值。

在CrimeFragment.java中,新增两个实例变量,如代码清单8-5所示。

代码清单8-5 添加组件实例变量(CrimeFragment.java)

image

使用Alt+Enter,完成CheckBox相关类包的导入。

接下来, 在onCreateView()方法中,引用新添加的按钮,如代码清单8-6所示设置它的文字属性值为crime的日期,然后暂时setEnabled(false)禁用灰掉它。

代码清单8-6 设置Button上的文字显示(CrimeFragment.java)

image

禁用按钮可以保证它不响应用户的单击事件。按钮禁用后,它的外观样式灰掉了,以此表明它已处于禁用状态。等到第12章我们设置监听器时,会再次启动该按钮。

下面要处理的是CheckBox组件,在代码中引用它并设置监听器用于更新Crime的mSolved变量值,如代码清单8-7所示。

代码清单8-7 侦听CheckBox状态的变化(CrimeFragment.java)

image

使用Alt+Enter快捷键引入OnCheckedChangeListener接口的类包时, Android Studio 将提供分别定义在CompoundButton以及RadioGroup两个类中的接口以供选择。选择CompoundButton接口,因为CheckBox是CompoundButton的子类。

如使用了代码自动补全功能,则可能会在onCheckedChanged()方法的代码上方,看到 @Overrides注解,而该注解在代码清单8-7中是不存在的。忽略此处差异,OnCheckedChangeListener接口中的方法不需要@Overrides注解。

运行CriminalIntent应用。尝试勾选清除CheckBox状态,欣赏一下用于显示日期的禁用Button吧。

8.4 深入探讨 XML 布局属性

本小节,我们一起回顾一下fragment_crime.xml文件中添加的一些属性定义,并解答可能一直困扰你的组件与属性相关问题。

8.4.1 样式、主题及主题属性

style(样式)是XML资源文件含有用来描述组件行为和外观的属性定义。例如,下列样式资源就是用来配置组件,使其显示的文字大小大于正常值的一段代码。

<style name="BigTextStyle">

<item name="android:textSize">20sp</item>

<item name="android:layout_margin">3dp</item>

</style>

我们可以创建自己的样式文件。将属性定义添加并保存在res/values/目录下的样式文件中,然后在布局文件中以@style/my_own_style(样式文件名)的形式引用它们。

如下面的代码清单8-7-1所示, fragment_crime.xml文件中的两个TextView组件,每个组件都有一个引用Android自带样式文件的style属性, 该预定义样式来自于应用的主题Theme,使得屏幕上的TextView组件看起来是以列表样式分隔开的 (仔细观察8-1,标题和明细文字下面分别一条分割线) 。

Theme是各种样式的集合。从结构上来说,主题本身也是一种样式资源,只不过它的属性指向了其他样式资源。(如Android Studio Theme)

代码清单8-7-1 内边距属性的实际应用(fragment_crime.xml)

<TextView
style="?android:listSeparatorTextViewStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/crime_title_label"
/>
<EditText ... />
<TextView
style="?android:listSeparatorTextViewStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/crime_details_label"
/>

使用主题属性引用,可将预定义的应用主题样式添加给指定组件。例如,在fragment_crime.xml文件中,样式属性值?android:listSeparatorTextViewStyle的使用就是一个很好的例子。

使用主题属性引用,相当于告知Android运行资源管理器 “在应用主题里找到名为listSeparatorTextViewStyle的属性。该属性指向其他样式资源,请将其资源的值放在这里”。

所有Android主题都包括名为listSeparatorTextViewStyle的属性。不过,基于主题的整体观感,它们的定义稍有不同。使用主题属性引用,可以确保TextView组件在应用中拥有正确一致的界面观感。

8.4.2 dpsp以及屏幕像素密度

px (pixels) 是像素,就是屏幕上实际的像素点单位。

dpi(dot per inch):屏幕像素密度,每英寸多少像素。对于屏幕来说,dpi越大,屏幕的精细度越高,屏幕看起来就越清楚。比如iphone4的视网膜级的屏幕肯定比iphone 3gs的屏幕像素密度高的多。

dp是与密度无关,在设置边距、内边距或任何不打算按像素值指定尺寸的情况下,通常都使用dp这种单位。

sp类似dp,主要处理字体的大小。

HVGAdensity=160QVGAdensity=120WVGAdensity=240WQVGAdensity=120

VGAVideo Graphics Array,即:显示绘图矩阵,相当于640×480

HVGAHalf-size VGA;即:VGA的一半,分辨率为480×320

QVGAQuarter VGA;即:VGA的四分之一,分辨率为320×240

WVGAWide Video Graphics Array;即:扩大的VGA,分辨率为800×480像素;

WQVGAWide Quarter VGA;即:扩大的QVGA,分辨率比QVGA高,比VGA低,一般是:400×240480×272

请参考教材,理解和完成本节其他内容... ..

8.5 使用图形布局工具

目前为止,布局都是通过手工输入XML的方式创建的。本小节,我们将开始学习使用图形布局工具,并为CrimeFragment创建一个水平模式下使用的布局。

设备旋转时,大多数内置布局类,如LinearLayout,都会自动拉伸和重新调整自己和自己的子类。不过,有时默认的调整并不能充分利用全部用户界面空间。

运行CriminalIntent应用,然后旋转设备查看水平方位下的CrimeFragment布局,如图8-4所示。

image

图8-4 水平模式下的CrimeFragment

要实现这个效果,需创建layout-land目录,在项目导航视图中,右键单击res目录,选择New → Directory菜单项,键入layout-land。可以看到,显示日期的按钮变成了一个长条。水平模式下,按钮如果能与check box并排放置的话会更美观些。

要实现这个效果,需创建layout-land目录,在项目导航视图中,右键单击res目录,选择New → Directory菜单项,键入layout-land。然后将fragment_crime.xml文件复制至layout-land目录下 (有时需要将导航视图切换为Project 模式,才能看见新建的layout-land目录)。

下面我们使用图形布局工具进行一些调整。 打开res\layout-land\fragment_crime.xml文件,切换至可视化的布局设计(Design)视图如图8-5所示。

image

图8-5 布局设计Design视图

在图8-5中,中间区域是布局的界面预览视图。左边是按类别组织的组件面板。右边的上半部分是组件的框架视图,它以树状排列组件,显示了组件是如何在布局中组织的;右边的下半部分是组件属性视图,在此视图中,我们可以查看并编辑框架视图中选中的组件属性。现在,参照图8-6,看看要对布局做哪些调整。

image

图8-6 CrimeFragment的水平模式布局

需要的调整可分为四部分:

  • 新增一个LinearLayout组件(horizontal);
  • 编辑LinearLayout组件的属性;
  • 将Button以及CheckBox组件设置为LinearLayout的子组件;
  • 更新Button和CheckBox组件的布局参数。

8.5.1 添加新组件

在组件面板中选中水平的LinearLayout并将其拖曳到右边的框架视图中,如图8-7所示。

image

图8-7 添加到fragment_crime.xml中的LinearLayout

也可以直接把组件从组件面板中拖曳到预览界面中,从而完成组件的添加。但由于布局组件通常是空的或者被其他视图所遮挡,所以要想获得所需的组件层级结构,很难判断到底该把组件放在预览视图的哪个部分。因此,拖曳组件到右边框架视图中是一种更为容易的方式。

8.5.2 属性视图中编辑组件属性

在框架视图选中新添加的LinearLayout,下面的属性视图中会显示出它的属性。

接下来,我们需要调整LinearLayout的边距来匹配其他组件,参考图8-8完成边距设置。

image

图8-8 在属性视图中设置边距属性

在预览界面底部的Text标签,切换到Text(XML)模式。可看到刚才新增边距属性的LinearLayout元素。

8.5.3 在框架视图中重新组织组件

接下来我们将ButtonCheckBox调整为新增LinearLayout的子组件。返回到图形布局工具,在框架视图中,选中Button后将其拖曳至LinearLayout上。

从框架视图可以看出,Button现在是新增LinearLayout的一个子组件。对CheckBox进行同样的操作,如图8-9所示。

image

图8-9 ButtonCheckBox现在是新增LinearLayout的子组件

如果子组件排列顺序不合适,可在框架视图中通过拖曳重新安排顺序。当然,也可以直接删除框架视图布局中的组件。但要当心,删除组件也会连带删除它的子组件。

回到预览界面,CheckBox貌似不见了。这是因为Button遮挡住了它。LinearLayout考虑到了它第一个子组件(Button)的宽度属性(match_parent),并赋予了它全部空间,以至于CheckBox没有了立身之地,如图8-10所示。

image

图8-10 Button子组件遮住了CheckBox组件

通过调整子组件的布局参数,可让其他子组件获得LinearLayout的平等对待。

8.5.4 更新子组件的布局参数

首先,在框架视图中选中crime_date日期按钮。在属性视图里,单击当前宽度值栏位,在弹出的下拉框中选择wrap_content,如图8-11-1所示。

image

图8-11-1 调整Button的宽度属性值为wrap_content

既然按钮已被放置在LinearLayout里面了,因此也就不再需要边距值了。接下来,删除按钮左右16dp的边距值。如图8-11-2所示。

image

图8-11-2 删除按钮左右16dp的边距值

最后,在布局参数区找到Weight栏位,设置Weight值为1。该栏位在XML文件中对应的属性是android:layout_weight,如图8-11-3所示。

image

图8-11-3 设置Weight值为1

同样,在框架视图里选中crime_solved CheckBox组件,参照Button进行同样的属性调整:设置Width值为wrap_contentWeight值为1,边距值为空值。

完成后,查看预览界面确认两个组件都能正确显现,界面效果如图8-11-4所示。

image

图8-11-4 修改后的界面效果图

代码清单8-9展示了完成后的XML代码。

代码清单8-9 图形工具创建的布局XML(layout-land/fragment_crime.xml)

image

posted @ 2015-08-23 19:52  jlxuqiang  阅读(807)  评论(0编辑  收藏  举报