加载中…
个人资料
行者无疆-超越
行者无疆-超越
  • 博客等级:
  • 博客积分:0
  • 博客访问:23,556
  • 关注人气:1
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
相关博文
推荐博文
正文 字体大小:

Android图片资源的缩放问题。《深入解析Android5.0系统》节选

(2014-04-24 11:17:02)
标签:

android

it

分类: Android系统

以下内容选自《深入解析Android5.0系统》,京东,当当,亚马逊上有售。

 

1.   图片缩放后对齐的问题

Android的开发中,如何使用图片对很多开发人员是一个很头痛的事。最常见的问题是在一台手机上调试好的UI,在不同dpi的手机上会变形。

Android提供了适配不同dpi的方案,每种dpi都有对应的资源目录。但是我们在开发程序时,对图片资源却不能这样处理,因为图片资源太大,如果我们每种类型的dpi都使用一套图片,应用的尺寸就会急剧膨胀,这可不是我们想看到的结果。

如果只有一套图片,但是有drawabledrawable-mdpidrawable-hdpi等好几个目录,到底放在哪个目录下才能保证在每种dpi的设备上都显示正确了?这个问题无法给出一个简单的答案,只能是根据具体情况分析。

首先,我们要理解图片放在这些目录下会有什么样的后果:

q  drawable目录:这个是所谓的“缺省”目录。如果把图片放在这里,从最终效果上讲,和放在drawable-mdpi目录下是一样的。

q  drawable-nodpi目录:放在这个目录下的图片被装载进内存后,不会被缩放,所谓不缩放的意思是一张72x72像素的图片,在内存中的大小仍然是72x72像素。但是在不同的设备上这张图片看起来大小会不一样。

q  drawable-mdpidrawable-xdpidreawable-xhdpi:如果将图片放在这些和dpi相关的目录下,当程序运行在相同dpi的设备上时,不会被缩放;当运行在dpi不相同的设备上时,会根据dpi之间的换算关系进行缩放。

对于放在drawable-nodpi下的图片比较简单,不用太多解释。但是对于放在其他目录下的图片,Android对图片缩放的目的是什么呢?其实目的和在layout文件中使用dp做为数量单位一样,是为了让一张图片在不同dpi的设备上看起来大小一样。例如,一张放在drawable-mdpi目录下,大小为72x72像素的图片,如果运行在mdpi的设备上,大小还是72x72像素,但是运行在drawable-hdpi的设备上时,尺寸就会被放大为108x108像素。

如果不考虑图片缩放的效果,通过缩放能够让应用适应不同的屏幕,不是很好吗?为什么开发人员还会觉得头痛呢?这是因为在开发中,很多UI效果是通过拼图的方式实现的,如果两张图片缩放后无法对齐,哪怕只有一个像素,也会让效果失色。要解决这个问题,先让我们看看Android是如何进行缩放的。

Android上最常见的四种dpildpi120dpi),mdpi160dpi),hdpi240dpi)和xhdpi320dpi)。这四种dpi的比值是120:160:240:320,化简后就是3:4:6:8。放在mdpi目录下的文件,在不同dpi的设备上缩放后的大小就是n*3/4n*4/4n*6/4n*8/4n为图片大小),如果希望放在mdpi下的图片缩放的效果最好,图片的尺寸必须是4的倍数,否则算法在处理图片的过程中,会不按比例的加入或删除几行(或几列)的像素,这样两张图片中的线条在缩放后就可能会相互错开几个像素。同理,放在ldpi下的图片,大小最好是3的倍数;放在hdpi下的图片,大小最好是6的倍数;放在xhdpi下的图片,大小最好是8的倍数。当然我们并不是要求每一张图都要符合这个规律,但是对于哪些需要精确对齐的图片,这样做还是有必要的。所以一套图片放在哪个目录下不是关键,关键是要确定图片的大小。

注意,这里谈论的图片缩放问题是指在图片装载进内存时就会进行的缩放。除此以外,很多widget在使用图片时还会再次缩放。当然Android也提供了方法禁止widget缩放。例如最常用的ImageView类可以通过设置scaleType属性为“center来禁止缩放,或者把ImageView的宽度和高度设为“wrap_content。但是要明白的是,这里设置了让ImageView不去缩放图片,图片装载时还是会被系统缩放的,很多开发人员在这里迷惑了,以为设置了Widget禁止缩放后,显示效果会和原图一样,折腾很长时间也不知道问题出在哪。

如果正在使用的widget也会去缩放图片,同样也要注意缩放的大小问题,原则也是要让每种图片按相同整数倍进行缩放。还要注意的是,在很多情况下,我们在布局上会让UI的宽度撑满整个屏幕。但是很多相同dpi,差不多大小的设备,它们的屏幕分辨率也可能有细微差别,这样如果根据屏幕宽度来缩放,可能有的设备看上去很完美,有的设备却还是对不齐。这种情况下,如果希望达到最佳效果,只能是根据dpi还有屏幕的宽度来动态的计算出一个最佳的宽度了,既要尽可能的占满屏幕,又要让缩放符合比例。但是这样就太麻烦了,而且也未必在所有的情况下都能有这么一个完美值。最好的办法还是在明白问题所在后,从UI设计上就要避免这种问题的出现。所以类似的问题没有一劳永逸的解决方案,需要我们根据实际情况来调整。

2.   NinePatch图片的缩放

NinePatch 图片是Android中定义的一种特殊的图片格式,它通过在普通图片的边缘做标记的方式把一张图片分成9个部分。如下所示:

Android图片资源的缩放问题。《深入解析Android5.0系统》节选

 

NinePatch图缩放时,图片中1379四个角保持不变。2号和8号区域水平缩放,4号和6号区域垂直缩放,5号区域则全缩放。

但是对NinePath图片最大的误解就是NinePatch的四个角是绝对不缩放的。除非图片是放在目录drawable-nodpi下,或者是运行在相同dpi的设备上,NinePath图片装载进内存时一样会先根据dpi的比值进行缩放。所谓四个角不缩放,是指装载进内存后,再调用缩放函数进行缩放时,四个角的尺寸不会再变化了。所以我们在制作圆角的NinePathc图时要注意,指定的四个角的大小也要符合前面讲的规律,根据所放目录的dpi来决定四个角的像素大小。

3.   为图片指定Density

Android装载图片时会根据当前设备的dpi进行缩放。我们也能在Bitmap类里或BitmapDrawable类里调用setDensity()setTargetDesnsity()来改变一张图片的缩放比例。

public final class Bitmap implements Parcelable {

public void setDensity(int density);

    ......

}

public class BitmapDrawable extends Drawable {

public void setTargetDensity(int density);

    ......

}

当调用这两个方法后,图片将不按照缺省的density来缩放,而是根据我们指定的density

0

阅读 评论 收藏 转载 喜欢 打印举报/Report
后一篇:SEAndroid简介
  • 评论加载中,请稍候...
发评论

    发评论

    以上网友发言只代表其个人观点,不代表新浪网的观点或立场。

    后一篇 >SEAndroid简介
      

    新浪BLOG意见反馈留言板 电话:4000520066 提示音后按1键(按当地市话标准计费) 欢迎批评指正

    新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 会员注册 | 产品答疑

    新浪公司 版权所有