如何为不同密度的屏幕提供不同的资源和使用密度独立的单位。

1 使用密度无关像素

坚决杜绝在布局文件中使用绝对像素来定位和设置大小。因为不同的屏幕有不同的像素密度,所以使用像素来设置控件大小是有问题的,在不同的设备上同样的像素可能代表不同的物理屏幕尺寸,所以当使用尺寸的时候,总是使用dp或者sp,dp是相对于160dpi屏幕的密度独立的像素单位,而sp是同样的,只不过会相对于用户设定的文字大小去缩放,因此在定义文字大小的时候要用sp而不要在定义布局的时候使用sp。

例如当你设置两个按钮的间隔的时候使用dp 而不是 px:

<Buttonandroid:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/clickme"
android:layout_marginTop="20dp"/>

当定义文字大小的时候,总是使用 sp:

<TextViewandroid:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="20sp"/>

2 不同的屏幕密度使用不同的图片

由于Android设备的屏幕密度是各种各样的,您应该为不同密度的屏幕提供不同的图片资源,这样在各种像素密度的屏幕上都能获得最好的图形质量和性能。

在原有矢量图的基础上按照如下的缩放比例来分别生成不同屏幕密度的图片资源:

  • xhdpi: 2.0

  • hdpi: 1.5

  • mdpi: 1.0 (baseline)

  • ldpi: 0.75

这意味着对于xhdpi 的设备需要使用200×200的图片;对于hdpi的设备只需要 150×150 的图片;而对于mdpi的设备需要 100×100 的图片; 对于ldpi 的设备只需要75×75 的图片。

把这些图片放到位于res/目录下对于的图片目录中:

MyProject/
res/
drawable-xhdpi/
awesomeimage.png
drawable-hdpi/
awesomeimage.png
drawable-mdpi/
awesomeimage.png
drawable-ldpi/
awesomeimage.png

然后,当您使用@drawable/awesomeimage的时候, 系统会根据当前设备的屏幕密度为您选择最优的图片。

小插曲:
如果我们只提供一个图片来适配不同屏幕密度的设备的话,就要考虑放在哪个文件夹下了。

我们以Nexus5为例,如果我们把图片放在drawable-xxhdpi下,占用的内存最小(凯子哥的例子是11.65M),如果放在drawabledrawable-mdpi下,占用的内存将会非常大(凯子哥的例子是74.95M)。如果放在drawable-hdpi下占用的为35.38M(同一张图片),所以,我们要提供不同尺寸的图片来适配不同的屏幕密度,否则可能会很大程度上浪费内存。

虽然是以了dp这种屏幕密度无关单位,但还是存在下面的问题,看下面的一个列子

Nexu5手机,对应的宽度是360dp

我们现在在一个布局文件中,放置两个按钮,一个按钮在最左边宽度是150dp,另外一个按钮放置布局的最右边宽度是200dp,中间还剩余了10dp,我们来看下布局的显示

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#a79"
tools:context=".MainActivity"> <Button
android:layout_width="150dp"
android:layout_height="fill_parent"
android:layout_alignParentLeft="true"
android:background="#779"
android:text="左边按钮"
/> <Button
android:layout_width="200dp"
android:layout_height="fill_parent"
android:layout_alignParentRight="true"
android:background="#179"
android:text="右边按钮"
/>
</RelativeLayout>

但是该布局在其他手机上的显示效果

即使我们使用了dp和sp,还是会存在上面的同一种布局文件在不同的手机上显示出不一样的效果,因为不同手机的宽度的大小对应的dp是不一样的。

解决上面问题的办法:

1、尽量不要直接写150dp这种固定值,可以使用weight、wrapcontent 相对布局来解决上面的问题,除了这种方法之外,还有没有其他的方式了

思路:把任何设备的手机宽度像素均分为320份,高度像素均分为480份,使用我们写好的程序自动生成资源values-***×***文件夹,里面包含lay_x.xmllay_y.xml,分别对应宽度和高度的像素。

