本章主要介绍了一些进阶的界面设计知识,以及如何用图形化界面设计 UI (虽然不推荐日常使用,但是至少要知道,特别是在 Android Studio 2.2 推出之后,可以直接查看设计蓝图,更为直观并且容易调整细节)。
GitHub 地址:
完成第八章,未完成挑战
完成第八章的挑战
1. 样式(style) 与 主题(theme)
为什么我们需要样式(style)? 因为当界面有统一风格时,就不需要针对每一个控件单独写属性了,规定几种样式(style)即可。
style 是 XML 资源文件,含有用来描述组件行为和外观的属性定义。例如,下面的样式能让其显示的文字大小大于一般的值。
<style name="BigTextStyle">
<item name="android:textSize">20sp</item>
<item name="android:padding">3dp</item>
</style>
我们可以在 res/values/ 目录下的样式文件中写入自己需要的属性定义,然后再布局文件中以 @style/my_own_style(file name)
的形式引用
什么是主题(theme)呢?主题是各种样式的集合,从结构上来说,主体本身也是一种样式资源,不过它的属性指向了其他样式资源
主题属性引用 顾名思义就是将预定义的应用主题样式添加给指定组件,比如给 TextView 控件定义下面的属性:
<style="?android:listSeparatorTextViewStyle">
意味着告诉 Android 运行资源管理器:“在应用主题里找到名为 listSeparatorTextViewStyle 的属性。该属性指向其他样式资源,请将其资源的值放在这里。”
2. margin 与 padding
Android 布局文件中的 margin 和 padding 跟 Web 编程的一样,具体定义如下:
- margin 指的是外边距,即指定视图组件之间的距离
- padding 指的是内边距,即指定视图外边框与其内容间的距离
两者之间区别如下图:
3. dp、sp 及屏幕像素密度
Android 使用密度修饰 drawable 目录(如 drawable-xhdpi)下的图像文件会自动适配不同像素密度的屏幕。那么问题来了,加入图像完成了自动适配,但是边距无法缩放适配,或者用户配置了大于默认值的文字大小,会出现什么意外呢?
为了解决这些可能的问题,Android 提供了密度无关的尺寸单位(density-independent dimension unit)。使用这种单位,可在不同屏幕密度的设备上获得同样的尺寸。无需进行麻烦的转换计算,应用运行时,Android 会自动将这种单位转换成像素单位。
1. dp (dip, density-independent pixel) 密度无关像素
所谓密度无关,即和屏幕的像素密度没有关系。1dp 单位在设备的屏幕上总是等于 1/160 英寸。使用 dp 的好处是,无论屏幕密度如何,总能获得同样的尺寸。
px = dp * (dpi / 160)
其中,dpi 即等于我们常说的 ppi,计算公式即为
ppi = sqrt(屏幕横向像素数的平方 + 屏幕纵向像素数的平方)/ 屏幕对角线英寸数
那么常见的 mdpi, hdpi 是什么呢?对应关系如下图:
也就是说 160ppi 像素密度的屏幕,又叫 mdpi 的屏幕,程序中写的 1dp 在上面呈现的就是 1 像素(pixel,px)。
2. sp (scale-independent pixel) 缩放无关像素
这种像素也与屏幕无关,但是与设置有关,一般用来设置文本的大小。
4. android:layout_weight 属性
在 LinearLayout 中,有这样一个特殊属性,它能让你自由分配摆放部件后的空间,避免大量留白。它就是 android:layout_weight,这里的 weight 是权重的意思,也就是说,每个部件都有自己的权重,用于分配摆放部件后剩余的空间。也就是说,如果两个部件权重都是 1 时,它们平分摆放它们之后的剩余空间。
但是这样就会出现一个问题,由于分配的是剩余的空间,所以在两个部件 layout_width 属性不一致(wrap_content 不算一致)时,layout_weight 属性不能使部件平分整块屏幕。如果想要平分怎么办呢?把两个部件的 layout_width 都设为 0dp 再保持其 weight 相等,也就是把整块屏幕都当做剩余空间,就能平分整块屏幕了。
5. 挑战练习:日期格式化
我使用的是 SimpleDateFormat 类,它能通过字符串来直接格式化 Date 类型的数据。
SimpleDateFormat sdf = new SimpleDateFormat("EEEE, MMM d, y", Locale.US);
mDateButton = (Button) v.findViewById(R.id.crime_date); mDateButton.setText(sdf.format(mCrime.getDate()));
GitHub Page: kniost.github.io
简书://www.greatytc.com/u/723da691aa42