当前位置:   article > 正文

屏幕适配_手机dpi怎么算

手机dpi怎么算

一.明确一些基本概念

屏幕尺寸:屏幕的对角线的长度,以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-120dpi48*48dp(36*36px)
mdpi 320x480120dpi-160dpi48*48dp(48*48px)假设切的图标大小为48dp
hdpi 480x800160dpi-240dpi48*48dp(72*72px)
xhdpi 720x1280240dpi-320dpi48*48dp(96*96px)
xxhdpi 1080x1920320dpi-480dpi48*48dp(144*144px)
xxxhdpi 1440x2560 480dpi-640dpi48*48dp(192*192px)
PPI 全称为 Pixel Per Inch,译为每英寸像素取值,更确切的说法应该是像素密度,也就是衡量单位物理面积内拥有像素值的情况。 ![在这里插入图片描述](https://imgconvert.csdnimg.cn/aHR0cHM6Ly9zdGF0aWMwMDEuaW5mb3EuY24vcmVzb3VyY2UvaW1hZ2UvNDMvOTIvNDNiNjRiYTZhZGI4YTQ0YjZlYWMwMGQ0OGFjNjkzOTIucG5n?x-oss-process=image/format,png)

密度无关像素:density-independent pixel,叫dp或dip,与终端上的实际物理像素点无关 可以保证在不同屏幕像素密度的设备上显示相同的效果

在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
所以如果要在480
320 像素密度为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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
lay_y.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="x480">480.0px</dimen>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
如果想要在1920x1080分辨率的手机上适配,则也需要在res目录下,新建 values-1920x1080文件夹,并新建相应的lay_x.xml和lay_y.xml文件。 要想在1920x1080的分辨率的手机上看到的效果和480x320手机上看到的效果差不多,则需要按照比例对控件进行缩放,这个横向的缩放的比例是 1080/320=3.375 所以,values-1920x1080文件夹下的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">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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
纵向的缩放比例是:1920/480 = 4, lay_y.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">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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
完成在1920x1080文件夹下的dimens.xml文件后,就可以在布局文件中,为 控件指定宽度和高度了,假设设计图上的一个控件的宽度为 320px,高度480px 那么布局中就写 android:layout_width="@dimen/x320" , android:layout_height="@dimen/x480" 当运行程序的时候,系统会根据设备的分辨率去寻找对应的 dimens.xml 文件。 当运行到1920x1080分辨率的手机上时,宽度找到的x320的实际值就是1080px,这样就正好在宽度上铺满全屏,高度x480找到的实际值就是1920px,这样,高度也正好铺满全屏,这样就达到了屏幕适配的效果。这个方案的核心原理就是选取一个基准的分辨率,然后其他分辨率的手机以这个基础分辨率为参考,进行缩放。
这个方案的弊端就是:
1.在res目录下,要写很多的values-xx这样的不同分辨率的文件夹,新建很多的dimes.xml文件,这样就会增大apk的大小。做过这种方案的同学反馈是增大apk的大小为1M~2M。
2.如果在res目录下,如果漏掉了某些分辨率的手机,则会出现,使用默认的大小的值,这样适配效果就不好了。
3.这个方案的单位是px,而google推荐的单位dp,sp。也就是和google推出的屏幕适配的初衷不符,后期如果使用dp作为单位进行适配,则迁移成本很高。




屏幕适配方案三: 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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
在具体的布局中使用: 为控件指定宽度和高度了,假设设计图上的一个控件的宽度为 320dp,高度480dp 那么布局中就写 android:layout_width="@dimen/dp_320" , android:layout_height="@dimen/dp_480"
最小宽度适配相比分辨率适配的优点是:
1.无论手机的分辨率是多少,像素密度多少,90%的手机的最小宽度都是360dp,所以,在res目录下,需要新生成的dimens.xml文件要少很多,这样,apk的大小就会小很多, 采用这种适配方案的同学提供的数据是,增加apk的大小500Kb左右。
2.这种方案的单位是sp,和dp,对于适配字体更加的灵活。
3.分辨率适配是根据设备的分辨率找到相应的限定符下的文件夹中的dimes.xml文件,但是如果找到相应 的限定符的dimens.xml文件,则会使用默认的值,这样适配效果就会不好,最小宽度适配,是根据重大向小的方法进行查找,比如,360dp宽度的手机未找到相应限定符values-sw360dp目录下的dimens.xml文件,则会继续查找values-sw320dp这个目录下的dimens.xml文件,这样,即使未找到values-360dp文件夹下的dimens.xml文件,也会使用values-sw320dp这个目录下的,这样适配的效果和values-sw360dp目录下的dimens.xml文件中的适配效果也差不太多,这样的适配效果会比使用分辨率适配那种默认值的适配效果要好。即时,全部未找到,也会使用默认values的。

屏幕适配方案四:今日头条方案 今日头条方案的原理是,将美工的设计图的屏幕作为基准屏幕尺寸,然后将所以屏幕的宽度都看成是这个基准宽度375dp, 则得到如下公式: density = 屏幕宽度px/375(设计宽度)dp, 当然可以根据px = density * dp,这个公式进行推导,density = px/dp 得到一个density,然后将这个density设置给系统的Metircs的density。 假设,美工是按照375dp的屏幕设计的ui,一个宽度为187dp的view,在设计图上显示的宽度占比是屏幕的一半,那么,如果要在1920x1080的屏幕上进行适配,则新的density=1080px/375dp = 2.88,则这个view显示的宽为 187dp * 2.88 =538.56px, 538.56px/1080px = 0.4986,刚好这个占比等于0.5,也就是在1920x1080屏幕上显示的宽度正好是屏幕的一半。
今日头条适配方案的优点:
1.侵入性小
2.使用成本低
3.可适配第三方控件和系统控件。
缺点:
1.会全局影响app的大小,例如,一些第三方的控件,如果设计的不是按照375dp为基准的设计图设置的,则会 导致控件的大小变形(本质是第三方控件的缩放比例和我们自身按照设计图设计的缩放比例不一致,导致我们自己按照 设计图的控件在某些屏幕上可能要放大两倍,但是第三方未按照375屏幕为设计图的控件不会放大两倍,导致,整体比例看起来就不协调)。
2.就是如果在系统设置中切换字体,再返回应用,字体并没有变化。于是还得监听下字体切换,调用 Application#registerComponentCallbacks 注册下 onConfigurationChanged 监听即可
   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();
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62




参考


Android屏幕适配方案分析
https://segmentfault.com/a/1190000019089019


一种非常好用的Android屏幕适配
https://www.jianshu.com/p/1302ad5a4b04


今日头条屏幕适配方案落地研究
https://mp.weixin.qq.com/s/ZUcIKuiKAodKKDGtx44QLQ

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/喵喵爱编程/article/detail/984727
推荐阅读
相关标签
  

闽ICP备14008679号