MakeXml类:
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintWriter; /**
* Created by wei.yuan on 2016/5/10.
*/
public class MakeXml {
private final static String rootPath = "F:\\layoutroot\\values-{0}x{1}\\"; private final static float dw = 320f;
private final static float dh = 480f; private final static String WTemplate = "<dimen name=\"x{0}\">{1}px</dimen>\n";
private final static String HTemplate = "<dimen name=\"y{0}\">{1}px</dimen>\n"; public static void main(String[] args) {
makeString(320, 480);
makeString(480, 800);
makeString(480, 854);
makeString(540, 960);
makeString(600, 1024);
makeString(720, 1184);
makeString(720, 1196);
makeString(720, 1280);
makeString(768, 1024);
makeString(800, 1280);
makeString(1080, 1812);
makeString(1080, 1920);
makeString(1440, 2560);
} public static void makeString(int w, int h) { StringBuffer sb = new StringBuffer();
sb.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
sb.append("<resources>");
float cellw = w / dw;
for (int i = 1; i < 320; i++) {
sb.append(WTemplate.replace("{0}", i + "").replace("{1}",
change(cellw * i) + ""));
}
sb.append(WTemplate.replace("{0}", "320").replace("{1}", w + ""));
sb.append("</resources>"); StringBuffer sb2 = new StringBuffer();
sb2.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
sb2.append("<resources>");
float cellh = h / dh;
for (int i = 1; i < 480; i++) {
sb2.append(HTemplate.replace("{0}", i + "").replace("{1}",
change(cellh * i) + ""));
}
sb2.append(HTemplate.replace("{0}", "480").replace("{1}", h + ""));
sb2.append("</resources>"); String path = rootPath.replace("{0}", h + "").replace("{1}", w + "");
File rootFile = new File(path);
if (!rootFile.exists()) {
rootFile.mkdirs();
}
File layxFile = new File(path + "lay_x.xml");
File layyFile = new File(path + "lay_y.xml");
try {
PrintWriter pw = new PrintWriter(new FileOutputStream(layxFile));
pw.print(sb.toString());
pw.close();
pw = new PrintWriter(new FileOutputStream(layyFile));
pw.print(sb2.toString());
pw.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} } public static float change(float a) {
int temp = (int) (a * 100);
return temp / 100f;
} }

执行上面程序,

 private final static String rootPath = "F:\\layoutroot\\values-{0}x{1}\\";知道生成文件的路径

会在f盘盘的layoutroot目录下生成下面这些文件夹和文件

F:\layoutroot\values-480x320\lay_x.xml

<?xml version="1.0" encoding="utf-8"?>
<resources><dimen name="x1">1.0px</dimen>
<dimen name="x2">2.0px</dimen>
<dimen name="x3">3.0px</dimen>
<dimen name="x4">4.0px</dimen>
<dimen name="x5">5.0px</dimen>
...省略...
<dimen name="x316">316.0px</dimen>
<dimen name="x317">317.0px</dimen>
<dimen name="x318">318.0px</dimen>
<dimen name="x319">319.0px</dimen>
<dimen name="x320">320px</dimen>
</resources>

F:\layoutroot\values-480x320\lay_y.xml

<?xml version="1.0" encoding="utf-8"?>
<resources><dimen name="y1">1.0px</dimen>
<dimen name="y2">2.0px</dimen>
<dimen name="y3">3.0px</dimen>
<dimen name="y4">4.0px</dimen>
<dimen name="y5">5.0px</dimen>
...省略...
<dimen name="y476">476.0px</dimen>
<dimen name="y477">477.0px</dimen>
<dimen name="y478">478.0px</dimen>
<dimen name="y479">479.0px</dimen>
<dimen name="y480">480px</dimen>
</resources>

在480×320的设备上,x2就代表2.0px,y2就代表3.0px。
在800×480的设备上,x2就代表3.0px,y2就代表3.33px。依次类推。

我们需要把上面生成的value文件夹拷贝到对应的工程目录下

如何使用:

<Button
android:background="#abd123"
android:layout_width="@dimen/x160"
android:layout_height="@dimen/y240"
android:text="Button" />

这样设置,在各种屏幕宽度的设备上,此Button的宽度和高度就都占屏幕的一半。

效果如下:

我们看到这种方式可以支持大部分屏幕宽度的设备,但是我们也看到了一些设备,如Nexus9、Nexus10上并没有显示出Button,这是因为我们生成的尺寸资源文件里没有对应分辨率的xml文件。

