Android屏幕适配基础(2)
2017-10-20 09:21
661 查看
上节课我们留一个问题,项目中的dpi和屏幕dpi如何对应的呢?
一般新建一个项目只有drawable文件夹,并没有这些后缀为“mdpi,nodpi,xhdpi,xxhdpi”的文件夹,如何新建这些文件夹呢?
假如你要适配的屏幕比较特殊,你也可以直接定义自己的屏幕密度文件夹
1 同一张图片,放在不同dpi文件夹下会有什么结果?
我找了一张child.jpg图片,原始为533*300像素,手机屏幕密度为420
结果如图:
mdpi=160dpi,xxhdpi=480dpi,420dpi对应533,那么160dpi对应多少?
我们本能认为是533/(420/160),尺寸应该是207;但是却是533*(420/160)的结果才是1399,这个结果和我们预期的不一样,这是为什么?
因为无论图片放在哪个分辨率的文件夹下,像素总数是不变的。
根据公式 px=dpi*inch,当图片放在低分辨率文件夹中,尺寸就会变大。
沿着这个思路,我们就明白屏幕上显示的尺寸其实要参考三个参数:项目中文件夹的dpi,手机屏幕的dpi,图片原始尺寸,根据这三个参数求出实际屏幕显示的尺寸,而确实Android也是这么处理的。
2 项目中文件夹的dpi(inDensity )
这里需要介绍一个类:TypedValue
这个类的作用是用来存储资源文件的值,可以简单理解为记录当前资源文件夹的屏幕密度
opts.inDensity = density 表示的是当前drawable dpi的值也就是项目中文件夹的dpi(density)
3 屏幕的dpi(inTargetDensity)
上图530行代码:
这句话的目的是获取屏幕的密度,具体如何实现可以看下DisplayMetrics类的getDeviceDensity方法
这是一个系统方法,当App运行的时候会在手机中创建一个build.prop文件用于记录手机的硬件信息,如果root系统可以查看此文件,然后调用此方法获取手机屏幕的密度。
4 inDensity和inTargetDensity如何使用?
追踪java源码到这里:
点击此链接查看C源码
最终定位到doDecode方法
一般新建一个项目只有drawable文件夹,并没有这些后缀为“mdpi,nodpi,xhdpi,xxhdpi”的文件夹,如何新建这些文件夹呢?
假如你要适配的屏幕比较特殊,你也可以直接定义自己的屏幕密度文件夹
1 同一张图片,放在不同dpi文件夹下会有什么结果?
我找了一张child.jpg图片,原始为533*300像素,手机屏幕密度为420
imageView.post(new Runnable() { @Override public void run() { Resources res=getResources(); Bitmap bmp= BitmapFactory.decodeResource(res, R.drawable.child); int w = bmp.getWidth(); int h = bmp.getHeight(); Log.i("TAG", "宽和高: " + w + "*" + h ); } });
结果如图:
mdpi=160dpi,xxhdpi=480dpi,420dpi对应533,那么160dpi对应多少?
我们本能认为是533/(420/160),尺寸应该是207;但是却是533*(420/160)的结果才是1399,这个结果和我们预期的不一样,这是为什么?
因为无论图片放在哪个分辨率的文件夹下,像素总数是不变的。
根据公式 px=dpi*inch,当图片放在低分辨率文件夹中,尺寸就会变大。
沿着这个思路,我们就明白屏幕上显示的尺寸其实要参考三个参数:项目中文件夹的dpi,手机屏幕的dpi,图片原始尺寸,根据这三个参数求出实际屏幕显示的尺寸,而确实Android也是这么处理的。
2 项目中文件夹的dpi(inDensity )
这里需要介绍一个类:TypedValue
这个类的作用是用来存储资源文件的值,可以简单理解为记录当前资源文件夹的屏幕密度
/** * Container for a dynamically typed data value. Primarily used with * {@link android.content.res.Resources} for holding resource values. */
opts.inDensity = density 表示的是当前drawable dpi的值也就是项目中文件夹的dpi(density)
3 屏幕的dpi(inTargetDensity)
上图530行代码:
opts.inTargetDensity = res.getDisplayMetrics().densityDpi;
这句话的目的是获取屏幕的密度,具体如何实现可以看下DisplayMetrics类的getDeviceDensity方法
private static int getDeviceDensity() { // qemu.sf.lcd_density can be used to override ro.sf.lcd_density // when running in the emulator, allowing for dynamic configurations. // The reason for this is that ro.sf.lcd_density is write-once and is // set by the init process when it parses build.prop before anything else. return SystemProperties.getInt("qemu.sf.lcd_density", SystemProperties.getInt("ro.sf.lcd_density", DENSITY_DEFAULT)); }
这是一个系统方法,当App运行的时候会在手机中创建一个build.prop文件用于记录手机的硬件信息,如果root系统可以查看此文件,然后调用此方法获取手机屏幕的密度。
4 inDensity和inTargetDensity如何使用?
追踪java源码到这里:
private static native Bitmap nativeDecodeStream(...);
点击此链接查看C源码
最终定位到doDecode方法
float scale = 1.0f; ... if (env->GetBooleanField(options, gOptions_scaledFieldID)) { const int density = env->GetIntField(options, gOptions_densityFieldID); const int targetDensity = env->GetIntField(options, gOptions_targetDensityFieldID); if (density != 0 && targetDensity != 0 && density != screenDensity) { scale = (float) targetDensity / density; } } ... if (scale != 1.0f) { willScale = true; scaledWidth = static_cast<int>(scaledWidth * scale + 0.5f); scaledHeight = static_cast<int>(scaledHeight * scale + 0.5f); } ... > 第一段代码定义一个scale系数,默认是1不需要缩放 > 第二段代码是原理,用手机屏幕密度除以资源文件密度得到缩放系数,这样就能解释为什么资源放在drawable-420dpi到drawable-xxhdpi,图片是在缩小了 > 第三段是计算缩放后的实际图片宽和高,画布也会随之缩小和放大。
相关文章推荐
- Android屏幕适配基础(1)
- Android屏幕适配的基础知识
- Android屏幕适配 - 屏幕基础理论知识笔记;res资源文件命名与匹配规则
- android 屏幕适配基础(1)
- Android开发基础之屏幕适配
- Android屏幕适配基础
- <Android 基础(二十一)> Android 屏幕适配
- Android基础之屏幕适配
- Android基础_屏幕适配!!
- 【Android】Android 开发新手基础之适配屏幕
- Android 屏幕适配笔记(基础概念)
- android屏幕适配的基础
- <Android 基础(二十一)> Android 屏幕适配
- android基础之屏幕适配基础 sdk版本支持基础
- android屏幕适配基础知识
- Android关于屏幕适配中一些基础概念解释
- 【Android基础知识】关于屏幕适配的学习(support-screens)
- android基础--屏幕适配
- Android实战屏幕适配方案-基础知识
- Android屏幕适配