Android 屏幕适配方案

参考

Android多屏幕适配学习笔记
Android官方提供的支持不同屏幕大小的全部方法 
Android屏幕适配方案 
Android百分比布局库(percent-support-lib) 解析与扩展 
官方适配教程  Develop/API Guide/Best Practices/Supporting Multiple Screens


基本概念

DisplayMetrics dm = getResources().getDisplayMetrics();
屏幕尺寸:   也就是我们平时所说的某某手机是几寸屏,1 inch = 2.54cm,5寸指的是屏幕的对角线的长度。
屏幕分辨率: 指屏幕的宽和高的像素数, 比如华为荣耀3c是720×1280px的。//int screenWidth = dm.widthPixels; int screenHeight = dm.heightPixels;
屏幕密度(dpi/ppi):   每inch的像素数,比如华为荣耀3c 320px/inch。 //int densityDPI = dm.densityDpi;
px:       像素一块显示屏是由很多的光点组成的,每一个光点就是一个像素。由于这些光点很小很密,想想看,在上面提到的3.7寸的手机上,横向有480个光点,纵向有800个光点,所以显示出来的文字或者图片才很细腻平滑。
dip(dp):或者叫dp,这是Android开发中特有的一种度量,称作屏幕无关像素, 它不表示任何具体的长度或者像素点
系数:   google把160dpi当做标准,dpi/160就是这个缩放系数  //float density = dm.density;
sp:     与dp类似,但是可以根据文字大小首选项进行放缩,是设置字体大小的御用单位。

px dp之间互相转化
scale = dpi/160;
px = dp * scale;


ldpi     Resources for low-density (ldpi) screens (~120dpi).
mdpi     Resources for medium-density (mdpi) screens (~160dpi). (This is the baseline density.)
hdpi     Resources for high-density (hdpi) screens (~240dpi).
xhdpi     Resources for extra-high-density (xhdpi) screens (~320dpi).
xxhdpi     Resources for extra-extra-high-density (xxhdpi) screens (~480dpi).
xxxhdpi Resources for extra-extra-extra-high-density (xxxhdpi) uses (~640dpi). Use this for the launcher icon only, see note above.


可以得到:

屏幕密度系数
mdpi  1
hdpi1.5
xhdpi  2
xxhdpi  3
xxxhdpi  4


目前常见分辨率

480*800       dp表示:320dp*533.3dp   hdpi    系数:1.5

720*1280     dp表示:360dp*640dp    xhdpi    系数:2

1080*1920   dp表示:360dp*640dp   xxhdpi   系数:3 

说明:1080*1920跟720*1280屏幕显示没问题,但是480*800屏幕上显示就会有点问题了。我们公司目前UI设计就是以1080×1920分辨率作为标准设计的。所以经常会碰到屏幕适配问题。同时图片为了节省资源,都是放在drawable-xxhdpi下,所以如果不是xxhdpi的屏幕,会对图片进行比例缩放



常用方法

单位转换

//android.util.TypedValue类提供了一个函数,支持把所有的单位换算到px
public static float applyDimension(int unit, float value,  DisplayMetrics metrics)  
{  
    switch (unit) {  
    case COMPLEX_UNIT_PX:  
        return value;  
    case COMPLEX_UNIT_DIP:  
        return value * metrics.density;  
    case COMPLEX_UNIT_SP:  
        return value * metrics.scaledDensity;  
    case COMPLEX_UNIT_PT:  
        return value * metrics.xdpi * (1.0f/72);  
    case COMPLEX_UNIT_IN:  
        return value * metrics.xdpi;  
    case COMPLEX_UNIT_MM:  
        return value * metrics.xdpi * (1.0f/25.4f);  
    }  
    return 0;  
}

获取屏幕宽度

获取屏幕密度,宽度方法
下面介绍一个google推荐使用的方法

                DisplayMetrics dm = getResources().getDisplayMetrics(); //推荐使用,简单粗暴
                float density = dm.density;// 屏幕密度(像素比例:0.75/1.0/1.5/2.0)
                int densityDPI = dm.densityDpi;// 屏幕密度(每寸像素:120/160/240/320)

                float xdpi = dm.xdpi;
                float ydpi = dm.ydpi;

                Log.d(TAG + "  DisplayMetrics", "xdpi=" + xdpi + "; ydpi=" + ydpi);
                Log.d(TAG + "  DisplayMetrics", "density=" + density + "; densityDPI=" + densityDPI);

                int screenWidth = dm.widthPixels;      // 屏幕宽(像素,如:480px)
                int screenHeight = dm.heightPixels;     // 屏幕高(像素,如:800px)

                Log.d(TAG + "  DisplayMetrics", "screenWidth=" + screenWidth + "; screenHeight=" + screenHeight);

                Configuration config = getResources().getConfiguration();
                int screenWidthDp = config.screenWidthDp;   // 屏幕宽(单位是dp)
                int screedHeightDp = config.screenHeightDp; // 屏幕高(单位是dp)
                int desityDpi = config.densityDpi;
                Log.d("LiaBin", "screenWidthDp=" + screenWidthDp + " screedHeightDp=" + screedHeightDp + " desityDpi=" + desityDpi);
我的手机上打印结果如下:
10-13 17:05:10.486 31170-31170/lbb.mytest.demo D/LiaBin: xdpi=320.0; ydpi=320.0
10-13 17:05:10.487 31170-31170/lbb.mytest.demo D/LiaBin: density=2.0; densityDPI=320
10-13 17:05:10.487 31170-31170/lbb.mytest.demo D/LiaBin: screenWidth=720; screenHeight=1280
10-13 17:05:10.487 31170-31170/lbb.mytest.demo D/LiaBin: screenWidthDp=360 screedHeightDp=615 desityDpi=320

