Android分辨率适配小试牛刀

概述

大家在Android开发时,肯定会觉得屏幕适配是个尤其痛苦的事,各种屏幕尺寸适配起来蛋疼无比。如果我们换个角度我们看下这个问题,不知道大家有没有了解过web前端开发,或者说大家对于网页都不陌生吧,其实适配的问题在web页面的设计中理论上也存在,为什么这么说呢?电脑的显示器的分辨率、包括手机分辨率,我敢说分辨率的种类远超过Android设备的分辨率,那么有一个很奇怪的现象:

为什么Web页面设计人员从来没有说过,尼玛适配好麻烦?

那么,到底是什么原因,让网页的设计可以在千差万别的分辨率的分辨率中依旧能给用户一个优质的体验呢?带着这个疑惑,我问了下媳妇(前端人员),媳妇睁大眼睛问我:什么叫适配?fc,尼玛,看来的确没有这类问题。后来再我仔细的追问后,她告诉我,噢,这个尺寸呀,我都是设置为20%的~~追根到底,其实就是一个原因,网页提供了百分比计算大小。

同样的,大家拿到UI给的设计图以后,是不是抱怨过尼玛你标识的都是px,我项目里面用dp,这什么玩意,和UI人员解释,UI妹妹也不理解。那么本例同样可以解决Android工程师和UI妹妹间的矛盾~UI给出一个固定尺寸的设计稿,然后你在编写布局的时候不用思考,无脑照抄上面标识的像素值,就能达到完美适配,理想丰不丰满~~。

然而,Android对于不同的屏幕给出的适配方案是dp,那么dp与百分比的差距到底在哪里?

dp vs 百分比

dp

我们首先看下dp的定义:

Density-independent pixel (dp)独立像素密度。标准是160dip.即1dp对应1个pixel,计算公式如:px = dp * (dpi / 160),屏幕密度越大,1dp对应 的像素点越多。

上面的公式中有个dpi,dpi为DPI是Dots Per Inch(每英寸所打印的点数),也就是当设备的dpi为160的时候1px=1dp;

好了,上述这些概念记不记得住没关系,只要记住一点dp是与像素无关的,在实际使用中1dp大约等于1/160inch。

那么dp究竟解决了适配上的什么问题?可以看出1dp = 1/160inch;那么它至少能解决一个问题,就是你在布局文件写某个View的宽和高为160dp160dp,这个View在任何分辨率的屏幕中,显示的尺寸大小是大约是一致的(可能不精确),大概是 1 inch 1 inch。

但是,这样并不能够解决所有的适配问题:

呈现效果仍旧会有差异,仅仅是相近而已

当设备的物理尺寸存在差异的时候,dp就显得无能为力了。为4.3寸屏幕准备的UI,运行在5.0寸的屏幕上,很可能在右侧和下侧存在大量的空白。而5.0寸的UI运行到4.3寸的设备上,很可能显示不下。

以上两点,来自参考链接1

一句话,总结下,dp能够让同一数值在不同的分辨率展示出大致相同的尺寸大小。但是当设备的尺寸差异较大的时候,就无能为力了。适配的问题还需要我们自己去做,于是我们可能会这么做:


  1. <?xml version="1.0" encoding="utf-8"?>   
  2. <resources>   
  3.     <!-- values-hdpi 480X800 -->   
  4.     <dimen name="imagewidth">120dip</dimen>       
  5. </resources>   
  6.  
  7. <resources>   
  8.     <!-- values-hdpi-1280x800 -->   
  9.     <dimen name="imagewidth">220dip</dimen>       
  10. </resources>   
  11.  
  12. <?xml version="1.0" encoding="utf-8"?>   
  13. <resources>   
  14.     <!-- values-hdpi  480X320 -->   
  15.     <dimen name="imagewidth">80dip</dimen>       
  16. </resources>  

上述代码片段来自网络,也就是说,我们为了优质的用户体验,依然需要去针对不同的dpi设置,编写多套数值文件。

可以看出,dp并没有能解决适配问题。下面看百分比。

百分比

这个概念不用说了,web中支持控件的宽度可以去参考父控件的宽度去设置百分比,最外层控件的宽度参考屏幕尺寸设置百分比,那么其实中Android设备中,只需要支持控件能够参考屏幕的百分比去计算宽高就足够了。

比如,我现在以下几个需求:

对于图片展示的Banner,为了起到该有的效果,我希望在任何手机上显示的高度为屏幕高度的1/4

我的首页分上下两栏,我希望每个栏目的屏幕高度为11/24,中间间隔为1/12

slidingmenu的宽度为屏幕宽度的80%

当然了这仅仅是从一个大的层面上来说,其实小范围布局,可能百分比将会更加有用。

那么现在不支持百分比,实现上述的需求,可能需要1、代码去动态计算(很多人直接pass了,太麻烦);2、利用weight(weight必须依赖Linearlayout,而且并不能适用于任何场景)

再比如:我的某个浮动按钮的高度和宽度希望是屏幕高度的1/12,我的某个Button的宽度希望是屏幕宽度的1/3。上述的所有的需求,利用dp是无法完成的,我们希望控件的尺寸可以按照下列方式编写:


  1. <Button 
  2.         android:text="@string/hello_world" 
  3.         android:layout_width="20%w" 
  4.         android:layout_height="10%h"/> 

利用屏幕的宽和高的比例去定义View的宽和高。

好了,到此我们可以看到dp与百分比的区别,而百分比能够更好的解决我们的适配问题。

some 适配tips

我们再来看看一些适配的tips

多用match_parent

多用weight

自定义view解决

其实上述3点tip,归根结底还是利用百分比,match_parent相当于100%参考父控件;weight即按比例分配;自定义view无非是因为里面多数尺寸是按照百分比计算的;

通过这些tips,我们更加的看出如果能在Android中引入百分比的机制,将能解决大多数的适配问题,下面我们就来看看如何能够让Android支持百分比的概念。

百分比的引入

1、引入

其实我们的解决方案,就是在项目中针对你所需要适配的手机屏幕的分辨率各自简历一个文件夹。

如下图:

然后我们根据一个基准,为基准的意思就是:

比如480*320的分辨率为基准

宽度为320,将任何分辨率的宽度分为320份,取值为x1-x320

高度为480,将任何分辨率的高度分为480份,取值为y1-y480

例如对于800*480的宽度480:

可以看到x1 = 480 / 基准 = 480 / 320 = 1.5 ;其他分辨率类似~~

你可能会问,这么多文件,难道我们要手算,然后自己编写?不要怕,下文会说。

那么,你可能有个疑问,这么写有什么好处呢?

假设我现在需要在屏幕中心有个按钮,宽度和高度为我们屏幕宽度的1/2,我可以怎么编写布局文件呢?


  1. <FrameLayout > 
  2.  
  3. <Button 
  4.  
  5. android:layout_gravity="center" 
  6.  
  7. android:gravity="center" 
  8.  
  9. android:text="@string/hello_world" 
  10.  
  11. android:layout_width="@dimen/x160" 
  12.  
  13. android:layout_height="@dimen/x160"/> 
  14.  
  15. </FrameLayout> 

可以看到我们的宽度和高度定义为x160,其实就是宽度的50%;

那么效果图:

可以看到不论在什么分辨率的机型,我们的按钮的宽和高始终是屏幕宽度的一半。

对于设计图

假设现在的UI的设计图是按照480*320设计的,且上面的宽和高的标识都是px的值,你可以直接将px转化为x[1-320],y[1-480],这样写出的布局基本就可以全分辨率适配了。

你可能会问:设计师设计图的分辨率不固定怎么办?下文会说~

对于上文提出的几个dp做不到的

你可以通过在引入百分比后,自己试试~~

好了,有个最主要的问题,我们没有说,就是分辨率这么多,尼玛难道我们要自己计算,然后手写?

2、自动生成工具

好了,其实这样的文件夹手写也可以,按照你们需要支持的分辨率,然后编写一套,以后一直使用。

当然了,作为程序员的我们,怎么能做这么low的工作,肯定要程序来实现:

那么实现需要以下步骤:

1).分析需要的支持的分辨率

对于主流的分辨率我已经集成到了我们的程序中,当然对于特殊的,你可以通过参数指定。关于屏幕分辨率信息,可以通过该网站查询:http://screensiz.es/phone| 00daae956ab82373e1f8431e7cd28c3516 |

2).编写自动生成文件的程序

