赞
踩
屏幕尺寸:屏幕的对角线的长度,以inch为单位。1英寸=2.54cm
屏幕分辨率:横纵向方向像素的大小,纵向像素横向像素,如1920px1080px,单位像素(px)
像素密度DPI( dot per inch):每英寸的像素点数 简称像素密度。
三者关系
像素密度=Sqrt(横向像素横向像素+纵向像素纵向像素)/屏幕尺寸
拿1920X1080,屏幕尺寸为6英寸的手机举例:
1920x1920+1080x1080=4852800,
4852800在开方后约等于2202,
2202/6=367
这个手机的像素密度就是367
屏幕密度(density),density和dpi的关系为 density = dpi/160
名称 | 代表的分辨率(px) | 像素密度范围 | 应用图标icon(2:3:4:6:8) |
ldpi | 240x320 | ?dpi-120dpi | 48*48dp(36*36px) |
mdpi | 320x480 | 120dpi-160dpi | 48*48dp(48*48px)假设切的图标大小为48dp |
hdpi | 480x800 | 160dpi-240dpi | 48*48dp(72*72px) |
xhdpi | 720x1280 | 240dpi-320dpi | 48*48dp(96*96px) |
xxhdpi | 1080x1920 | 320dpi-480dpi | 48*48dp(144*144px) |
xxxhdpi | 1440x2560 | 480dpi-640dpi | 48*48dp(192*192px) |
在Android中,规定以160dpi(即屏幕分辨率为320x480)为基准:1dp=1px
dip和px之间的转换关系 1dip= (手机的像素密度/160dpi)px
当手机的像素密度是160dpi时 1dip = (160/160)*1px 即1dip = 1px
例如:800480 240dpi的手机
1dip = (240dpi/160dpi)px=1.5px
所以如果要在480320 像素密度为160dpi的手机表示320px就需要320dip来表示
如果也在800480,像素密度为240dpi的手机上也用320dip,则320dip代表320(240/160)px=480px
这就说明在像素密度为160dpi手机上如果用160dip表示屏幕的宽度,则将这个160dip
放到像素密度为240dpi的手机上也是一个屏幕的宽度。这样就达到了同样的效果。
如果涉及到dip和sp相互转换时,描述手机时,仅仅用分辨率是不够的,主要是要用到像素密度,因为
这两个单位的转换,涉及到的其实是手机的像素密度。
sp的使用google推荐使用12sp以上的字体大小,设置的比12小,用户可能看到。
不要使用小数,奇数,否则可能造成精度的丢失。
获取屏幕分辨率信息的方法
DisplayMetrics metrics = new DisplayMetrics();
Display display = activity.getWindowManager().getDefaultDisplay();
display.getMetrics(metrics);
int width = metrics.widthPixels; // 屏幕宽度(像素)
int height = metrics.heightPixels; // 屏幕高度(像素)
float density = metrics.density; // 屏幕密度(0.75 / 1.0 / 1.5)
int densityDpi = metrics.densityDpi; // 屏幕密度DPI(120 / 160 / 240)
Android Drawable
我们新建一个Android项目后应该可以看到很多drawable文件夹,分别对应不同dpi
drawable-ldpi (dpi=120, density=0.75)
drawable (dpi=160, density=1)
drawable-mdpi (dpi=160, density=1)
drawable-hdpi (dpi=240, density=1.5)
drawable-xhdpi (dpi=320, density=2)
drawable-xxhdpi (dpi=480, density=3)
drawable-xxxhdpi (dpi=640, density=4)
Android手机加载图片的顺序:
Android SDK会自动屏幕尺寸选择对应的资源文件进行渲染,
如果SDK检测到你的手机是320dpi的,则会优先到drawable-xhdpi文件夹下找
对对应的图片资源,注意,只是优先,如果drawable-xhdpi文件夹下没有相应的
资源图片,则会继续向上,在drawable-xxhdpi的文件夹中,找是否有相应的
图片资源,如果没有,则继续在drawable-xxxhdpi的文件夹下寻找是否有相应
的图片资源,如果仍然没有,则会向下寻找,这时会继续在drawable-hdpi的文件
夹中寻找图片资源,如果仍然没有,则会继续到drawable-mdpi的文件夹中寻找,
如果还是没找,则会到drawable文件夹中找,如果还未找到这,则继续到drawable-ldpi的文件夹中寻找,要是还是没有,编译阶段就会报错。所以,SDK加载图片的顺序是,优先到当前手机对应的像素密度的文件夹下加载图片,如果没找到,则"向上"继续优先寻找和自己像素密度相近的文件夹,如果"向上"未找到,则就"向下",优先找和自己的像素密度相近的文件夹。
ios,android 常用手机屏幕分辨率归纳。
针对IOS,Android 手机分辨率大小、屏幕尺寸、开发尺寸的参考。 在实际页面的开发过程,往往显示屏幕的宽度换算为像素尺寸的1/2。
IOS:
这里写图片描述
Android:
这里写图片描述
所以:ios的@2X图片相当于andriod的xhdpi的图片,ios的@3x图片相当于android的xxhdpi的图片
原文链接:https://blog.csdn.net/zaizai2154365/article/details/51514441
当图像的分辨率大于显示器的分辨率时有两种显示方法,一种是局部显示,即屏幕的像素有多少就显示多少像素,这时只能看到图片的某一部分,可以上下左右的移动来看完整的内容。另一种方法是在屏幕内显示完整的图像,这时图片的像素会被压缩,如2560X1600的图片会删去一部分像素,以1920X1080的分辨率(显示屏的分辨率)来显示。这时可以看到完整的图片内容,不过在细节上是丢失一小部分像素的,如用数码相机的屏幕也可以看到完整的照片,不过感觉很模糊,放在电脑上看就好多了,因为屏幕的分辨率低。
当图像的分辨率小于显示器的分辨率时也有两种显示方法,一种是显示实际大小,即图片的分辨率是多少,就用屏幕上的多少个像素来显示,这时屏幕是以点对点的方式来显示图片,不过图片不是全屏,只在屏幕中央的一部分。另一种方法也是全屏显示,这时图片不是被压缩像素,而是被人为的插入了很多像素,图片看起来很大,满屏显示,不过有效像素很少,比如说可以把一个很小的图标文件放完屏来观看,不过画面惨不忍睹。
**
**
打个比方,720p的屏幕显示720p的图像,尺寸相符,能一个屏幕像素对应一个图像像素,所以效果很好。但如果一个1080p屏幕显示一个720p图像,屏幕像素比图像像素多,一个图像像素要多个屏幕像素来显示,这时候“平滑处理”将起作用,
手机先用插值算法在图中产生新的像素,使图像像素强行转到1080p,然后再在相邻两种颜色,或锯齿之间用平衡算法产生过渡的颜色(因为不是一个屏幕像素显示一个图像像素,所以有的屏幕像素可以用来显示这种过渡颜色),使图像过渡自然。有点类似于抗锯齿,但最终结果就是使图像看上去不锐利,比较模糊。通常分辨率越低的图用更高分辨率的屏幕显示,模糊更严重这是图像显示技术“平滑(优化)处理”的后果。也跟用放大镜看物体,放得越大越觉得粗糙同理。
**
屏幕适配方案一:获取缩放比例,代码动态设置控件的宽和高
这种屏幕适配的思路是,首先按照美工给的设计图的屏幕宽和高作为参考基准确的宽和高,在获取到设备的实际屏幕的宽和高,通过获取到的设备的宽和高,来和美工给的设计图的这个基本的宽和高相除,得到缩放的比例,这样,控件实际显示
的宽和高,就可以通过给控件设定的宽和高的基础上,乘以这个比例,就是该控件在当前设备实际显示的宽和高了,这样就起到了,根据不同的屏幕,等比例的缩放控件的宽高,达到,屏幕适配的效果。
这个思路实现过程中,有以下地方要注意:
第一:要设置控件的宽和高,就需要自定义一个父布局的控件AdapterViewGroup,并在这个控件的onMeasure方法中,获取到当前父布局中包含的所有子布局的宽和高的数据,在将这些子子控件的宽和高的数据乘以缩放比例,然后,在重新设置给这些子控件。
第二:计算设备的宽或者高时,为了适配准确,要记得高度减去状态栏的高度。
第三:有些控件可能测量多次,所以在设置子控件的宽度和高度时,记得只能执行一次这个逻辑,否则,会因为多次的给子控件的宽和高乘以缩放比,导致,子控件偏大或者偏小。
第四:要记得给子控件设置宽高时,也要设置margin和padding的缩放比例。
第五:对于自定义的View,如果想要适配,要先写一个基类自定义的View或者Viewgroup,并在onMeasure方法中,事先处理好子控件或自身的宽和高,在用这个自定义的view去继承这个基类的自定义view或者ViewGroup,对于第三方的自定义控件,如果要拿来直接使用,也是要让这个第三方的自定义控件来继承我们自己写的 基类的自定义View或者ViewGroup。
屏幕适配方案二:分辨率屏幕适配
分辨率屏幕适配的思路是:首先选定一个分辨率为参照基准,假设以320*480的屏幕分辨率为参照基准,在res文件夹下新建values-480x320的文件夹,并将宽分成320分,即1px-320px,将高分成480等分,即1px-480px,生成分辨率对应的dimens.xml文件。例如:lay_x.xml文件,
lay_x.xml文件中的内容如下:
<!-- dp and sp values, must be defind in this file! -->
<!-- view size,you can add if there is no one -->
<dimen name="x_0_5">0.5px</dimen>
<dimen name="x1">1.0px</dimen>
<dimen name="x2">2.0px</dimen>
<dimen name="x3">3.0px</dimen>
<dimen name="x4">4.0px</dimen>
<dimen name="x5">5.0px</dimen>
<dimen name="x6">6.0px</dimen>
<dimen name="x7">7.0px</dimen>
...
<dimen name="x320">320.0px</dimen>
<!-- dp and sp values, must be defind in this file! -->
<!-- view size,you can add if there is no one -->
<dimen name="x_0_5">0.5px</dimen>
<dimen name="x1">1.0px</dimen>
<dimen name="x2">2.0px</dimen>
<dimen name="x3">3.0px</dimen>
<dimen name="x4">4.0px</dimen>
<dimen name="x5">5.0px</dimen>
<dimen name="x6">6.0px</dimen>
<dimen name="x7">7.0px</dimen>
...
<dimen name="x480">480.0px</dimen>
<!-- dp and sp values, must be defind in this file! -->
<!-- view size,you can add if there is no one -->
<dimen name="x_0_5">1.6875px</dimen>
<dimen name="x1">3.375px</dimen>
<dimen name="x2">6.75px</dimen>
<dimen name="x3">10.125px</dimen>
<dimen name="x4">13.5px</dimen>
<dimen name="x5">16.875px</dimen>
<dimen name="x6">20.25px</dimen>
<dimen name="x7">23.625px</dimen>
...
<dimen name="x320">1080.0px</dimen>
<!-- dp and sp values, must be defind in this file! -->
<!-- view size,you can add if there is no one -->
<dimen name="x_0_5">2.0px</dimen>
<dimen name="x1">4.0px</dimen>
<dimen name="x2">>8.0px</dimen>
<dimen name="x3">12.0px</dimen>
<dimen name="x4">16.0px</dimen>
<dimen name="x5">20.0px</dimen>
<dimen name="x6">24.0px</dimen>
<dimen name="x7">28.0px</dimen>
...
<dimen name="x480">1920.0px</dimen>
屏幕适配方案三: smallestWidth 限定符适配
这个方案的原理和屏幕分辨率的方案原理是一样的,系统会根据限定符去对应的文件夹下,寻找资源文件,加入最小宽度是360dp的设备上,系统会自动找打values-sw360dp这个文件夹下的dimens.xml文件,不同的是,分辨率适配是根据px的值进行等比例缩放,而最小宽度限定适配是根据dp的值进行等比例适配的。还有,最小宽度适配,这里的最小宽度是不区分方向的。如下,分别是values-sw360dp文件夹下和values-sw640dp文件夹下的dimens.xml文件。
values-sw360dp\dimens.xml
<!-- dp and sp values, must be defind in this file! --> <!-- view size,you can add if there is no one --> <dimen name="card_common_margin_left">@dimen/dp_15</dimen> <dimen name="dp_m_1">-1dp</dimen> <dimen name="dp_0">0dp</dimen> <dimen name="dp_0_1">0.1dp</dimen> <dimen name="dp_0_5">0.5dp</dimen> <dimen name="dp_1">1dp</dimen> <dimen name="dp_1_5">1.5dp</dimen> <dimen name="dp_2">2dp</dimen> ... <dimen name="dp_500">500dp</dimen> <dimen name="dp_600">600dp</dimen> <dimen name="dp_640">640dp</dimen> <dimen name="dp_720">720dp</dimen> <!-- font size,you can add if there is no one --> <dimen name="sp_6">6sp</dimen> <dimen name="sp_7">7sp</dimen> ... <dimen name="sp_40">40sp</dimen> <dimen name="sp_42">42sp</dimen> <dimen name="sp_48">48sp</dimen>
values-sw640dp\dimens.xml
<!-- dp and sp values, must be defind in this file! --> <!-- view size,you can add if there is no one --> <dimen name="dp_m_1">-1.7778dp</dimen> <dimen name="dp_0">0dp</dimen> <dimen name="dp_0_1">0.1778dp</dimen> <dimen name="dp_0_5">0.8889dp</dimen> <dimen name="dp_1">1.7778dp</dimen> <dimen name="dp_1_5">2.6667dp</dimen> ... <dimen name="dp_500">888.8889dp</dimen> <dimen name="dp_600">1066.6667dp</dimen> <dimen name="dp_640"1137.7778dp</dimen> <dimen name="dp_720">1280.0000dp</dimen> <!-- font size,you can add if there is no one --> <dimen name="sp_6">10.6667sp</dimen> <dimen name="sp_7">12.4444sp</dimen> ... <dimen name="sp_40">71.1111sp</dimen> <dimen name="sp_42">74.6667sp</dimen> <dimen name="sp_48">85.3333sp</dimen>
private static float sRoncompatDennsity; private static float sRoncompatScaledDensity; private void setCustomDensity(@NonNull Activity activity, final @NonNull Application application) { //application final DisplayMetrics appDisplayMetrics = application.getResources().getDisplayMetrics(); if (sRoncompatDennsity == 0) { sRoncompatDennsity = appDisplayMetrics.density; sRoncompatScaledDensity = appDisplayMetrics.scaledDensity; application.registerComponentCallbacks(new ComponentCallbacks() { @Override public void onConfigurationChanged(Configuration newConfig) { if (newConfig != null && newConfig.fontScale > 0) { sRoncompatScaledDensity = application.getResources().getDisplayMetrics().scaledDensity; } } @Override public void onLowMemory() { } }); } //计算宽为360dp 同理可以设置高为640dp的根据实际情况 final float targetDensity = appDisplayMetrics.widthPixels / 360; final float targetScaledDensity = targetDensity * (sRoncompatScaledDensity / sRoncompatDennsity); final int targetDensityDpi = (int) (targetDensity * 160); appDisplayMetrics.density = targetDensity; appDisplayMetrics.densityDpi = targetDensityDpi; appDisplayMetrics.scaledDensity = targetScaledDensity; //activity final DisplayMetrics activityDisplayMetrics = activity.getResources().getDisplayMetrics(); activityDisplayMetrics.density = targetDensity; activityDisplayMetrics.densityDpi = targetDensityDpi; activityDisplayMetrics.scaledDensity = targetScaledDensity; setBitmapDefaultDensity(targetDensityDpi); } /** * 该方法解决 * 从获取 ImageView 的 Bitmap 的宽高,发现获取的宽高和实际的宽高(布局出来观察)不一致的问题 * @param defaultDensity */ private static void setBitmapDefaultDensity(int defaultDensity) { //获取单个变量的值 Class clazz; try { clazz = Class.forName("android.graphics.Bitmap"); Field field = clazz.getDeclaredField("sDefaultDensity"); field.setAccessible(true); field.set(null, defaultDensity); field.setAccessible(false); } catch (ClassNotFoundException e) { } catch (NoSuchFieldException e) { } catch (IllegalAccessException e) { e.printStackTrace(); } }
参考
Android屏幕适配方案分析
https://segmentfault.com/a/1190000019089019
一种非常好用的Android屏幕适配
https://www.jianshu.com/p/1302ad5a4b04
今日头条屏幕适配方案落地研究
https://mp.weixin.qq.com/s/ZUcIKuiKAodKKDGtx44QLQ
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。