2.1 屏幕显示

本节从最基础的显示单元开始介绍,讲述了移动设备如何在屏幕上展现丰富多彩的界面。本节主要内容包括像素的几个常用单位、颜色的编码与使用、屏幕分辨率的获取等。

2.1.1 像素

老子曾说“天下难事必作于易,天下大事必作于细”, Android开发也是如此。纵使App的界面千变万化、绚丽多姿,也都归因于数百万个像素的组合排列,就像万物皆由原子构成一般。像素看似简单,实际有大学问,如果对像素单位不知其所以然,开发时只知一根筋的填数字,结果在模拟器上运行得很好的界面,在真机上很可能显示得东倒西歪,这就是没打好基础的缘故。如果一开始就把像素的基本概念弄清楚,后面就会少走很多弯路,开发起来也会更加得心应手。

Android支持的像素单位有:px(像素)、in(英寸)、mm(毫米)、pt(磅,1/72英寸)、dp(与设备无关的显示单位)、dip(就是dp)、sp(用于设置字体大小)。其中,常用的有px、dp和sp三种。

具体来说,px是手机屏幕上可显示的最小单位,与物理设备的显示屏有关。一般来说,同样尺寸的屏幕(比如5寸的手机)看起来越清晰,像素的密度越高,以px计量的分辨率也越大。

dp与物理设备无关,只与屏幕的尺寸有关。一般来说,同样尺寸的屏幕以dp计量的分辨率是一样的,无论这个手机是哪个厂家生产的,dp大小都一样。

sp的原理跟dp差不多,专门用于设置字体大小。手机在系统设置里可以调整字体的大小(小、普通、大、超大)。设置普通字体时,同数值dp和sp的文字看起来一样大;如果设置为大字体,用dp设置的文字没有变化,用sp设置的文字就变大了。例如,当系统设置普通字体时,18dp与18sp的文字一样大,如图2-1所示;当系统设置大字体时,18dp的文字大小不变,18sp的文字却增大了,如图2-2所示。

图2-1 普通字体的效果图

图2-2 大字体的效果图

所以说,dp与系统设置的字体大小没有关系,而sp会随系统设置的字体大小变大或变小。

dp和px之间的联系取决于具体设备上的像素密度,像素密度就是DisplayMetrics里的density参数。当density=1.0时,表示一个dp值对应一个px值;当density=1.5时,表示两个dp值对应3个px值;当density=2.0时,表示一个dp值对应两个px值。具体的转换函数如下:

        public class Utils {
            //根据手机的分辨率从dp的单位转成为px(像素)
            public static int dip2px(Context context, float dpValue) {

                final float scale = context.getResources().getDisplayMetrics().density;
                return (int) (dpValue * scale + 0.5f);
            }


            //根据手机的分辨率从px(像素) 的单位 转成为dp
            public static int px2dip(Context context, float pxValue) {
                final float scale = context.getResources().getDisplayMetrics().density;
                return (int) (pxValue / scale + 0.5f);
            }
        }

在XML布局文件中,为了让不同设备屏幕拥有统一的显示效果,除了sp用于设置文字大小外,其余要用大小的地方都用dp。在代码中情况又有所不同,Android用于设置大小的函数都以px为单位。无论是LayoutParams里的width和height,还是setMargins和setPadding,参数单位都是px,要想在代码中使用dp设置布局大小或间距,得先把dp值转换成px值。代码示例如下:

              int dip_10 = Utils.dip2px(this, 10L);
              TextView tv_padding = (TextView) findViewById(R.id.tv_padding);
              tv_padding.setPadding(dip_10, dip_10, dip_10, dip_10);

2.1.2 颜色

在Android中,颜色值由透明度alpha和RGB(红、绿、蓝)三原色定义,有八位十六进制数与六位十六进制数两种编码,例如八位编码FFEEDDCC, FF表示透明度,EE表示红色的浓度,DD表示绿色的浓度,CC表示蓝色的浓度。透明度为FF表示完全不透明,为00表示完全透明。RGB三色的数值越大颜色越浓也就越亮,数值越小颜色越暗。亮到极致就是白色,暗到极致就是黑色,这样记就不会搞混了。

六位十六进制编码有两种情况,在XML文件中默认不透明(透明度为FF),在代码中默认透明(透明度为00)。下面的代码分别给两个文本控件设置六位编码和八位编码的背景色。

                TextView tv_code_six = (TextView) findViewById(R.id.tv_code_six);
                tv_code_six.setBackgroundColor(0x00ff00);
                TextView tv_code_eight = (TextView) findViewById(R.id.tv_code_eight);
                tv_code_eight.setBackgroundColor(0xff00ff00);

从图2-3可以看到,代码使用六位编码看不到任何背景,使用八位编码能够看到正确的绿色背景。

图2-3 不同方式设置颜色编码的效果图

在Android中使用颜色有下列3种方式:

1.使用系统已定义的颜色常量。

Android系统有12种已经定义好的颜色,具体的类型定义在Color类中,详细的取值说明见表2-1。

表2-1 颜色类型的取值说明

2.使用十六进制的颜色编码。

在布局文件中设置颜色需要在色值前面加“#”,如android:textColor="#000000"。在代码中设置颜色可以直接填八位的十六进制数值(如setTextColor(0xff00ff00);),也可以通过Color.rgb(intred,intgreen,intblue)和Color.argb(intalpha,intred,intgreen,intblue)这两种方法指定颜色。在代码中一般不要用六位编码,因为六位编码在代码中默认透明,所以代码用六位编码跟不用没什么区别。

3.使用colors.xml中定义的颜色。

res/values目录下有个colors.xml文件,是颜色常量的定义文件。如果要在布局文件中使用XML颜色常量,可引用“@color/常量名”;如果要在代码中使用XML颜色常量,可通过这行代码获取:getResources().getColor(R.color.常量名)。

2.1.3 屏幕分辨率

在App编码中时常要取手机的屏幕分辨率(如当前屏幕的宽和高),然后动态调整界面上的布局。在代码中获取分辨率就是想办法获得DisplayMetrics对象,然后从该对象中获得宽度、高度、像素密度等信息。下面是DisplayMetrics类的常用属性说明。

● widthPixels:以px为单位计量的宽度值。

● heightPixels:以px为单位计量的高度值。

● density:像素密度,即一个dp单位包含多少个px单位。

下面是获取当前屏幕的宽度、高度、像素密度的代码示例。

        public class DisplayUtil {
            public static int getSreenWidth(Context ctx) {
                WindowManager wm = (WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE);
                DisplayMetrics dm = new DisplayMetrics();
                wm.getDefaultDisplay().getMetrics(dm);

                return dm.widthPixels;
            }


            public static int getSreenHeight(Context ctx) {
                WindowManager wm = (WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE);
                DisplayMetrics dm = new DisplayMetrics();
                wm.getDefaultDisplay().getMetrics(dm);
                return dm.heightPixels;
            }


            public static float getSreenDensity(Context ctx) {
                WindowManager wm = (WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE);
                DisplayMetrics dm = new DisplayMetrics();
                wm.getDefaultDisplay().getMetrics(dm);
                return dm.density;
            }
        }

从一个接入设备上获得屏幕分辨率信息,如图2-4所示。该设备为5寸屏幕,分辨率是720*1280,像素密度是2。

图2-4 某手机上的分辨率信息