此时可以看出我的手机分辨率720*1280px(360*640dp至于打印的结果615而不是640原因是有状态栏或者是虚拟按键吧)  dpi=320  系数320/160=2
注意:config.screenWidthDp/screenHeightDp返回的都是以dp作为单位屏幕宽高,很有用



使用dp存在的问题

使用dp虽然解决了视觉上大小一致的问题,比如80dp的view在160dp宽的屏幕上显示一半(80px),在320dp屏幕上显示的显示效果也是一半(80dp*scale=(320/160)=160px)。
当设备的物理尺寸存在差异的时候,dp就显得无能为力了。为4.3寸屏幕准备的UI,运行在5.0寸的屏幕上,很可能在右侧和下侧存在大量的空白。而5.0寸的UI运行到4.3寸的设备上,很可能显示不下。如下举例
<RelativeLayout
    android:id="@+id/layout"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/scroll_but"
        android:layout_width="150dp"
        android:layout_height="match_parent"
        android:background="#b3efe8"
        android:text="Scroll But"/>

    <Button
        android:layout_width="200dp"
        android:layout_height="match_parent"
        android:layout_alignParentRight="true"
        android:background="@android:color/holo_green_dark"
        android:text="Button 2"/>

</RelativeLayout>
按照Nexus 5(1080*1920) xxhdpi   中间还有一个10dp的空白,xxhdpi说明系数是3,那么屏幕宽就是1080px/3=360dp,所以中间就留有10dp的空白
但是如果是在Nexus S和Nexus One(480*800) hdpi(系数是1.5),却不够显示了,因为此时屏幕总宽度是480/1.5=320,比两个button加起来的350dp还要小,所以不够显示

解决这个问题的方案:
使用百分比
参考
Android屏幕适配方案  http://blog.csdn.net/lmj623565791/article/details/45460089
Android百分比布局库(percent-support-lib) 解析与扩展  http://blog.csdn.net/lmj623565791/article/details/46695347



Tips

以下内容为转载

资源缺失情况下的适配

app运行时,系统会根据属性选择适配的资源进行展示。如果有符合的资源则使用,反之,当符合的资源不存在时,系统会去寻找最相近的可用资源来代替。但是,查找的属性不同,查找的顺序会有所有差异。对dpi属性来说,查找的顺序为,高dpi的资源优先。例如,没能找到hdpi的图片资源,则系统的搜索顺序是drawable-xhdpi->drawable-xxhdpi->drawable-mdip->drawable->drawable->drawable-ldpi。这里drawable被认为比drawable-ldpi更接近hdpi。
另外,对于图片资源在找到相近的资源后,系统还需要对图片进行缩放才会进行使用(否则,可能出现显示不下,或者图片过小的问题,缩放比例是多少,根据dpi的比例来计算缩放比例)。上文的例子中,如果在drawable-xhdpi中找到了资源,那么找到的图片会先缩小到0.75倍以后再使用;如果是在drawable-mdpi中找到了资源,那么图片需要放大到1.5倍以后再使用(放大肯定会造成图片模糊,可能这就是高dpi资源优先的原因所在)。

所以如果你把一张500*500px的图片放在了drawable文件夹下,然后imageview使用wrap-content自适应大小,那么在1080×1920(系数3)的屏幕上显示,那么该图片就被放大到了1500px*1500px,那么屏幕宽都显示不下这张图片了。尽量不要把图片放在drawable中,最好放在drawable-xxhdpi,让图片进行自动压缩,不失真。放大图片会失真。所以设计的时候,最好按照大屏幕来设计切图

有时候,我们的图片资源不一定是从drawable文件夹中读取的,还有可能是从sd卡上读取的,或者从网络上下载的。这个时候,我们需要注意,默认情况下,通过BitmapFactory.decodeFile()函数生成的图片被认为是MDPI的,如果想让图片也获得与drawable文件夹相似的缩放能力,则需要通过BitmapFactory.Option.inDensity属性设置(例如如果图片是为hdpi准备的,则设置为240)。
 对于screan size,查找的顺序则是小尺寸优先,大尺寸放弃。例如,在Galaxy note 2上执行apk时,如果未能找到layout-large资源,则查找顺序为:layout-normal->layout->layout-small,不会查找layout-xlarge。


个人对于多设备UI适配的理解

   以下是个人的一点总结:
   I.   使用简洁的风格来设计UI,让界面变得简单并且一体化,使UI有更加的自适应能力。
   II.  尽量使用match_parent,wrap_content等属性来实现实现UI的自适应,减少dp的使用,尽量不要使用px。
   III. 如果使用dp,那么不要在layout文件中显示的设定数值,而是通过dimens文件来引用,不同设备上就可以使用同一份layout,而通过不同的dimens来适配。
   IV.  可以的情况下,尽量使用.9的png文件,通过无损的缩放来适应UI。
   V.   有些在XML上很难设定的UI细节,可能可以通过java代码动态调整的方案来解决。
   VI.  如果有需要的话,可以通过w720dp,h360dp,1024x768等属性来对市面上销量比较好的手机做针对性的UI适配。
   VII. 没有真机的情况下,可以通过SDK内的模拟器和网上的在线模拟器检查UI效果。
   VIII.对于某些app,可以使用Html5来开发UI(即以app内嵌WebView控件来展示Html5),可能可以获得更加的UI适应效果


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值