代码如下


  1. import java.io.File; 
  2. import java.io.FileNotFoundException; 
  3. import java.io.FileOutputStream; 
  4. import java.io.PrintWriter; 
  5.  
  6. /** 
  7.  * Created by zhy on 15/5/3. 
  8.  */ 
  9. public class GenerateValueFiles { 
  10.  
  11.     private int baseW; 
  12.     private int baseH; 
  13.  
  14.     private String dirStr = "./res"; 
  15.  
  16.     private final static String WTemplate = "<dimen name=\"x{0}\">{1}px</dimen>\n"; 
  17.     private final static String HTemplate = "<dimen name=\"y{0}\">{1}px</dimen>\n"; 
  18.  
  19.     /** 
  20.      * {0}-HEIGHT 
  21.      */ 
  22.     private final static String VALUE_TEMPLATE = "values-{0}x{1}"; 
  23.  
  24.     private static final String SUPPORT_DIMESION = "320,480;480,800;480,854;540,960;600,1024;720,1184;720,1196;720,1280;768,1024;800,1280;1080,1812;1080,1920;1440,2560;"; 
  25.  
  26.     private String supportStr = SUPPORT_DIMESION; 
  27.  
  28.     public GenerateValueFiles(int baseX, int baseY, String supportStr) { 
  29.         this.baseW = baseX; 
  30.         this.baseH = baseY; 
  31.  
  32.         if (!this.supportStr.contains(baseX + "," + baseY)) { 
  33.             this.supportStr += baseX + "," + baseY + ";"; 
  34.         } 
  35.  
  36.         this.supportStr += validateInput(supportStr); 
  37.  
  38.         System.out.println(supportStr); 
  39.  
  40.         File dir = new File(dirStr); 
  41.         if (!dir.exists()) { 
  42.             dir.mkdir(); 
  43.  
  44.         } 
  45.         System.out.println(dir.getAbsoluteFile()); 
  46.  
  47.     } 
  48.  
  49.     /** 
  50.      * @param supportStr 
  51.      *            w,h_...w,h; 
  52.      * @return 
  53.      */ 
  54.     private String validateInput(String supportStr) { 
  55.         StringBuffer sb = new StringBuffer(); 
  56.         String[] vals = supportStr.split("_"); 
  57.         int w = -1; 
  58.         int h = -1; 
  59.         String[] wh; 
  60.         for (String val : vals) { 
  61.             try { 
  62.                 if (val == null || val.trim().length() == 0) 
  63.                     continue; 
  64.  
  65.                 wh = val.split(","); 
  66.                 w = Integer.parseInt(wh[0]); 
  67.                 h = Integer.parseInt(wh[1]); 
  68.             } catch (Exception e) { 
  69.                 System.out.println("skip invalidate params : w,h = " + val); 
  70.                 continue; 
  71.             } 
  72.             sb.append(w + "," + h + ";"); 
  73.         } 
  74.  
  75.         return sb.toString(); 
  76.     } 
  77.  
  78.     public void generate() { 
  79.         String[] vals = supportStr.split(";"); 
  80.         for (String val : vals) { 
  81.             String[] wh = val.split(","); 
  82.             generateXmlFile(Integer.parseInt(wh[0]), Integer.parseInt(wh[1])); 
  83.         } 
  84.  
  85.     } 
  86.  
  87.     private void generateXmlFile(int w, int h) { 
  88.  
  89.         StringBuffer sbForWidth = new StringBuffer(); 
  90.         sbForWidth.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"); 
  91.         sbForWidth.append("<resources>"); 
  92.         float cellw = w * 1.0f / baseW; 
  93.  
  94.         System.out.println("width : " + w + "," + baseW + "," + cellw); 
  95.         for (int i = 1; i < baseW; i++) { 
  96.             sbForWidth.append(WTemplate.replace("{0}", i + "").replace("{1}", 
  97.                     change(cellw * i) + "")); 
  98.         } 
  99.         sbForWidth.append(WTemplate.replace("{0}", baseW + "").replace("{1}", 
  100.                 w + "")); 
  101.         sbForWidth.append("</resources>"); 
  102.  
  103.         StringBuffer sbForHeight = new StringBuffer(); 
  104.         sbForHeight.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"); 
  105.         sbForHeight.append("<resources>"); 
  106.         float cellh = h *1.0f/ baseH; 
  107.         System.out.println("height : "+ h + "," + baseH + "," + cellh); 
  108.         for (int i = 1; i < baseH; i++) { 
  109.             sbForHeight.append(HTemplate.replace("{0}", i + "").replace("{1}", 
  110.                     change(cellh * i) + "")); 
  111.         } 
  112.         sbForHeight.append(HTemplate.replace("{0}", baseH + "").replace("{1}", 
  113.                 h + "")); 
  114.         sbForHeight.append("</resources>"); 
  115.  
  116.         File fileDir = new File(dirStr + File.separator 
  117.                 + VALUE_TEMPLATE.replace("{0}", h + "")// 
  118.                         .replace("{1}", w + "")); 
  119.         fileDir.mkdir(); 
  120.  
  121.         File layxFile = new File(fileDir.getAbsolutePath(), "lay_x.xml"); 
  122.         File layyFile = new File(fileDir.getAbsolutePath(), "lay_y.xml"); 
  123.         try { 
  124.             PrintWriter pw = new PrintWriter(new FileOutputStream(layxFile)); 
  125.             pw.print(sbForWidth.toString()); 
  126.             pw.close(); 
  127.             pw = new PrintWriter(new FileOutputStream(layyFile)); 
  128.             pw.print(sbForHeight.toString()); 
  129.             pw.close(); 
  130.         } catch (FileNotFoundException e) { 
  131.             e.printStackTrace(); 
  132.         } 
  133.     } 
  134.  
  135.     public static float change(float a) { 
  136.         int temp = (int) (a * 100); 
  137.         return temp / 100f; 
  138.     } 
  139.  
  140.     public static void main(String[] args) { 
  141.         int baseW = 320; 
  142.         int baseH = 400; 
  143.         String addition = ""; 
  144.         try { 
  145.             if (args.length >= 3) { 
  146.                 baseW = Integer.parseInt(args[0]); 
  147.                 baseH = Integer.parseInt(args[1]); 
  148.                 addition = args[2]; 
  149.             } else if (args.length >= 2) { 
  150.                 baseW = Integer.parseInt(args[0]); 
  151.                 baseH = Integer.parseInt(args[1]); 
  152.             } else if (args.length >= 1) { 
  153.                 addition = args[0]; 
  154.             } 
  155.         } catch (NumberFormatException e) { 
  156.  
  157.             System.err 
  158.                     .println("right input params : java -jar xxx.jar width height w,h_w,h_..._w,h;"); 
  159.             e.printStackTrace(); 
  160.             System.exit(-1); 
  161.         } 
  162.  
  163.         new GenerateValueFiles(baseW, baseH, addition).generate(); 
  164.     } 
  165.  

同时我提供了jar包,默认情况下,双击即可生成,使用说明:

下载地址见文末,内置了常用的分辨率,默认基准为480*320,当然对于特殊需求,通过命令行指定即可:

例如:基准 1280 800 ,额外支持尺寸:1152 735;4500 * 3200;

按照

Java -jar xx.jar width height width,height_width,height

上述格式即可。

结束语

到此,我们通过编写一个工具,根据某基准尺寸,生成所有需要适配分辨率的values文件,做到了编写布局文件时,可以参考屏幕的分辨率;在UI给出的设计图,可以快速的按照其标识的px单位进行编写布局。基本解决了适配的问题。欢迎大家点赞和评论,也欢迎大家去作者博客评论交流。

作者:tiaozhan2015

来源:51CTO

时间: 2024-11-05 17:34:44

Android分辨率适配小试牛刀的相关文章

android 分辨率适配的方法_Android

以前在公司做项目的时候,遇到了分辨率的适配问题,说起来当时挺纠结的,因为没有外网,所以这个问题,都是黑暗中摸索的,尝试了许多方法,最后和徒弟们一起搞出了这个方法,具体行不行,先和大家分享下,这个方法不能说万能的,但是最起码它解决了分辨率跟密集度的关系,但是也引来一个问题,就是布局会因为图片资源小而失真,所以这也需要美工的同志多多配合的,废话不说,贴代码: 第一步,先创建一个view信息的javabean类: 复制代码 代码如下: package com.zte.layout.adapter; i

android网络图片适配不同分辨率屏幕

问题描述 android网络图片适配不同分辨率屏幕 需要在android手机上面显示网络图片,但是手机的分辨率是有不同的,有mdpi,ldpi,hdpi,xhdpi等多种分辨率,怎么让图片在每个手机上面显示都是和屏幕一样宽.是让手机传不同的分辨率给服务器,服务器返回不同的图片,还是怎么做?求解答! 解决方案 一般是传参数告诉服务器是什么类型的,服务器返回不同的图片还有就是比如新浪Open API的那些图像分为middle,large,small等去获取

一种粗暴快速的Android全屏幕适配方案

本文讲的是一种粗暴快速的Android全屏幕适配方案,由于Android碎片化严重,屏幕适配一直是开发中较为头疼的问题.面对市面上五花八门的屏幕大小与分辨率,Android基于dp与res目录名称来适配的方案已无法满足一次编写全屏幕适配的需求,为了达到最优的视觉效果,开发过程中总是需要花费较多资源进行适配.也有开发者给出了一些自己的解决方案.首先来分析一下一些常见的解决方案的现状: 1. 官方适配方案 – dp.dp是Android开发中特有的一个单位.与px不同,dp是基于屏幕像素密度的一种单

图片-Android屏幕适配问题,菜鸟求助

问题描述 Android屏幕适配问题,菜鸟求助 如题, 本人菜鸟不知道怎么屏幕适配呀, 我用的是demin建立了两个文件, 一个是(1280x720的),另外一个是1920x1080的. 在里面写的尺寸.因为我们美工给我的图片都是px的. 换算如下 解决方案 做android开发,开源嘛,满市场都是凌乱的机型,总少不了适配这样或那样的型号.在这里分享一下自己在开发中用到的方法. 首先要介绍一下drawable-mdpi.drawable-hdpi-1280x800.drawable-hdpi.这

Android 屏幕适配方案

转载请标明出处:  http://blog.csdn.net/lmj623565791/article/details/45460089:  1.概述 大家在Android开发时,肯定会觉得屏幕适配是个尤其痛苦的事,各种屏幕尺寸适配起来蛋疼无比.如果我们换个角度我们看下这个问题,不知道大家有没有了解过web前端开发,或者说大家对于网页都不陌生吧,其实适配的问题在web页面的设计中理论上也存在,为什么这么说呢?电脑的显示器的分辨率.包括手机分辨率,我敢说分辨率的种类远超过Android设备的分辨率

android-有关于Android屏幕适配

问题描述 有关于Android屏幕适配 请问一下各位牛人,分辨率为1280x800的手机匹配不到values-1280x800的资源呢? 解决方案 10.1" WXGA(Tablet) 1280×800 解决方案二: 谢谢回答!但是我没看明白!

实用Android 屏幕适配方案分享

转载地址:http://blog.csdn.net/gao_chun/article/details/45645051 真正可用,并且简单易行,可以在多个屏幕大小和屏幕密度上有良好表现的Android 屏幕适配方案,已用在一款成熟互联网应用中,效果还不错. 说起android开发,UI界面的多机型适配,一向是个很重要的问题. 网上这方面的文章很多,面试的时候也经常会问到,大部分的内容都很类似,无外乎用dp,sp 不要用px之类老生常谈的问题. 但是会说的居多,实际可以执行的可行方案,很少有人会.

Android屏幕适配全攻略(最权威的官方适配指导)

转载请注明出处:http://blog.csdn.net/zhaokaiqiang1992 Android的屏幕适配一直以来都在折磨着我们这些开发者,本篇文章以Google的官方文档为基础,全面而深入的讲解了Android屏幕适配的原因.重要概念.解决方案及最佳实践,我相信如果你能认真的学习本文,对于Android的屏幕适配,你将有所收获! Android屏幕适配出现的原因 重要概念 屏幕尺寸 屏幕分辨率 屏幕像素密度 dpdipdpisppx mdpihdpixdpixxdpi 解决方案 支持

Android屏幕适配

http://www.apkbus.com/android-41832-1-1.html 图像显示所需的概念: 像素:一幅图片的显示就是由许多显示着不同颜色的小方格组成的,这样的小方格就被称为像素,是构成图片的最小单位.但是这个像素的具体大小是多少呢?这需要取决于显示这张图片的具体的物理设备显示一个图片像素点的荧光点的大小.图片文件只是记录着它自身有多少个像素点,每个像素点显示什么颜色,至于它自身物理尺寸有多大,它自身也无法得知,例如一张480*800像素的图片在电脑显示器上显示明显要比在手机屏