Android 屏幕适配之基础知识全解

本章节讲述Android屏幕的基础知识

 

 

1.基本概念讲解

 

 

1.1.屏幕尺寸

 

含义:手机对角线的物理尺寸。

单位:英寸(inch),1英寸=2.54cm。

 

 

 

1.2.屏幕分辨率

 

含义:手机在横向、纵向上的像素点数总和。

一般描述成屏幕的"宽x高”=AxB:屏幕在横向方向(宽度)上有A个像素点,在纵向方向(高)有B个像素点。

 

例子:1080x1920,即宽度方向上有1080个像素点,在高度方向上有1920个像素点。

 

UI设计师的设计图会以px作为统一的计量单位。

Android手机常见的分辨率:320x480、480x800、720x1280、1080x1920。

 

附 目前手机主流分辨率列表:

 

链接1:http://screensiz.es/phone

 

链接2:https://material.io/tools/devices/

 

 

 

1.3.屏幕像素密度

 

含义:每英寸的像素点数。

单位:dpi(dots per ich)有的也说PPI(PX PER INCH)。

 

其中:

dpi: 像素密度,在系统软件上指定的单位尺寸的像素数,可认为调整,dpi没有认为调整时==ppi。

 

ppi:像素密度,每英寸所包含的像素数,屏幕物理参数,不可调整,ppi==dpi没有认为调整时。

 

 

 

1.4.密度无关像素

 

含义:density-independent pixel,叫dp或dip,与终端上的实际物理像素点无关。

单位:dp,可以保证在不同屏幕像素密度的设备上显示相同的效果。

 

 

1.5.独立比例像素

 

含义:scale-independent pixel,叫sp或sip。

单位:sp。

 

 

1.6.屏幕尺寸、分辨率、像素密度三者关系

 

 

 

 

1.7.dp与px的转换

 

因为ui设计师给你的设计图是以px为单位的,Android开发则是使用dp作为单位的,那么我们需要进行转换:

 

| 密度类型 | 代表的分辨率(px) | 屏幕密度(dpi)|换算(px/dp)

| 低密度(ldpi) | 240x320 | 120 |1dp=0.75px (过时)

| 中密度(mdpi) | 320x480 | 160 |1dp=1px                              2

| 高密度(hdpi) | 480x800 | 240|1dp=1.5px                             3

| 超高密度(xhdpi) | 720x1280 | 320|1dp=2px                        4

| 超超高密度(xxhdpi) | 1080x1920 | 480 |1dp=3px                6

| 超超超高密度(xxXhdpi) | 1440x3120 | 640 |1dp=4px          8

 

 

Google官方指定按照下列标准进行区分

 

 

在Android中,规定以160dpi(即屏幕分辨率为320x480)为基准:1dp=1px

 

在设计图标时,对于五种主流的像素密度(MDPI、HDPI、XHDPI、XXHDPI 和 XXXHDPI)应按照 2:3:4:6:8 的比例进行缩放。例如,一个启动图标的尺寸为48x48 dp,这表示在 MDPI 的屏幕上其实际尺寸应为 48x48 px,在 HDPI 的屏幕上其实际大小是 MDPI 的 1.5 倍 (72x72 px),在 XDPI 的屏幕上其实际大小是 MDPI 的 2 倍 (96x96 px),依此类推。

 

虽然 Android 也支持低像素密度 (LDPI) 的屏幕,但无需为此费神,系统会自动将 HDPI 尺寸的图标缩小到 1/2 进行匹配。

 

下图为图标的各个屏幕密度的对应尺寸

 

 

 

 

2.屏幕适配问题的本质

 

使得“布局”、“布局组件”、“图片资源”、“用户界面流程”匹配不同的屏幕尺寸。

使得“图片资源”匹配不同的屏幕密度。

 

 

2.1.布局匹配

 

使得布局元素自适应屏幕尺寸。即根据需求使用相应的布局。

开发中,我们使用的布局一般有:

线性布局(Linearlayout)

相对布局(RelativeLayout)

帧布局(FrameLayout)

动画布局(ConstraintLayout)详情:Android ConstraintLayout相关属性详解