android屏幕适配的全攻略2--支持手机各种屏幕密度dpi的更多相关文章

  1. android屏幕适配的全攻略3-动态获取手机屏幕宽高及动态设置控件宽高

    1.获取手机屏幕宽高: DisplayMetrics dm = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetr ...

  2. android屏幕适配的全攻略--支持不同的屏幕尺寸适配平板和手机

    一. 核心概念与单位详解 1. 什么是屏幕尺寸.屏幕分辨率.屏幕像素密度? 屏幕分辨率越大,手机越清晰 dpi就是dot per inch dot意思是点,就是每英寸上面的像素点数 android原始 ...

  3. 打造一个高逼格的android开源项目——小白全攻略 (转)

    转自:打造一个高逼格的android开源项目 小引子 在平时的开发过程中,我们经常会查阅很多的资料,最常参考的是 github 的开源项目.通常在项目的主页面能看到项目的简介和基本使用,并且时不时能看 ...

  4. Android Preference 设置偏好全攻略

    Android 设置是每个App必不可小的东西,看似很简单,但是初学不熟悉的很花时间去研究,特别样式兼容方面,以及有自定义设置的需求,下面是对用法做一个总结 Preference结构 界面结构看下图 ...

  5. Android屏幕适配全攻略 (转载)

    http://blog.csdn.net/jdsjlzx/article/details/45891551 https://github.com/hongyangAndroid/AndroidAuto ...

  6. Android屏幕适配全攻略(最权威的官方适配指导)屏幕尺寸 屏幕分辨率 屏幕像素密度 dpdipdpisppx mdpihdpixdpixxdpi

    Android屏幕适配全攻略(最权威的官方适配指导)原创赵凯强 发布于2015-05-19 11:34:17 阅读数 153734 收藏展开 转载请注明出处:http://blog.csdn.net/ ...

  7. 【收藏】Android屏幕适配全攻略(最权威的Google官方适配指导)

    来源:http://blog.csdn.net/zhaokaiqiang1992 更多:Android AutoLayout全新的适配方式, 堪称适配终结者 Android的屏幕适配一直以来都在折磨着 ...

  8. Android屏幕适配全攻略(最权威的官方适配指导)(转),共大家分享。

    Android的屏幕适配一直以来都在折磨着我们这些开发者,本篇文章以Google的官方文档为基础,全面而深入的讲解了Android屏幕适配的原因.重要概念.解决方案及最佳实践,我相信如果你能认真的学习 ...

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

    招聘信息: Cocos2d-X 前端主程 [新浪微博]手机客户端iOS研发工程师 20k-40k iOS 开发工程师 iOS高级开发工程师(中国排名第一的企业级移动互联网云计算公司 和创科技 红圈营销 ...

随机推荐

  1. Spring Cloud 学习笔记一

    一.spring cloud 搭建注册中心(Eureka server) 1.spring cloud中提供了多种分步式服务组件,其都依赖于注册中心(eureka),注册中心的服务者与发现者都通过Eu ...

  2. Error C2079 'CMFCPropertySheet::m_wndOutlookBar' uses undefined class 'CMFCOutlookBar'

    Severity Code Description Project File Line Suppression StateError C2079 'CMFCPropertySheet::m_wndOu ...

  3. 04 . 前端之JQuery

    JQuery简介 # 1. jQuery是一个轻量级的.兼容多浏览器的JavaScript库.# 2. jQuery使用户能够更方便地处理HTML Document.Events.实现动画效果.方便地 ...

  4. Alpha冲刺 —— 5.7

    这个作业属于哪个课程 软件工程 这个作业要求在哪里 团队作业第五次--Alpha冲刺 这个作业的目标 Alpha冲刺 作业正文 正文 github链接 项目地址 其他参考文献 无 一.会议内容 1.展 ...

  5. [C#.NET拾遗补漏]01:字符串操作

    字符串操作在任意编程语言的日常编程中都随处可见,今天来汇总一下 C# 中关于字符串的一些你可能遗忘或遗漏的知识点. 逐字字符串 在普通字符串中,反斜杠字符是转义字符.而在逐字字符串(Verbatim ...

  6. Java并发编程 (九) 线程调度-线程池

    个人博客网:https://wushaopei.github.io/    (你想要这里多有) 声明:实际上,在开发中并不会普遍的使用Thread,因为它具有一些弊端,对并发性能的影响比较大,如下: ...

  7. Java实现 LeetCode 392 判断子序列

    392. 判断子序列 给定字符串 s 和 t ,判断 s 是否为 t 的子序列. 你可以认为 s 和 t 中仅包含英文小写字母.字符串 t 可能会很长(长度 ~= 500,000),而 s 是个短字符 ...

  8. java实现立方和等式

    考虑方程式:a^3 + b^3 = c^3 + d^3 其中:"^"表示乘方.a.b.c.d是互不相同的小于30的正整数. 这个方程有很多解.比如: a = 1,b=12,c=9, ...

  9. java实现第五届蓝桥杯等额本金

    等额本金 题目描述 小明从银行贷款3万元.约定分24个月,以等额本金方式还款. 这种还款方式就是把贷款额度等分到24个月.每个月除了要还固定的本金外,还要还贷款余额在一个月中产生的利息. 假设月利率是 ...

  10. Linux 用户组管理命令

    groupadd 组名,可以添加用户组 groupmod -n 新组名 老组名,可以修改组名 groupdel 组名,可以删除组(组中不能有初始用户存在,附加用户无所谓) gpasswd -a 用户名 ...