开闭原则--可变与不变的分离,且容易定制
应用程序的目的是尽可能做到适用于多种设备,这些设备的配置不尽相同,有些不同的物理尺寸,分辨率.为了达到最佳的适配效果,和最少的代码重复,以及最好的可扩展性,就需要分离资源的使用和资源.用一个统一的资源管理者来管理资源.代码通过资源管理者提供的统一的接口来获取资源.这样对于使用者来讲资源的获取的方式是统一,资源者无需关心如何为不同的设备获取不同的资源.这样就把随不同设备变化而变化的代码降到最低,只有资源管理者需要操心不同的设备相关的不同的资源.
比如:字串的获取和使用.最直接的方式就是直接在代码中使用字面常量.但处理多语言时,这就非常的麻烦,需要代码去判断当前系统语言,然后决定使用哪个!但如果使用资源管理器来获取字串,就把代码耦合降到最低:只有资源管理器需要判断当前系统语言,然后去去相应的字串.其他人则无需要关心.
Android当中也是这样子的,代码通过统一的接口获取系统资源,而由资源管理器来处理设备相关性的问题.
Android的资源里面常见的hdpi等这都是什么意思呢?要理解这些,先要了解一下标准的Graphic Design中的一些度量和尺寸的
基本的术语和概念:
屏幕尺寸 Screen size
是指屏幕的物理尺寸,度量的方式是以屏幕对角线的长度,单位是英寸(1英寸=2.54厘米).
屏幕尺寸的大与小,通常能决定屏幕究竟能显示多少内容,比如电脑上能显示的区域一般都要比手机要多.
分辨率Resolution
通常以像素为单位,像素的定义为设备能显示的基本单元,比如480x800,或者1024x768,这意思就是说这个屏幕在长度上能显示1024这么多个点,在高度上能显示768个点.分辨率通常用于表示图像的尺寸.但是分辨率不能代表图像的真实物理尺寸.也不能决定在屏幕上显示的物理尺寸.
屏幕密度Density
是指这个屏幕在单位长度上能显示的像素点数,也就是一英寸上能显示的像素点数,计算方式就是分辨率除以物理尺寸.屏幕密度能反应设备的清晰程度.单位通常是PPI(Pixels Per Inch). PPI值越高,证明屏幕的清晰程度越好,能显示的越清楚.比如苹果的Retina系列屏幕,达到了326PPI.人眼的识别能力在300PPI左右,所以达到326时,人眼就无法分辨出像素点了,所以它显示的就更清晰.
有了屏幕密度的概念就可以看到,同样尺寸(分辨率)的图片在高密度的屏幕上显示的物理尺寸就会小(看起来小了),在低密度的屏幕上显示的物理尺寸就会变大(看起来大了).
所以为什么,没有为MBP视网膜屏做适配的软件,比如PS的图标会看起来模糊.因为MBP视网膜屏幕的密度大大提高,是以前的4倍,所以同样尺寸的图片看起来就会比原来小,是原来的1/4,太小了会看不见的,但是这样使用起来是很不方便的.所以Mac系统为了适应新的视网膜屏幕,就必须把图片进行缩放,放大原来的四倍,这样在用户眼中"看起来"(物理尺寸)图片还是那么大!因为图标被拉大了四倍,当然会模糊了!所以,Mac上面的应用,在视网膜之后必须对应用进行专门的优化和适配.
屏幕的长宽比
物理长度与物理宽度的比例.
如何适配不同的屏幕
适配不同的屏幕的目的也就是让应用在所有的系统上体验一致. 这个不同的平台有不同的策略.有些平台仅是以屏幕分辨率为依据.也就是把设备以屏幕分辨率为分类依据.这也是平常所见的VGA一类的名字的来源:
根据不同的屏幕分辨率来区分不同的设备,比如一些常见的名字:
QVGA: 240*320 Quarter VGA 四分之一的意思(1/2 * 1/2 = 1/4)
HVGA: 320*480 Half size VGA 的意思 二分之一(1/2 * 1 = 1/2)
VGA: 480*640 远古时代的电脑显示器的分辨率,其他的都是以此为基础来缩放
WVGA: 480*800 Wide VGA
SVGA: 600*800 Super VGA
等等,关于分辨率的区分可以参考维基百科:Graphics display resolution
那么,有一些的GUI系统就是以分辨率方式来区分不同的资源.
但是,如前面所述,分辨率不能代表屏幕的清晰程度.同样分辨率的图片,或者同样的长度在高密度的屏幕上看起来就会小,在低密度的屏幕上就会变大!因为它的单位是像素.所以,如果以分辨率作为依据来区分资源,那么就必须为所有不同的分辨率设定资源,并且做适配的优化,否则就不会得到好的显示效果!而想一想这工作量会多大!
屏幕密度无关的单位长度
适配不同的屏幕的目的是什么 呢?就是为了能让
1.应用在不同的平台都能正常的显示,也就是把该显示的显示出来,不能太大(低密度上)也不能太小(高密度上)
2. 排版等能够一致.也就是说元素在大尺寸屏幕上(高分辨率)上要大些,在小尺寸屏幕(低分辨率)上要小些
做为懒惰的人类的目的是:用最小的工作量来适配最多的屏幕,那么怎么做到呢?如果能有一个度量单位能随屏幕变化而变化,那多好啊,这样就可以指定一个长度,让设备自己去处理变化的因素.
所以,就出来了一个新的长度单位DIP---Density Independent Pixels,也就是密度无关的一个抽象的单位长度.它不像像素或者Inch之类的固定不变,而是随着设备的密度而变化的.在低密度的设备上它的值很小,而在高密度的屏幕上它的值会变得大些,这样一来,开发者就可以指定一个长度从而适应不同密度的屏幕,以解决低密度屏幕变大,高密度屏幕变小的问题.详细的来讲:比如某一窗口的长度是100DIP,在低密度的屏幕上DIP值,假如说是1pixel,那么长度就变成了100 pixels;而到了高密度屏幕上,DIP可能会变成了1.5
pixel,这样长度就变成了150pixels. 这样就达到了,以不变应万变的目的.而DIP具体取什么值,也是由设备来给出,因为设备知道它自己是什么样的密度.
Android上的适配策略
Android上面如何解决适配不同尺寸(分辨率)和密度的问题呢?它主要是通过以密度分类,再加上分辨率的方式来减化适配不同尺寸屏幕的工作量.
一般来讲,屏幕分辨率越高,清晰度也应该越高,也即其密度也应该越大,否则会看起来很不清楚,比如4寸的屏幕只显示100个像素,这就近距离看电影,或者看投影仪一样,非常的粗糙和不清晰.所以,Android主要是以屏幕密度来区分不同的设备:
高密度: hdpi (High dots per inch)
中等密度: mdpi (Medium dots per inch)
低密度: ldpi (Low dots per inch)
并且布局中推荐使用密度无关单位dip或dp,来作为长度或者宽度的单位.这样,从理论上来讲,开发者只需要做:
1. 为不同的密度屏幕准备图片资源
(图片是没办法的,因为图片的长度和宽度是固定的像素值,不能够随密度变化而变化,可以强行拉伸,但图片会失真.当然也有9 Patch图片可以解决随意拉伸的问题.但普通的图片的长度和宽度是固定的.
2. 用dip作为单位来指定长度或者宽度
就可以适配所有的设备,让布局在所有的屏幕上都得到比较好的显示效果.
当然,现实的生活没有这么完美,各种设备千差万别.但是总体仍可分为这三大类,为这三大类准备好图片后,其他的只要与某一类较接近,即使稍有拉伸或失真,也不太明显,是可以接受的.所以,对于一般性的应用程序,写一个布局文件在layout中,为三种密度准备图片drawable-hdpi, drawable-mdpi, drawable-ldpi,就足以应对80%的设备.
res/
drawable-hdpi/
ic_launcher.png
drawable-mdpi/
ic_launcher.png
drawable-ldpi/
ic_launcher.png
layout/
main.xml
(这里可能有点过时了,因为现在多了xdpi,而且很多设备也是xdpi的.)
但是光以密度屏幕来分类和处理还不够.随着设备的越来越多,以及屏幕尺寸越来越大,还有就是Tablet的出现,又会出现这样的问题:设备的屏幕密度虽然不高,但其分辨率很高.举个简单的例子:iPad2的分辨率是1024x768,iPhone 4 960x640,但是iPhone 4的密度是326ppi,远大于iPad2.但是,无论密度有多高它的屏幕就那么,最多能显示960x640个像素点,一个1024*768的图片在iPad上可以看到全部,而iPhone上只能看到一大半!这也是为什么用iPad来运行iPhone上的应用程序时,只是以屏幕中间的一部分来模拟显示的原因.
对Android来说也是一样的.如此一来,即使相同的dpi,假如其屏幕尺寸非常大,那么为其准备的图片将被拉伸很大或者显示不全.UI元素也会被拉伸很长.这样并不是很好的体验.对于尺寸大的屏幕应该让其显示更多的内容,而不是把一部分元素拉伸很大.所以,很多手机安卓应用如果未经专门适配,在平板上直接使用体验将会是非常差的.
为了解决这样的问题,就还必须以屏幕尺寸来区分设备
主要有四种屏幕尺寸:small, normal, large and xlarge
这主要是配合屏幕密度来一起使用,比如,适配平板的图片:
drawable-xlarge-hdpi/ic_launcher.png
这里就要提到了密度,尺寸和分辨率的对应关系了. 屏幕分辨率是随设备变化最明显的一个,上面的二种分类方法仅是对屏幕进行的大致的一个分类.虽然屏幕分辨率与密度没有直接的关系,但是所有的设备都基本上一致的(约定俗成?):
ldpi QVGA 240*320 0.8
mdpi HVGA 320*480 1.0
hdpi WVGA 480*800 1.5
hdpi qHD 540*960 1.5
xdpi WXGA 720*1280 2
对于,如何适配,以及如何提供资源可以阅读官方文档,里面讲的还算详细.http://developer.android.com/guide/topics/resources/providing-resources.html
适配不同屏幕的常见问题
虽然有了上述的策略的方式,但是在实际中还是不够的.因为屏幕尺寸的比例与密度的比例并不一致.举例来说HVGA与WVGA相比,宽度的比例与密度的比例是一致的480/320=1.5.所以说宽度上显示的内容一样多.无需操心.但是高度上面就不一样了.800/480 >1.5,这就造成了什么情况呢,也就是同样的东西缩放了1.5倍以后,对于WVGA还会有相当的屏幕空着.或者如果以WVGA为基准时,放到HVGA上就会显示不全. 在qHD上这个问题会更明显.甚至同样的hdpi的WVGA和qHD都会有问题,qHD能显示的内容要多于WVGA.
使用dimension资源来解决问题
从上面的问题可以看出,密度无关的单位解决不了上面的问题.当然也可以选择为每一分辨率做一布局,但这样又会造成大量的重复工作,因为毕竟布局是相同的,仅是元素的高度或者宽度需要考虑分辨率和屏幕密度.
这时可以把高度或者宽度抽象出来放到一个单独 的资源dimensions中,从而把变化的东西降到最小:
比如某个View的高度:
layout/
main.xml # android:layout_height="@dimen/view_height"
values-mdpi
dimensions.xml item name="view_height">20dip</item>
values-hdpi
dimensions.xml 30dip
values-hdpi-960x540
dimensions.xml 40dip
还有一点就是,尽可能用相对的值,如wrap_content和fill_parent(or match_parent)它们不是固定的值而是会在具体布局的时候计算出来.
最后,分享一个坑,资源的默认值并不总是values,drawable和layout. 当你分别在values中指定一个值和在values-mdpi中指定一个值,对于其他的类型如hdpi会使用mdpi中的值,而非values中的值.
另外就是,做图片时需要注意尺寸问题
因为图片的尺寸是以像素为单位,而Android应用程序中多以dip或dp为单位,所以就要注意不同密度上它们的对应关系.让像素仁值和用dip换算过后都是整数.举例来讲HVGA上或者mdpi上1个dip就等于1个像素.但到了WVGA或者hdpi上1个dip就是1.5个像素,所以对于WVGA的图片的尺寸的像素值最好能是1.5的倍数.这样就更方便用dip来定义图片的长度的宽度.
其他有用的资料:
1.Support different Android device configurations with dimension resources
2.Providing Resources
3.
适配特定的分辨率
分享到:
相关推荐
ValueError: Negative dimension size caused by subtracting 5 from 1 for ‘conv2d_1/convolution’ (op: ‘Conv2D’) with input shapes: [?,1,28,28], [5,5,28,30]. 这部分提到的代码是这样的,这是我的分类器的...
The dimension of the circle radius app:strokeWidth dimension The dimension of the circle stroke width app:lineWidth dimension Color used for the progress completed app:progressDuration integer ...
We give a tutorial overview of several geometric methods for dimension reduction. We divide the methods into projective methods and methods that model the manifold on which the data lies. For ...
Dimension
本书是一本与众不同的Android学习读物,是一本化繁为简,把抽象问题具体化,把复杂问题简单化的书。本书避免出现云山雾罩、晦涩难懂的讲解,代之以轻松活泼、由浅入深的剖析。这必将使得阅读本书的读者少走弯路,...
ShapeImageView 图形裁剪ImageView 源码地址:ProjectX 介绍 图形裁剪ImageView,API 21 及以上 使用 View.setOutlineProvider( ViewOutlineProvider) 方式实现,API 18 及以上 使用 ...dimension void setRoundRec
查看了解更多Next.js启动器和模板。预习入门首先,只需克隆存储库并运行npm install # Clone the repogit clone ...
本书是一本与众不同的Android学习读物,是一本化繁为简,把抽象问题具体化,把复杂问题简单化的书。本书避免出现云山雾罩、晦涩难懂的讲解,代之以轻松活泼、由浅入深的剖析。这必将使得阅读本书的读者少走弯路,...
欢迎使用 TvTabLayout 针对TV端的特性对TabLayout进行了适配与开发; 支持图片或颜色值作为Indicator; 效果 Android Studio 集成 // support版本 implementation 'com.owen:tv-tablayout:1.0.4' // androidx版本 ...
主要介绍了解决Error:All flavors must now belong to a named flavor dimension. Learn more at https://d.android.com,需要的朋友可以参考下
Android文字轮播控件 现在的绝大数APP特别是类似淘宝京东等这些大型APP都有文字轮播界面,实现循环轮播多个广告词等功能;这种控件俗称“跑马灯”,而TextBannerView已经实现了可垂直跑、可水平跑的跑马灯了。 效果...
Data Quality: The Accuracy Dimension is about assessing the quality of corporate data and improving its accuracy using the data profiling method. Corporate data is increasingly important as companies ...
森林尺寸创造者目录基本信息公司Forest Dimension的创建者。 它用于设计木制绘画。技术领域使用以下项目创建项目: HTML CSS JavaScript设置要运行此项目,请使用npm在本地安装它: $ npm install$ npm run build...
Rather, Imagining the Tenth Dimension is a mind-expanding exercise that could change the way you view this incredible universe in which we live. Read the book whose companion website (tenthdimension...
A FlowLayout for Android, which allows child views flow to next row when there is no enough space. The spacing between child views can be calculated by the FlowLayout so that the views are evenly ...
基础线性代数库Dimension-dk- 的初始版本将基于 。 在更高的版本中可能会更改它,因为: hmatrix具有更严格的许可证hmatrix依赖于 ,这使得在Windows上安装它相对笨拙。 理想情况下,最终版本将同时支持Windows和ARM...
以qt5.9.0为例,包括已下载好的ActivePerl-5.28.1.0000-MSWin32-x64,qtxlsxwriter-master。
用于Iris Dimension Engine的Overworld Pack的修改版。这是的fork。 请参阅 ,以了解分叉时存储库的许可证。 贡献者和创造者: ( (许多生物群落,物体,发电机构造,洞穴,锯结构。他的背包在这里:) (创造...
On the Estimation of Network Complexity:Network complexity has been studied for