绝对布局(AbsoluteLayout)(停止使用)

 

 

2.2.尺寸(size)限定符

 

 

 

 

2.3.最小宽度(Smallest-width)限定符

 

 

 

2.4.使用布局别名

 

 

 

2.5.使用屏幕方向限定符

 

 

 

2.6.图片资源匹配

 

2.6.1.使用.9图片。

 

关于高清设计图尺寸Google官方给出的高清设计图尺寸有两种方案

一种是以mdpi设计,然后对应放大得到更高分辨率的图片。

另外一种则是以高分辨率作为设计大小,然后按照倍数对应缩小到小分辨率的图片。

 

根据经验,我更推荐第二种方法,因为小分辨率在生成高分辨率图片的时候,会出现像素丢失,我不知道是不是有方法可以阻止这种情况发生。

而分辨率可以以1280*720或者是1960*1080作为主要分辨率进行设计。

 

 

 

2.6.2.ImageView的ScaleType属性

 

设置不同的ScaleType会得到不同的显示效果,一般情况下,设置为centerCrop能获得较好的适配效果。

 

 

附:ImageView的ScaleType 属性


1.CENTER /center :按图片的原来size居中显示,当图片长/宽超过View的长/宽,则截取图片的居中部分显示。

2.CENTER_CROP / centerCrop :按比例扩大图片的size居中显示,使得图片长(宽)等于或大于View的长(宽)。

3.CENTER_INSIDE / centerInside :将图片的内容完整居中显示,通过按比例缩小或原来的size使得图片长/宽等于或小于View的长/宽。

4.FIT_CENTER / fitCenter :把图片按比例扩大/缩小到View的宽度,居中显示。

5.FIT_END / fitEnd:把图片按比例扩大/缩小到View的宽度,显示在View的下部分位置。

6.FIT_START / fitStart:把图片按比例扩大/缩小到View的宽度,显示在View的上部分位置。

7.FIT_XY / fitXY:把图片不按比例扩大/缩小到View的大小显示。

8.MATRIX / matrix:用矩阵来绘制,动态缩小放大图片来显示。

 

 

 

2.7.动态设置
 

有一些情况下,我们需要动态的设置控件大小或者是位置,比如说popwindow的显示位置和偏移量等,这个时候我们可以动态的获取当前的屏幕属性,然后设置合适的数值。再比如说banner图设计宽度为屏幕的宽度,高度为屏幕高度的1/3.

 

 

3.Android系统适配原则

Android为了更好地优化应用在不同屏幕密度下的用户体验,在项目的res目录下可以创建drawab目录,开发者在进行APP开发时,针对不同的屏幕密度,将图片放置于对应的drawable目录,Android系统会依据特定的原则来查找各drawable目录下的图片。查找流程为: 

 

3.1. 先查找和屏幕密度最匹配的文件夹。如当前设备屏幕密度dpi为160,则会优先查找drawable-mdpi目录;如果设备屏幕密度dpi为420,则会优先查找drawable-xxhdpi目录。 
 

3.2. 如果在最匹配的目录没有找到对应图片,就会向更高密度的目录查找,直到没有更高密度的目录。例如,在最匹配的目录drawable-mdpi中没有查找到,就会查找drawable-hdpi目录,如果还没有查找到,就会查找drawable-xhdpi目录,直到没有更高密度的drawable目录。 
 

3.3. 如果一直往高密度目录均没有查找,Android就会查找drawable目录drawable目录中的资源适用于所有密度的设备,不管当前屏幕的密度如何,系统都不会缩放此目录中的资源。因此,对于永远不希望系统缩放的资源,最简单的方法就是放在此目录中;同时,放在该目录中的资源最好不要再放到其他drawable目录下了,避免得到非预期的效果。 
 

3.4. 如果在drawable目录也没有查找到,系统就会向比最匹配目录密度低的目录依次查找,直到没有更低密度的目录。例如,最匹配目录是xxhdpi,更高密度的目录和drawable目录查找不到后,就会依次查找drawable-xhdp、drawable-hdpi、drawable-mdpi、drawable-ldpi。

 

