Android 适配多种屏幕

it2022-05-05  155

文字和尺寸的适配


我们这里需要将代码跑在一个1920*1200分辨率320dpi的平板上,发现所有的字体都变大了,看似1920*1200的分辨率比之前的1280*800要大一大圈,但是因为dpi也高,所以导致字体变大。

Configuration config = getResources().getConfiguration(); int smallestScreenWidth = config.smallestScreenWidthDp; 运行上面的获取smallestScreenWidth的代码后,发现值为600。(base size的平板电脑这个值是800)

 

首先在values文件夹中建立一个dimens.xml文件

 

继续在res中建立和values文件夹同级别的两个文件夹values-sw600dp-land和values-sw800dp-land,为了适应更多的屏幕,也加入了values-sw480dp-land (后缀是land是因为例子的项目是平板)

 

随后我们一个个的把原来写的layout文件找出来,找出里面原来写死的“数字”,比如宽度和字体大小之类的,一般来说单位是dp或者sp,将这些数字全部在values/dimens.xml中定义一个变量同时写回layout文件中对应的数字的地方,这里举个例子:

原来的代码是这样的:

现在代码成了这样:

dimens.xml中添加的内容:

 

然后你将values-sw600dp-land的里面的dimens.xml分别乘以0.75来获得:(因为600/800等于0.75)

 

values-sw480dp-land里面的dimens.xml分别乘以0.6来获得(因为480/800等于0.6)

 

values-sw800dp-land保持和values里面的一样,因为它是base size。

这样子以后我们再运行代码到1920*1200分辨率320dpi的平板上,发现这个时候字体还有空间宽高都和原来的base size的一模一样了,就像是原封不动的跑在base size平板上的感觉!

 

那么这个时候问题来了:

那么多的layout文件夹本身每个创建一个dimen变量就够累了,然后还要分别拷贝一份同时手动计算乘以0.6或者0.75来获得新的值,拿计算器一个个的计算,多大的工作量啊,况且以后要是要来个sw1028、sw320呢?再次算一次?

 

这里提供一个方法:

在代码里面新加一个带main的java类,事实上它是自动的帮你在原来的values/dimens.xml的基础上自动的帮你把每个dimen乘以你所需要的乘积然后将结果写回对应的dimens.xml里面,这大大的减轻了工作量,以后每次修改dimens.xml只要这样子即可:

在values/dimens.xml里面添加或修改变量跑一边上述java类自动的生成别的dimens.xml

这里给出这个工具java类的代码:

public class DimenTool { public static void gen() { File file = new File("./app/src/main/res/values/dimens.xml"); BufferedReader reader = null; StringBuilder sw480 = new StringBuilder(); StringBuilder sw600 = new StringBuilder(); StringBuilder sw720 = new StringBuilder(); StringBuilder sw800 = new StringBuilder(); StringBuilder w820 = new StringBuilder(); try { System.out.println("生成不同分辨率:"); reader = new BufferedReader(new FileReader(file)); String tempString; int line = 1; // 一次读入一行,直到读入null为文件结束 while ((tempString = reader.readLine()) != null) { if (tempString.contains("</dimen>")) { //tempString = tempString.replaceAll(" ", ""); String start = tempString.substring(0, tempString.indexOf(">") + 1); String end = tempString.substring(tempString.lastIndexOf("<") - 2); int num = Integer.valueOf(tempString.substring(tempString.indexOf(">") + 1, tempString.indexOf("</dimen>") - 2)); sw480.append(start).append((int) Math.round(num * 0.6)).append(end).append("\n"); sw600.append(start).append((int) Math.round(num * 0.75)).append(end).append("\n"); sw720.append(start).append((int) Math.round(num * 0.9)).append(end).append("\n"); sw800.append(tempString).append("\n"); w820.append(tempString).append("\n"); } else { sw480.append(tempString).append("\n"); sw600.append(tempString).append("\n"); sw720.append(tempString).append("\n"); sw800.append(tempString).append("\n"); w820.append(tempString).append("\n"); } line++; } reader.close(); System.out.println("<!-- sw480 -->"); System.out.println(sw480); System.out.println("<!-- sw600 -->"); System.out.println(sw600); System.out.println("<!-- sw720 -->"); System.out.println(sw720); System.out.println("<!-- sw800 -->"); System.out.println(sw800); String sw480file = "./app/src/main/res/values-sw480dp-land/dimens.xml"; String sw600file = "./app/src/main/res/values-sw600dp-land/dimens.xml"; String sw720file = "./app/src/main/res/values-sw720dp-land/dimens.xml"; String sw800file = "./app/src/main/res/values-sw800dp-land/dimens.xml"; String w820file = "./app/src/main/res/values-w820dp/dimens.xml"; writeFile(sw480file, sw480.toString()); writeFile(sw600file, sw600.toString()); writeFile(sw720file, sw720.toString()); writeFile(sw800file, sw800.toString()); writeFile(w820file, w820.toString()); } catch (IOException e) { e.printStackTrace(); } finally { if (reader != null) { try { reader.close(); } catch (IOException e1) { e1.printStackTrace(); } } } } public static void writeFile(String file, String text) { PrintWriter out = null; try { out = new PrintWriter(new BufferedWriter(new FileWriter(file))); out.println(text); } catch (IOException e) { e.printStackTrace(); } out.close(); } public static void main(String[] args) { gen(); } }

 

图片的适配


文字和空间宽度适配后,大家可能发现部分的ImageView或者ImageButton部分还有些变大或者变小,有的变模糊了,这里需要美工提供多套图片,大家请看这张图:

这里说明了开发时应该图片以160dpi为基准,同时提供不同dpi的基于baseline的图片的放大或者缩小版本。那么每套图片放什么地方呢?

以上是Google官方给出的分类标准(虽然 Android 也支持低像素密度 (LDPI) 的屏幕,但无需为此费神,系统会自动将 HDPI 尺寸的图标缩小到 1/2 进行匹配。)

 

所以对于我们的例子中1920*1200分辨率320dpi的平板,我们应该让美工制作放大2x的版本的图片,同时将图片放到drawable-xhdpi文件夹中,原来的图片放到drawable-mdpi文件夹中。这里需要注意一下,对于drawable你可能会写很多的比如shape或者selector的xml形式的drawable,他们本身不是图片而是一个xml文件,但是他们都会去引用真实的drawable图片,对于这种xml最好是要放到无dpi影响的drawable文件夹中(无后缀)

 

这样子以来,我们再把代码跑到1920*1200分辨率320dpi的平板上,发现图片部分也OK了,适配完毕。

 

这里还需要提醒的一点,并不是每个地方的图片都需要提供多套图片这种方案来解决,因为这种方案会带来使apk的size变大的副作用。所以大家可以根据实际需求,若可以通过上一节的方式来修改imageView的尺寸大小来解决(而非用wrap_content来指定layout_width和layout_height)的话,就不需要用多套图片的方式。

 

 

应用启动图标的适配


对于高分辨率低dpi的设备,我们经常会发现在launcher中我们的应用的启动icon被拉伸的模糊了,严重影响了门面的形象。

这里我们也通过提供多套icon的方式来解决,下面列表给出了不同屏幕密度中推荐的icon的size大小

 

在Android4.2以上的版本中,提供了对mipmaps的支持,说简单点就是他能对bitmap进行缩放的时候减少一些性能的耗损。如果你用Andorid Studio开发Android程序会发现Android Studio自动帮你创建了几个mipmaps文件夹,你可将应用的启动图标放到不同的mipmaps文件夹中而不是上述的drawable文件夹中,比如:

 

这里你至少要提供一个xxxhdpi类型的启动图标,因为Android会帮你自动缩小图标到对应的别的分辨率上(放大是会变模糊的),这样子可以节省些apk size。

 

转自:https://www.cnblogs.com/soaringEveryday/p/4835839.html


最新回复(0)