巧用Android图片资源,打造更精致的APP
hjl_168562
8年前
<h2>前言</h2> <p>由于android系统的开放性,以及IOS的相对封闭。第三方设备想要使用苹果的OS,目前来说是不可能。所以,各厂商纷纷的投入了android的怀抱, android阵营也越来越强大,如今移动操作系统也就是android和ios的天下。也正是因为android的开放性,可定制度高,导致了各种屏幕尺寸、各种分辨率的android设备 铺满了手机、平板、智能电视、手表、盒子、智能硬件…等各种应用场景。</p> <p>作为一名有逼格的程序猿,在面对如此众多的尺寸和分辨率设备上,想要打造一款通吃的app,势必是要花费一番功夫的。</p> <h2>drawable-xxx资源文件夹</h2> <p>还好google已经为我们想好了对策,为不同的分辨率提供不同的drawable资源。</p> <p>先来看看微信的android客户端,在图片资源的使用</p> <p><img src="https://simg.open-open.com/show/33adcc1c3fd997734ee5f1ff96c13bef.png"></p> <p>在res目录下,以drawable开头的文件夹占了一大半,后面以-hdpi、-land、-mdpi、-xhdpi…等文件夹以适配不同分辨率的机型。</p> <p>可能有人会说,开发应用只用适配hdpi或者xhdpi就可以了,同样可以显示出来嘛!干嘛搞这么多版本,浪费空间,还麻烦!</p> <p>如果是这样的想法,那只能说你的应用受众群体还没达到一定程度,或者不追求细节的完美。对于高逼格的应用来说,哪怕一个像素的缺失,都是不完美。</p> <p>废话了这么多,先来看卡google官方对dp的定义</p> <p>Density-independent pixel (dip)</p> <p>A virtual pixel unit that you should use when defining UI layout, to express layout dimensions or position in a density-independent way. The density-independent pixel is equivalent to one physical pixel on a 160 dpi screen, which is the baseline density assumed by the system for a “medium” density screen. At runtime, the system transparently handles any scaling of the dp units, as necessary, based on the actual density of the screen in use. The conversion of dp units to screen pixels is simple: px = dp * (dpi / 160). For example, on a 240 dpi screen, 1 dp equals 1.5 physical pixels. You should always use dp units when defining your application’s UI, to ensure proper display of your UI on screens with different densities.</p> <p>独立像素单位(Density-independent pixel (dp)</p> <p>一个虚拟的单位,用来决定UI布局的。用来表述布局的尺寸或者位置。 dp是一个与屏幕密度有关系的单位,dp与像素的换算关系为 px = dp * (dpi / 160)。例如在240密度(dpi)的屏幕上一个dp等于1.5个像素。以后我们应该尽量使用dp单位布局,不要使用像素单位。这样会使你的app屏幕兼容性更好</p> <p><img src="https://simg.open-open.com/show/a547a8e829add9333d7edaf79b8e1ab3.png"></p> <pre> 为了更直观的感受,他们之间的区别,在1920x1080的手机屏幕上: </pre> <ul> <li> <p>将同一张96×96像素的png图片,分别放到hdpi、xhdpi、xxhdpi文件夹中,宽高均以wrap_content显示</p> <p><img src="https://simg.open-open.com/show/979d5cd31344232a30c226bea3012790.png"></p> <p>可以看到,适配较低drawable-dpi的资源图片,显示尺寸相对较大,但是清晰度差。而适配高dpi的图片,显示尺寸相对较小,但是锐度高,比较清晰!</p> </li> <li> <p>将像素分别为72×72、96×96、144×144像素的图片,分别放置于hdpi xhdpi xxhdpi文件夹中,宽高以wrap_content显示效果。</p> <p><img src="https://simg.open-open.com/show/1f2912828413715214a45756602a68e8.png"></p> <p>可以看到,不同大小的图片,放到不同的资源文件夹下,最终在屏幕上显示的大小居然一致!但是144×144像素对应的图片显示的最精致和清晰。</p> </li> </ul> <p>到这里,应该能看出图片资源与drawable文件夹对应的关系了。即使不使用高质量的图片,仍然可在高分辨率的屏幕上进行对应的显示,但是牺牲了控件显示的精细度,屏幕dpi越高显示越不清楚。如果一张高清晰度的照片,被放置在不恰当的drawable下也不能准确的还原应有的尺寸和清晰度。</p> <p>对比IOS对图片的定义,2倍图即-xhdpi密度,3倍图即-xxhdpi密度。</p> <p><img src="https://simg.open-open.com/show/78ae1b9b2e75cad074c3630a25d74614.jpg"></p> <p>所以,想要让应用中的icon显示的更加精致,那就需要对应的配置不同像素的图片。</p> <h2>使用wrap_content代替dp</h2> <p>很多人在处理带图片的icon的时候,会指定其大小,如:</p> <pre> <ImageView android:layout_width="45dp" android:layout_height="45dp" android:src="@drawable/icon_hdpi"/> </pre> <p><em>wrap_content</em> 可理解为包裹内容,当控件被设置为 <em>wrap_content</em> 将会根据实际大小进行显示。相比直接设置dip的方式,在图片的显示上或多或少的会存在缩放。也就会导致图标会显示的不够精致。</p> <pre> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/voip_camerachat_xhdpi"/> </pre> <p>下面以应用中常用的tabbar,作为对比:(以1920×1080屏幕像素截图)</p> <ul> <li>图1</li> </ul> <p><img src="https://simg.open-open.com/show/23121523e017cce3bff269a49a9dba54.png"></p> <ul> <li>图2</li> </ul> <p><img src="https://simg.open-open.com/show/0f432409ea17a56247deb91aef94ebb4.png"></p> <p>图1中的icon统一被设置了固定的大小24dp,同时只在drawable-xhdpi中进行图片的适配。可以看出图片被不同程度的拉伸,icon显示较模糊。</p> <p>图2将icon的宽高均设置为 <em>wrap_content</em> ,同时在drawable-xxhdpi中进行了适配。图2的icon锐度有所提高,因为wrap_content属性的设置,本身icon图片大小不同,导致icon显示的大小不一致。所以完美的方案就是,需要UI提供尺寸均一的大图片,适配到drawable-xxhdpi下.</p> <p>相比微信的高清图片资源,展现的精致效果:</p> <p><img src="https://simg.open-open.com/show/9f581b645af1bcec998dee8c53a5fd3b.png"></p> <h2>SVG</h2> <p>Scalable Vector Graphics</p> <p>在 Android 5.0(API 级别 21)及更高版本中,可定义矢量图片,而且图片可在不损失清晰度的情况下缩放。 只需一个资产文件即可创建一个矢量图像,而位图图像则需要为每个屏幕密度提供一个资产文件。 如果要创建一个矢量图像,在 XML 元素中定义形状的详情。</p> <p>下列示例以定义一个矢量图像:</p> <p>在drawable文件夹下–>new–>vector Asset</p> <p><img src="https://simg.open-open.com/show/a5b4934be0b4743b27d2d8106fb1aeda.png"></p> <p>可以选择Material Icon,使用studio内置的icon资源。这里选择了Local SVG file,使用自己定义的svg文件。</p> <p><img src="https://simg.open-open.com/show/6966a038773aef2f42854b33fb89ecea.png"></p> <p>确定保存文件的位置。svg文件会导出为xml文件:</p> <p><img src="https://simg.open-open.com/show/ae283ec0e4a3ef164a82ee3bb40f0e5e.png"></p> <p>生成的moon.xml内容如下,path节点下的fillColor属性,可以自定义颜色值。</p> <pre> <vectorxmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:viewportHeight="22.0" android:viewportWidth="22.0"> <path android:fillColor="#FF000000" android:pathData="M16,10l0.8,-3.2L20,6l-3.2,-0.8L16,2l-0.8,3.2L12,6l3.2,0.8L16,10zM6,8c0,-2.17 0.867,-4.134 2.269,-5.575C4.634,3.581 2,6.982 2,11c0,4.971 4.029,9 9,9c4.018,0 7.419,-2.634 8.575,-6.269C18.134,15.133 16.17,16 14,16C9.582,16 6,12.418 6,8z"/> </vector> </pre> <p>layout中使用和普通图片使用相同</p> <pre> <ImageView android:layout_width="40dp" android:layout_height="40dp" android:src="@drawable/moon"/> </pre> <p>界面显示效果:</p> <p><img src="https://simg.open-open.com/show/3fbb7e3df641d3cf80cf32e3a8959ad9.png"></p> <p>控件的宽高可以任意以dp的方式设置,而清晰度并未受影响。</p> <p>SVG除了可以用在矢量图片上,也可以在android上用来显示精美的动画效果。</p> <p>有时间再对svg的生成,以及使用做更详细的介绍。</p> <p> </p> <p>来自:https://blog.maxleap.cn/archives/1226</p> <p> </p>