Android屏幕适配讲解与实战
文章大纲
一、屏幕适配是什么
二、 重要概念讲解
三、屏幕适配实战
四、项目源码下载

一、屏幕适配是什么
Android中屏幕适配就是通过对尺寸单位、图片、文字、布局这四种类型的资源进行合理的设计和规划,在布局时合理利用各种类型的资源,让布局拥有适应能力,能在各种设备下保持良好的展现效果。
二、常见屏幕适配方法介绍
1 屏幕尺寸
屏幕尺寸是指屏幕对角线的长度,单位是英寸,1英寸=2.54厘米
2 屏幕分辨率
屏幕分辨率是指横纵向上的像素点数,单位是px,1px=1个像素点,一般以纵向像素横向像素,如19201080,分辨率越高,显示效果越好。
3 屏幕像素密度
屏幕像素密度是指每英寸上的像素点数,单位是dpi,屏幕像素密度与屏幕尺寸和屏幕分辨率有关。
4. px、dp、sp
(1)安卓里面获取屏幕宽和高,也是以px作为单位的。
(2)在160dpi(即分辨率是480*320)基准下,1dip=1px(也就是px不能适配所有机型),如下图所示,要充满屏幕,箭头的px值是不一样的。1dp=那个机型dpi/160px。所以用dp会比px好。

(3)在使用sp(设置文字的)时候,使用偶数,不要使用奇数或者小数,最最推荐的是12.14.18,22sp的文字大小(尽量不要使用12sp以下的大小,用户可能看不清楚)。
5. mdpi,hdpi,xdpi,xxdpi
安卓软件运行时,会自动根据屏幕像素去不同文件夹加载对应图片。

三、屏幕适配实战
1. 使用dp设置控件大小,sp设置字体大小(不可行)
activity_main2.xml布局代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<Button
android:layout_width="200dp"
android:layout_height="50dp"
android:textSize="20sp"
android:text="按钮1"/>
<Button
android:layout_width="200dp"
android:layout_height="50dp"
android:layout_marginTop="20dp"
android:textSize="20sp"
android:text="按钮2"/>
</LinearLayout>
运行结果如下:

得出结论:即使使用dp设置控件大小,sp设置字体大小,也是无法适配所有手机的。因为这是谷歌自己的一个标准。dp是根据屏幕像素和分辨率一起来解决的。但是有些手机像素和分辨率不是对应关系,所以不行。
2. weight属性使用
activity_main3.xml布局代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
tools:context=".MainActivity">
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textSize="20sp"
android:text="按钮1"/>
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:textSize="20sp"
android:text="按钮2"/>
</LinearLayout>
运行结果如下:

得出结论:采用weight,可以使得组件按屏幕大小进行放大缩小,weight的计算方式如下:

如果将xml中的android:layout_weight属性值1和2互换,则结果是相反的,有兴趣伙伴可以下载源码看看效果。
3. 使用自动拉伸位图.9图
什么是.9图
因为Android有太多的分辨率了,当圆角矩形控件在被拉伸放大的时候,圆角的部分就会出现模糊的情况。而点九切图就不同,它可以保证不管你上下还是左右拉伸,放大都可以保持原有的清晰度。
.9图存放位置

4. 屏幕方向限定符large
比如我们想在屏幕竖屏时候加载什么布局,在屏幕横线时候加载什么布局。在手机加载什么布局,在平板电脑加载什么布局。
该文章暂不展开讨论,将在Fragment使用中进行讲解。
5.多文件适配(重要)
大家经过上面的学习之后,已经知道有些手机像素和分辨率不是对应关系,无法使用dp等单位来解决,那么我们可以以某个常见的屏幕分辨率作为基准,自定义需要适配到的屏幕分辨率的xml文件,如下图所示:


使用生成器生成对应的文件
生成器代码(使用320*480作为基准)如下:
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintWriter;
/**
* Created by 吴晓畅
*/
public class GenerateValueFiles {
private int baseW;
private int baseH;
private String dirStr = "./res";
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";
private final static String VALUE_TEMPLATE = "values-{0}x{1}";
//新增文件的分辨率,以x,x;隔开
private static final String SUPPORT_DIMESION = "320,480;480,800;480,854;540,960;600,1024;720,1184;720,1196;720,1280;768,1024;768,1280;800,1280;1080,1812;1080,1920;1440,2560;";
private String supportStr = SUPPORT_DIMESION;
public GenerateValueFiles(int baseX, int baseY, String supportStr) {
this.baseW = baseX;
this.baseH = baseY;
if (!this.supportStr.contains(baseX + "," + baseY)) {
this.supportStr += baseX + "," + baseY + ";";
}
this.supportStr += validateInput(supportStr);
System.out.println(supportStr);
File dir = new File(dirStr);
if (!dir.exists()) {
dir.mkdir();
}
System.out.println(dir.getAbsoluteFile());
}
private String validateInput(String supportStr) {
StringBuffer sb = new StringBuffer();
String[] vals = supportStr.split("_");
int w = -1;
int h = -1;
String[] wh;
for (String val : vals) {
try {
if (val == null || val.trim().length() == 0)
continue;
wh = val.split(",");
w = Integer.parseInt(wh[0]);
h = Integer.parseInt(wh[1]);
} catch (Exception e) {
System.out.println("skip invalidate params : w,h = " + val);
continue;
}
sb.append(w + "," + h + ";");
}
return sb.toString();
}
public void generate() {
String[] vals = supportStr.split(";");
for (String val : vals) {
String[] wh = val.split(",");
generateXmlFile(Integer.parseInt(wh[0]), Integer.parseInt(wh[1]));
}
}
private void generateXmlFile(int w, int h) {
StringBuffer sbForWidth = new StringBuffer();
sbForWidth.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
sbForWidth.append("<resources>");
float cellw = w * 1.0f / baseW;
System.out.println("width : " + w + "," + baseW + "," + cellw);
for (int i = 1; i < baseW; i++) {
sbForWidth.append(WTemplate.replace("{0}", i + "").replace("{1}",
change(cellw * i) + ""));
}
sbForWidth.append(WTemplate.replace("{0}", baseW + "").replace("{1}",
w + ""));
sbForWidth.append("</resources>");
StringBuffer sbForHeight = new StringBuffer();
sbForHeight.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
sbForHeight.append("<resources>");
float cellh = h *1.0f/ baseH;
System.out.println("height : "+ h + "," + baseH + "," + cellh);
for (int i = 1; i < baseH; i++) {
sbForHeight.append(HTemplate.replace("{0}", i + "").replace("{1}",
change(cellh * i) + ""));
}
sbForHeight.append(HTemplate.replace("{0}", baseH + "").replace("{1}",
h + ""));
sbForHeight.append("</resources>");
File fileDir = new File(dirStr + File.separator
+ VALUE_TEMPLATE.replace("{0}", h + "")//
.replace("{1}", w + ""));
fileDir.mkdir();
File layxFile = new File(fileDir.getAbsolutePath(), "lay_x.xml");
File layyFile = new File(fileDir.getAbsolutePath(), "lay_y.xml");
try {
PrintWriter pw = new PrintWriter(new FileOutputStream(layxFile));
pw.print(sbForWidth.toString());
pw.close();
pw = new PrintWriter(new FileOutputStream(layyFile));
pw.print(sbForHeight.toString());
pw.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
public static float change(float a) {
int temp = (int) (a * 100);
return temp / 100f;
}
public static void main(String[] args) {
//基准大小,比如320.480,其他则以这个基准进行放大缩小
int baseW = 320;
int baseH = 480;
String addition = "";
try {
if (args.length >= 3) {
baseW = Integer.parseInt(args[0]);
baseH = Integer.parseInt(args[1]);
addition = args[2];
} else if (args.length >= 2) {
baseW = Integer.parseInt(args[0]);
baseH = Integer.parseInt(args[1]);
} else if (args.length >= 1) {
addition = args[0];
}
} catch (NumberFormatException e) {
System.err
.println("right input params : java -jar xxx.jar width height w,h_w,h_..._w,h;");
e.printStackTrace();
System.exit(-1);
}
new GenerateValueFiles(baseW, baseH, addition).generate();
}
}
运行代码,结果会在项目的res文件夹中生成对应的内容,如下图所示:


温馨提示:上图每个文件夹是以320*480作为基准进行放大缩小后的px值
将上面生成的文件夹复制到实际项目中
复制所有文件夹,右击studio中的res文件夹进行粘贴

xml布局中进行引用
activity_main4.xml代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<Button
android:layout_width="@dimen/x200"
android:layout_height="@dimen/y30"
android:text="按钮1"/>
<Button
android:layout_width="@dimen/x200"
android:layout_height="@dimen/y30"
android:layout_marginTop="@dimen/y30"
android:text="按钮2"/>
</LinearLayout>
运行结果如下图所示:

温馨提示:
- 如果运行后发现某个尺寸的屏幕没有是配到,那么可以在生成器中添加对应屏幕尺寸,重新生成文件夹,之后拷贝到项目中即可
- 图片适配则可以采用图片放在不同文件夹里面,系统会自动选图,但最好每次切图都包含多种分辨率的图片,例如某一测试的机器是xxhdpi密度的,所以当把图片放在xxhdpi时候(其他文件夹没放),加载时候占用内存是较小的。默认是没有加载任何东西(运行一个空白app)占用的内存。如果加载其他像素下的图片,则会占用很多内容。所以总结来说就是要各个文件夹都放有图片,可以减少占用内存的加载。

四、项目源码下载
Android屏幕适配讲解与实战的更多相关文章
- 【收藏】Android屏幕适配全攻略(最权威的Google官方适配指导)
来源:http://blog.csdn.net/zhaokaiqiang1992 更多:Android AutoLayout全新的适配方式, 堪称适配终结者 Android的屏幕适配一直以来都在折磨着 ...
- Android屏幕适配全攻略(最权威的官方适配指导)(转),共大家分享。
Android的屏幕适配一直以来都在折磨着我们这些开发者,本篇文章以Google的官方文档为基础,全面而深入的讲解了Android屏幕适配的原因.重要概念.解决方案及最佳实践,我相信如果你能认真的学习 ...
- Android屏幕适配全攻略(最权威的官方适配指导) (转)
招聘信息: Cocos2d-X 前端主程 [新浪微博]手机客户端iOS研发工程师 20k-40k iOS 开发工程师 iOS高级开发工程师(中国排名第一的企业级移动互联网云计算公司 和创科技 红圈营销 ...
- 【转】Android屏幕适配全攻略(最权威的官方适配指导)
原文网址:http://blog.csdn.net/jdsjlzx/article/details/45891551 Android的屏幕适配一直以来都在折磨着我们这些开发者,本篇文章以Google的 ...
- Android屏幕适配全攻略(最权威的官方适配指导)
转载请注明出处:http://blog.csdn.net/zhaokaiqiang1992 Android的屏幕适配一直以来都在折磨着我们这些开发者,本篇文章以Google的官方文档为基础,全面而深入 ...
- Android屏幕适配全攻略(最权威的官方适配指导)
摘自:http://www.cocoachina.com/android/20151030/13971.html Android屏幕适配出现的原因 在我们学习如何进行屏幕适配之前,我们需要先了解下为什 ...
- Android 屏幕适配:最全面的解决方案
转自:https://www.jianshu.com/p/ec5a1a30694b 前言 Android的屏幕适配一直以来都在折磨着我们Android开发者,本文将结合: Google的官方权威适配文 ...
- Android 一种非常好用的Android屏幕适配
前言 网上关于屏幕适配的文章已经铺天盖地了,为什么我还要讲?因为网上现在基本都是使用px适配,即每种屏幕分辨率的设备需要定义一套dimens.xml文件.再加上有些手机还有虚拟按键(例如华为),这样就 ...
- 好用的Android屏幕适配
前言 网上关于屏幕适配的文章已经铺天盖地了,为什么还要讲?因为网上现在基本都是使用px适配,即每种屏幕分辨率的设备需要定义一套dimens.xml文件.再加上有些手机还有虚拟按键(例如华为),这样就还 ...
随机推荐
- cropper(裁剪图片)插件使用(案例)
公司发布微信H5前端阵子刚刚弄好的H5端的图片上传插件,现在有需要裁剪图片.前端找了一个插件---cropper 本人对这插件不怎么熟悉,这个案例最好用在一个页面只有一个上传图片的功能上而且只适合单个 ...
- synchronized修饰方法和代码块的区别
先看一段代码 Class A { public synchronized methodA() {//对当前对象加锁 } public methodB() { synchronized(this){}/ ...
- oracle数据库-错误编码大全
ORA-00001: 违反唯一约束条件 (.) ORA-00017: 请求会话以设置跟踪事件 ORA-00018: 超出最大会话数 ORA-00019: 超出最大会话许可数 ORA-000 ...
- Linux Vim配置
用过很多vim配置的版本,怎么说,想轻量级就不要胡加乱七八糟的功能:如果不在乎反应是不是快速,侧重功能是否强大,可以参考vim大神的配置策略(spf13-vim)https://github.com/ ...
- 基于Mybatis的Dao层的开发
基于Mybatis的Dao层开发 SqlSessionFactoryBuilder用于创建SqlSessionFacoty,SqlSessionFacoty一旦创建完成就不需要SqlSessionFa ...
- win7 中如何设置eclipse的背景色--Console
http://blog.csdn.net/u013161399/article/details/47297781
- 解决C语言程序报错:return type defaults to‘int’
下面是通过自定义一个函数printN,之后在main函数中调用printN,使得可以通过输入整数N,将从1到N的全部整数都打印出来的程序. 但是在编译过程中却报错: return type defau ...
- js算法初窥03(简单搜索及去重算法)
前面我们了解了一些常用的排序算法,那么这篇文章我们来看看搜索算法的一些简单实现,我们先来介绍一个我们在实际工作中一定用到过的搜索算法--顺序搜索. 1.顺序搜索 其实顺序搜索十分简单,我们还是以第一篇 ...
- 使用nginx搭建https服务器
http://www.cnblogs.com/tintin1926/archive/2012/07/12/2587311.html 最近在研究nginx,整好遇到一个需求就是希望服务器与客户端之间传输 ...
- vs插件-基于TFS的源码记录可视化
插件地址:https://marketplace.visualstudio.com/items?itemName=AlexandrBiryukov.TFSSourceControlHistoryVis ...