当前位置: 首页 > 科技观察

Android分辨率适配小测

时间:2023-03-16 02:03:23 科技观察

概述在你开发Android的时候,肯定会觉得屏幕适配是一件特别痛苦的事情,适配各种屏幕尺寸是一件极其痛苦的事情。如果换个角度来看这个问题,不知道大家有没有web前端开发的知识,或者大家对网页都不陌生。其实适配的问题在网页设计中理论上也存在。你为什么这么说?什么?电脑显示的分辨率,包括手机的分辨率,我敢说分辨率的种类远远超过安卓设备的分辨率,所以出现了一个很奇怪的现象:为什么网页设计者从来不说尼玛适合匹配有问题?那么,是什么原因让网页的设计在不同的分辨率下依然能够给用户带来优质的体验呢?带着这个疑惑,我问了儿媳妇(前端人员),儿媳妇瞪大了眼睛问我:什么是适配?fc,尼玛,看来确实没有这个问题。后来仔细一问,她告诉我,哦,这个尺寸,我一直都设置成20%~~最后其实有一个原因,网页提供了一个百分比计算尺寸。同理,你拿到UI给的设计图后,有没有抱怨尼玛,你的logo全是px,而我项目里用的是dp。这是什么?我跟UI人员解释了一下,UI小姐姐没听懂。那么这个例子也可以解决Android工程师和UI妹子的矛盾~UI给出一个固定大小的设计稿,然后你写布局的时候就不用考虑了,直接复制上面标注的像素值即可不假思索,就可以和你完美契合,丰满丰满的理想~~。但是Android对不同屏幕的适配方案是dp,那么dp和百分比的差距在哪里呢?dpvspercentagedp先来看看dp的定义:Density-independentpixel(dp)独立像素密度。标准是160dip。即1dp对应1个像素。计算公式为:px=dp*(dpi/160),屏幕密度越大,1dp对应的像素越多。上面公式中有个dpi,dpi表示DPI为DotsPerInch(每英寸打印的点数),即当设备的dpi为160时,1px=1dp;好吧,记住上面的概念没关系,只要记住dp和像素没有关系即可。在实际使用中,1dp约等于1/160inch。那么dp在适配上解决什么问题呢?可以看出,1dp=1/160inch;那么它至少可以解决一个问题,就是你在布局文件中写一个宽高为160dp160dp的View,而这个View在任何分辨率的高速屏下,显示的大小都是差不多的(可能不准确),大约1英寸1英寸。但是,这并不能解决所有的适配问题:渲染效果还是会有所不同,只是相似而已。当设备的物理尺寸不同时,dp就无能为力了。一个为4.3寸屏幕准备的UI,运行在5.0寸的屏幕上,很可能右侧和底部会有大量的空白。但是,5.0英寸的UI可能无法在4.3英寸的设备上显示。以上两点来自参考链接1中的一句话,总结一下,dp可以让同一个值在不同分辨率下显示大致相同的大小。但是当装备的尺寸相差很大的时候,就没有办法了。适配的问题还是需要我们自己解决,所以我们可能会这样:120dip220dip80dip以上代码片段来源于网络,即也就是说,我们为了高质量的用户体验,还是需要针对不同的dpi设置编写多套数值文件。可见dp并没有解决适配问题。请参阅下面的百分比。百分比的概念就不用多说了,web中支持的控件的宽度可以参考父控件的宽度来设置百分比,最外层控件的宽度可以参考屏幕尺寸来设置百分比。事实上,在Android设备中,只要支持的控件需要能够引用屏幕以百分比的形式计算宽高就足够了。比如我现在有如下需求:对于图片显示的Banner,为了达到想要的效果,希望在任何手机上显示的高度都是屏幕高度的1/4。我的主页分为两栏。我希望每一列的屏幕高度是11/24,中间间隔是1/12。滑动菜单的宽度为屏幕宽度的80%。当然,这只是从大的层面上说的。事实上,在小规模布局中,百分比可能更有用。好吧,现在不支持百分比。要实现上面的需求,可能需要1.动态计算的代码(很多人直接pass,太麻烦);2.使用weight(weight必须依赖Linearlayout,不能应用于任何场景)再举个例子:我的一个浮动按钮的高和宽要求是屏幕高度的1/12,而宽我的一个按钮预计是屏幕宽度的1/3。使用dp无法满足上述所有要求。我们希望控件的大小可以这样写:使用比例屏幕宽度和高度来定义视图的宽度和高度。好了,至此我们可以看出dp和percentage的区别,percentage可以更好的解决我们的适配问题。someadaptationtips让我们来看看一些适配技巧。使用match_parent和使用weightcustomview解决以上3个tips。归根结底还是用百分比。match_parent相当于100%引用父控件;权重按比例分配;customview无非是因为里面的尺寸大部分都是按百分比计算的;通过这些提示,我们可以看出,如果能在Android中引入百分比机制,就可以解决绝大部分的适配问题。让我们来看看如何让Android支持百分比的概念。百分比的介绍1.介绍其实我们的解决方案是在项目中为每个需要适配的手机屏幕分辨率创建一个文件夹。如下图所示:那么我们使用一个benchmark,意思是:比如480*320的分辨率就是320的benchmark宽度,任意一个分辨率的宽度都被分成320份。取值为x1-x320,高度为480。将任意分辨率的高度分成480份,取值为y1-y480。比如800*480的宽度480:可以看到x1=480/benchmark=480/320=1.5;其他分辨率类似~~你可能会问,那么多文件,我们是不是要自己手算,然后自己写?别怕,以后再说。那么,你可能会有疑问,这样写有什么好处呢?假设我需要一个按钮在屏幕中央,宽和高都是我们屏幕宽度的1/2,布局文件怎么写呢?<按钮android:layout_gravity="center"android:gravity="center"android:text="@string/hello_world"android:layout_width="@dimen/x160"android:layout_height="@dimen/x160"/>可以看到我们的宽高定义为x160,其实就是宽度的50%;然后效果图:无论模型是什么分辨率,我们的按钮的宽和高总是屏幕宽度的一半。对于设计图,假设现在的UI设计图是按照480*320设计的,上面的宽高标识都是px值,可以直接将px转换成x[1-320],y[1-480],这样写出来的layout基本可以适配全分辨率。你可能会问:设计师的设计图分辨率不固定怎么办?下面说一下~上面说的几个dp你做不到,引入百分比后你可以自己试试~~好吧,还有最重要的问题我们没有提到的就是分辨率有那么多。是不是要自己算出来,然后手写?2、自动生成工具准备就绪。其实这样的文件夹也可以手写,根据你需要的分辨率支持率,然后写一套,以后一直用到。当然,作为程序员,我们怎么能做这么底层的工作,必须要用程序来实现:那么实现需要以下几个步骤:1)。主流分辨率需要支持的分辨率分析我已经集成到我们的程序中了,当然对于特殊的,可以通过参数指定。关于屏幕分辨率信息,可以通过这个网站查询:http://screensiz.es/phone|00daae956ab82373e1f8431e7cd28c3516|2)。编写自动生成文件程序代码如下:;privateintbaseH;privateStringdirStr="./res";privatefinalstaticStringWTemplate="{1}px\n";privatefinalstaticStringHTemplate="{1}px\n";/***{0}-HEIGHT*/privatefinalstaticStringVALUE_TEMPLATE="values-{0}x{1}";,1812;1080,1920;1440,2560;";privateStringsupportStr=SUPPORT_DIMESION;publicGenerateValueFiles(intbaseX,intbaseY,StringsupportStr){this.baseW=baseX;this.baseH=baseY;if(!this.supportStr.contains(baseX+","+baseY)){this.supportStr+=baseX+","+baseY+";";}this.supportStr+=validateInput(supportStr);System.out.println(supportStr);Filedir=newFile(dirStr);if(!dir.exists()){dir.mkdir();}System.out.println(dir.getAbsoluteFile());}/***@paramsupportStr*w,h_...w,h;*@return*/privateStringvalidateInput(StringsupportStr){StringBuffersb=newStringBuffer();String[]vals=supportStr.split("_");intw=-1;inth=-1;String[]wh;for(Stringval:vals){try{if(val==null||val.trim().length()==0)continue;wh=val.split(",");w=Integer.parseInt(wh[0]);h=Integer.parseInt(wh[1]);}catch(Exceptione){System.out.println("skipinvalidateparams:w,h="+val);继续;}sb.append(w+","+h+";");}returnsb.toString();}publicvoidgenerate(){String[]vals=supportStr.split(";");for(Stringval:vals){String[]wh=val.split(",");generateXmlFile(Integer.parseInt(wh[0]),Integer.parseInt(wh[1]));}}privatevoidgenerateXmlFile(intw,inth){StringBuffersbForWidth=newStringBuffer();sbForWidth.append("\n");sbForWidth.append("<资源>");floatcellw=w*1.0f/baseW;System.out.println("宽度:"+w+","+baseW+","+cellw);for(inti=1;i");StringBuffersbForHeight=newStringBuffer();sbForHeight.append("\n");sbForHeight.append("");floatcellh=h*1.0f/baseH;System.out.println("height:"+h+","+baseH+","+cellh);for(inti=1;i");FilefileDir=newFile(dirStr+File.separator+VALUE_TEMPLATE.replace("{0}",h+"")//.replace("{1}",w+""));fileDir.mkdir();FilelayxFile=newFile(fileDir.getAbsolutePath(),"lay_x.xml");FilelayyFile=newFile(fileDir.getAbsolutePath(),"lay_y.xml");try{PrintWriterpw=newPrintWriter(newFileOutputStream(layxFile));pw.print(sbForWidth.toString());pw.close();pw=newPrintWriter(newFileOutputStream(layyFile));pw.print(sbForHeight.toString());pw.close();}catch(FileNotFoundExceptione){e.printStackTrace();}}publicstaticfloatchange(floata){inttemp=(int)(a*100);returntemp/100f;}publicstaticvoidmain(String[]args){intbaseW=320;intbaseH=400;Stringaddition="";try{if(args.length>=3){baseW=Integer.parseInt(args[0]);baseH=Integer.parseInt(args[1]);addition=args[2];}elseif(args.length>=2){baseW=Integer.parseInt(args[0]);baseH=Integer.parseInt(args[1]);}elseif(args.length>=1){加法=args[0];}}catch(NumberFormatExceptione){System.err.println("rightinputparams:java-jarxxx.jarwidthheightw,h_w,h_..._w,h;");e.printStackTrace();System.exit(-1);}newGenerateValueFiles(baseW,baseH,addition).generate();}}同时我提供jar包,默认双击生成,使用说明:见文末下载地址,内置常用分辨率默认基准为480*320。当然,如果有特殊需要,可以通过命令行指定:例如:benchmark1280800,附加支持尺寸:1152735;4500*3200;根据Java-jarxx.jarwidthheightwidth,height_width,height可以按照上面的格式来做。至此,我们写一个工具,根据某个参考尺寸,生成所有需要适配分辨率的values文件。在编写布局文件时,我们可以参考屏幕的分辨率;UI中给出的设计图可以根据其logo的px单位快速编写布局。基本解决了适配问题。欢迎大家点赞评论,也欢迎大家到作者博客评论交流。