举个例子,假如当前设备的dpi是320,系统会优先去drawable-xhdpi目录查找,如果找不到,会依次查找xxhdpi → xxxhdpi → hdpi → mdpi → ldpi。对于不存在的drawable目录直接跳过,中间任一目录查找到资源,则停止本次查找。

 

总结一下图片查找过程:优先匹配最适合的图片→查找密度高的目录(升序)→查找密度低的目录(降序)。

 

 

 

 

 

按上面的原理

只需选择唯一一套分辨率规格的图片资源

(

  每个分辨率下都生成一套图片 是常见的一种方案,这固然是一种解决办法。

  但缺点在于:


  每套分辨率出一套图,为美工或者设计增加了许多工作量 对Android工程文件的apk包变的很大

)

 

那么应该提供哪种分辨率规格呢

 

 

 

如果只提供ldpi规格的图片,对于大分辨率(xdpi、xxdpi)的手机如果把图片放大就会不清晰。

所以需要提供一套你需要支持的最大dpi分辨率规格的图片资源,这样即使用户的手机分辨率很小,这样图片缩小依然很清晰。那么这一套最大dpi分辨率规格应该是哪种呢?是现在市面手机分辨率最大可达到1080X1920的分辨率(dpi=xxdpi=480)


xhdpi应该是首选

 

 

 

原因如下:

xhdpi分辨率以内的手机需求量最旺盛

目前市面上最普遍的高端机的分辨率还多集中在720X1080范围内(xhdpi),所以目前来看xhpdi规格的图片资源成为了首选。

 

 

节省设计资源&工作量

 

在现在的App开发中(iOS和Android版本),有些设计师为了保持App不同版本的体验交互一致,可能会以iPhone手机为基础进行设计,包括后期的切图之类的。

设计师们一般都会用最新的iPhone6和iPhone5s(5s和5的尺寸以及分辨率都一样)来做原型设计,所有参数请看下图


|机型|   分辨率(px)  |  屏幕尺寸(inch) | 系统密度(dpi)|
| ------------- |:-------------:| -------------:| 
|iPhone 5s| 640X1164     |  4 | 332 |
|iPhone 6| 1334x750     |  4.7 | 326 |
| iPhone 6 Plus    | 1080x1920  |5| 400 |


iPhone主流的屏幕dpi约等于320, 刚好属于xhdpi,所以选择xhdpi作为唯一一套dpi图片资源,可以让设计师不用专门为Android端切图,直接把iPhone的那一套切好的图片资源放入drawable-xhdpi文件夹里就好,这样大大减少的设计师的工作量。

 

 

 

 

4.px+dp+sp相互转换

 

工具类

public class DisplayUtil {


    /**
     * 获取屏幕宽度 单位px
     */
    
    public static int getScreenWidth(Context context) {
        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        int width = wm.getDefaultDisplay().getWidth();
        return width;
    }


    /**
     * 获取屏幕高度 单位px
     */
    
    public static int getScreenHeight(Context context) {
        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        int height = wm.getDefaultDisplay().getHeight();
        return height;
    }


    /**
     * 根据手机分辨率从DP转成PX
     */

    public static int dip2px(Context context, float dpValue) {
        float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }


    /**
     * 根据手机的分辨率PX(像素)转成DP
     */
    
    public static int px2dip(Context context, float pxValue) {
        float scale = context.getResources().getDisplayMetrics().density;
        return (int) (pxValue / scale + 0.5f);
    }


    /**
     * 将sp值转换为px值,保证文字大小不变
     */

    public static int sp2px(Context context, float spValue) {
        final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
        return (int) (spValue * fontScale + 0.5f);
    }


    /**
     * 将px值转换为sp值,保证文字大小不变 
     * 由于density和scaledDensity取值一样 所以 px转dp和px转 sp一样
     */

    public static int px2sp(Context context, float pxValue) {
        final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
        return (int) (pxValue / fontScale + 0.5f);
    }


    /**
     * 获取屏幕密度 0.75 1.0 1.5 2.0
     */
    
    public static float getScreenDensity(Context context) {
        DisplayMetrics dm = context.getResources().getDisplayMetrics();
        float density = dm.density;
        return density;
    }
    
}

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值