SocksCap代理使用教程

mikel阅读(884)

很多使用SSH的用户都会遇到这样的问题,为什么我已经设置了socks代理,还设置了OpenDNS,怎么还是上不了Facebook,这就涉及到DNS污染技术,需要用户使用远程解析域名的方法才能访问目标网站

对于Firefox来说,远程解析域名的设置非常简单,只要在about:config修改 network.proxy.socks_remote_dns=true就可以了。但对于IE和其他软件来说,就没有类似的修改方法,需要使用一个名为 SocksCap的代理软件来解决这个问题。

SocksCap是一个通过Socks代理连接网络的代理服务器第三方支持软件,拥有功能 强大的Socks调度,所有Windows应用(如IE、Firefox、QQ、FTP等)都可以使用这个Socks代理工具通过Socks代理服务器上 网,即使不支持Socks代理的应用也可以用Socks代理上网。

首先下载安装SocksCap,安装结束后,运行SocksCap,出现如下图所示界面,这时候需要进行一些配置工作,选择菜单File – Settings。

SocksCap代理

在Socks Server中填入Socks代理的IP地址:127.0.0.1,在Port项中填入代理端口:1080;Protocol选择Socks5项,选中Resolve all names remot,点击“确定”。

SocksCap代理

接下来要做的便是把应用程序加入到SocksCap中。点File – New选项就可以出现如下图窗口。

SocksCap代理

点Browse浏览选择应用程序,如IE等应用的EXE文件,其他选择默认,点“OK”就可以完成配置。

更简便的操作方法是将应用程序的快捷图标拖入主窗口中既可,然后鼠标右键会显示“New application profile”,给这个应用命名,然后给出要运行的程序和工作目录,点“OK”设置生效。

这时候的SocksCap主界面会如下图所示,列出一系列应用程序的图标。

SocksCap代理

双击SocksCap主界面的应用程序图标,即可通过SocksCap运行应用程序。若双击桌面上的应用程序,则为不使用代理运行程序。

总体来说,SocksCap代理的目的是把一些不支持socks的代理的软件在进行网络通信的时候的数据全部转化成socks代理数据,然后再通过代理出去。对于IE来说,不需要在IE里面做任何配置,只要从SocksCap中运行IE就可以支持Socks代理。

除了SocksCap之外,也可以使用功能和界面几乎完全相同的另一款软件FreeCap来代替。

[转载]TOR使用说明和介绍-月光博客

mikel阅读(860)

来源: [转载]TOR使用说明和介绍-月光博客

   Tor的全称是“The Onion Router”,号称是“An anonymous Internet communicaton system”。它针对现阶段大量存在的流量过滤、嗅探分析等工具,在JAP之类软件基础上改进的,支持Socks5,并且支持动态代理链(通过Tor访 问一个地址时,所经过的节点在Tor节点群中随机挑选,动态变化,由于兼顾速度与安全性,节点数目通常为2-5个),因此难于追踪,有效地保证了安全性。 另一方面,Tor 的分布式服务器可以自动获取,因此省却了搜寻代理服务器的精力。

将Tor和SocksCap32(SocksCap32可以用FreeCap替代)联合使用,将得到一个永远有效的支持Socks5的代理。由于Socks5的代理实在太难找了,所以Tor实在是一大福音。

这个软件使用起来也很简单。先去下载最新版本的TOR和SOCKSCAP32,下载完毕后我们安装TOR,然后我们就可以运行Sockscap32,设 置服务器地址为,Socks5:127.0.0.1:9050,然后把你的IE浏览器拉入Sockscap,双击后打开IE,即可通过TOR上网。

TOR

很多网络软件本身也支持使用代理,因此可以连Sockscap32也可以省了,比如FLASHFXP,QQ等都支持Socks5,只要在代理服务器地址填写127.0.0.1,端口填写9050,即可实现安全上网,那时你的QQ好友会发现你的IP竟然是来自美国呢。

除非注明,月光博客文章均为原创,转载请以链接形式标明本文地址

本文地址:http://www.williamlong.info/archives/424.html

[转载]Android开发--传感器介绍 - Android移动开发技术文章_手机开发 - 红黑联盟

mikel阅读(820)

来源: [转载]Android开发–传感器介绍 – Android移动开发技术文章_手机开发 – 红黑联盟

获取手机中的传感器的步骤为:

获取SensorManager对象
执行SensorManager对象的getDefaultSensor()方法获取Sensor对象,这里getDefaultSensor()方法要传递一个参数,指定具体的传感器类型
获取Sensor对象中的各种属性
下面给出获取手机内传感器的实现代码:
Log.d(“BruceZhang”, “以下是你的手机里的传感器:”);
            List<Sensor> sensors=sensorManager.getSensorList(Sensor.TYPE_ALL);
            Log.d(“BruceZhang”, “—>”);
            for(Sensor sensor: sensors){
                Log.d(“BruceZhang”, sensor.getName());
            }
            //通过使用getDefaultSensor方法获得一个特定的传感器
/               Sensor sensor=sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY);
在知道怎么获取传感器之后,我们需要使用程序获取传感器的值,下面给出实例代码:
SensorManager sensorManager=(SensorManager)getSystemService(Context.SENSOR_SERVICE);
        Sensor sensor=sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
        sensorManager.registerListener(new SensorEventListener() {
            /*
             * SensorEvent event
             * 一旦传感器感知外界条件发生变化,就会把相应的数据传递给这个对象
             * 一般会把这个方法放在onCreate里,不用手动的去获取
             */
            @Override
            public void onSensorChanged(SensorEvent event) {
                // TODO Auto-generated method stub
                float auc=event.accuracy;
                //这里的第一个元素代表的是光线的强度
                float lux=event.values[0];
                Log.d(“BruceZhang”, auc+””);
                Log.d(“BruceZhang”, lux+””);
            }
            @Override
            public void onAccuracyChanged(Sensor sensor, int accuracy) {
                // TODO Auto-generated method stub
            }
        }, sensor, SensorManager.SENSOR_DELAY_NORMAL);
        //SensorManager.SENSOR_DELAY_NORMAL
        //这个参数就是设置传感器的采样率
    }
传感器有一系列的属性:
1、传感器的采样率
  a) SENSOR_DELAY_NOMAL    (200000微秒)
  b) SENSOR_DELAY_UI       (60000微秒)
  c) SENSOR_DELAY_GAME     (20000微秒)
  d) SENSOR_DELAY_FASTEST  (0微秒)
2、传感器的属性
  a) 传感器的名称
  b) 传感器制造商
  c) 传感器功率
  d) 传感器的resulotion
获取这些属性的方法也很简单,代码如下:
SensorManager sensorManager=(SensorManager)getSystemService(Context.SENSOR_SERVICE);
                Sensor sensor=sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
                sensorManager.registerListener(new SensorEventListener() {
                    @Override
                    public void onSensorChanged(SensorEvent event) {
                        // TODO Auto-generated method stub
                        //传感器的名字
                        String sensorName=event.sensor.getName();
                        //传感器制造商的名字
                        String sensorVendor=event.sensor.getVendor();
                        //传感器的分辨率,传感器所能识别的最小的精度是多少
                        float sensorRevolution=event.sensor.getResolution();
                        //传感器的功率
                        float sensorPower=event.sensor.getPower();
                        //传感器取得数据的时间是多少
                        double timeStamp=event.timestamp;
                        //打印数据
                        Log.d(“BruceZhang”, sensorName+””);
                        Log.d(“BruceZhang”, sensorVendor+””);
                        Log.d(“BruceZhang”, sensorRevolution+””);
                        Log.d(“BruceZhang”, sensorPower+””);
                        Log.d(“BruceZhang”, timeStamp+””);
                    }
                    @Override
                    public void onAccuracyChanged(Sensor sensor, int accuracy) {
                        // TODO Auto-generated method stub
                    }
                }, sensor, SensorManager.SENSOR_DELAY_NORMAL);
            }
下面实现的这个实例实现了上述内容的综合:
实例的完整代码如下:
/*
 * 传感器会通过传感器事件把值传给用户
 * 所以,我们的应用程序是被动的,等待传感器把数据传递给SensorEvent对象
 */
public class MainActivity extends Activity {
    private Button button;
    private Button button2;
    private Button button3;
    private SensorManager sensorManager;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //得到SensorManager对象
        sensorManager=(SensorManager)getSystemService(Context.SENSOR_SERVICE);
        button=(Button)findViewById(R.id.sensorButton);
        button2=(Button)findViewById(R.id.lightButton);
        button3=(Button)findViewById(R.id.lightButton2);
        button3.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                SensorManager sensorManager=(SensorManager)getSystemService(Context.SENSOR_SERVICE);
                Sensor sensor=sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
                sensorManager.registerListener(new SensorEventListener() {
                    @Override
                    public void onSensorChanged(SensorEvent event) {
                        // TODO Auto-generated method stub
                        //传感器的名字
                        String sensorName=event.sensor.getName();
                        //传感器制造商的名字
                        String sensorVendor=event.sensor.getVendor();
                        //传感器的分辨率,传感器所能识别的最小的精度是多少
                        float sensorRevolution=event.sensor.getResolution();
                        //传感器的功率
                        float sensorPower=event.sensor.getPower();
                        //传感器取得数据的时间是多少
                        double timeStamp=event.timestamp;
                        //打印数据
                        Log.d(“BruceZhang”, sensorName+””);
                        Log.d(“BruceZhang”, sensorVendor+””);
                        Log.d(“BruceZhang”, sensorRevolution+””);
                        Log.d(“BruceZhang”, sensorPower+””);
                        Log.d(“BruceZhang”, timeStamp+””);
                    }
                    @Override
                    public void onAccuracyChanged(Sensor sensor, int accuracy) {
                        // TODO Auto-generated method stub
                    }
                }, sensor, SensorManager.SENSOR_DELAY_NORMAL);
            }
        });
        button2.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                SensorManager sensorManager=(SensorManager)getSystemService(Context.SENSOR_SERVICE);
                Sensor sensor=sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
                sensorManager.registerListener(new SensorEventListener() {
                    /*
                     * SensorEvent event
                     * 一旦传感器感知外界条件发生变化,就会把相应的数据传递给这个对象
                     * 一般会把这个方法放在onCreate里,不用手动的去获取
                     */
                    @Override
                    public void onSensorChanged(SensorEvent event) {
                        // TODO Auto-generated method stub
                        float auc=event.accuracy;
                        //这里的第一个元素代表的是光线的强度
                        float lux=event.values[0];
                        Log.d(“BruceZhang”, auc+””);
                        Log.d(“BruceZhang”, lux+””);
                    }
                    @Override
                    public void onAccuracyChanged(Sensor sensor, int accuracy) {
                        // TODO Auto-generated method stub
                    }
                }, sensor, SensorManager.SENSOR_DELAY_NORMAL);
                //SensorManager.SENSOR_DELAY_NORMAL
                //这个参数就是设置传感器的采样率
            }
        });
        button.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View arg0) {
                // TODO Auto-generated method stub
                Log.d(“BruceZhang”, “以下是你的手机里的传感器:”);
                List<Sensor> sensors=sensorManager.getSensorList(Sensor.TYPE_ALL);
                Log.d(“BruceZhang”, “—>”);
                for(Sensor sensor: sensors){
                    Log.d(“BruceZhang”, sensor.getName());
                }
                //通过使用getDefaultSensor方法获得一个特定的传感器
//              Sensor sensor=sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY);
            }
        });
    }
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }
}

[转载]GITHUB使用教程 - luwenjie - 博客园

mikel阅读(996)

来源: [转载]GITHUB使用教程 – luwenjie – 博客园

windows系统下:

1、安装完成后,还需要最后一步设置,在命令行输入:

$ git config --global user.name "Your Name"
$ git config --global user.email "email@example.com"

2、
创建版本库

创建一个版本库非常简单,首先,选择一个合适的地方,创建一个空目录:

$ mkdir learngit
$ cd learngit
$ pwd
/Users/michael/learngit

第二步,通过git init命令把这个目录变成Git可以管理的仓库:

$ git init
Initialized empty Git repository in /Users/michael/learngit/.git/

3、更新版本库

第一步,用命令git add告诉Git,把文件添加到仓库:

$ git add readme.txt
$ git add . //整个文件夹添加

第二步,用命令git commit告诉Git,把文件提交到仓库:

$ git commit -m "wrote a readme file"
[master (root-commit) cb926e7] wrote a readme file
 1 file changed, 2 insertions(+)
 create mode 100644 readme.txt

4、
版本回退
git reset --hard commit_id

5、删除文件

命令git rm删掉,并且git commit

$ git rm test.txt
rm 'test.txt'
$ git commit -m "remove test.txt"
[master d17efd8] remove test.txt
 1 file changed, 1 deletion(-)

6、远程仓库

第1步:创建SSH Key。在用户主目录下,看看有没有.ssh目录,如果有,再看看这个目录下有没有id_rsaid_rsa.pub这两个文件,如果已经有了,可直接跳到下一步。如果没有,打开Shell(Windows下打开Git Bash),创建SSH Key:

$ ssh-keygen -t rsa -C "youremail@example.com"

你需要把邮件地址换成你自己的邮件地址,然后一路回车,使用默认值即可,由于这个Key也不是用于军事目的,所以也无需设置密码。

第2步:登陆GitHub,打开“Account settings”,“SSH Keys”页面:

然后,点“Add SSH Key”,填上任意Title,在Key文本框里粘贴id_rsa.pub文件的内容

 

7、添加远程库

首先,登陆GitHub,然后,在右上角找到“Create a new repo”按钮,创建一个新的仓库:在Repository name填入learngit,其他保持默认设置

然后,把本地仓库的内容推送到GitHub仓库。

现在,我们根据GitHub的提示,在本地的learngit仓库下运行命令:

$ git remote add origin git@github.com:yourname/learngit.git

下一步,就可以把本地库的所有内容推送到远程库上:

$ git push -u origin master
Counting objects: 19, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (19/19), done.
Writing objects: 100% (19/19), 13.73 KiB, done.
Total 23 (delta 6), reused 0 (delta 0)
To git@github.com:michaelliao/learngit.git
 * [new branch]      master -> master
Branch master set up to track remote branch master from origin.

由于远程库是空的,我们第一次推送
master分支时,加上了-u参数,Git不但会把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和远程的master分支关联起来,在以后的推送或者拉取时就可以简化命令。

从现在起,只要本地作了提交,就可以通过命令:

$ git push origin master
8、从远程库克隆
$ git clone git@github.com:yourname/gitskills.git
Cloning into 'gitskills'...
remote: Counting objects: 3, done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (3/3), done.

9、
创建与合并分支

首先,我们创建dev分支,然后切换到dev分支:

$ git checkout -b dev
Switched to a new branch 'dev'

然后,用git branch命令查看当前分支:

$ git branch
* dev
  master

dev分支的工作完成,我们就可以切换回master分支:

$ git checkout master
Switched to branch 'master'

现在,我们把dev分支的工作成果合并到master分支上:

$ git merge dev
Updating d17efd8..fec145a
Fast-forward
 readme.txt |    1 +
 1 file changed, 1 insertion(+)

合并完成后,就可以放心地删除dev分支了:

$ git branch -d dev
Deleted branch dev (was fec145a).

删除后,查看branch,就只剩下master分支了:

$ git branch
* master

10、分支管理策略

准备合并dev分支,请注意--no-ff参数,表示禁用Fast forward

$ git merge --no-ff -m "merge with no-ff" dev
合并分支时,加上
--no-ff参数就可以用普通模式合并,合并后的历史有分支,能看出来曾经做过合并,而fast forward合并就看不出来曾经做过合并。






小结

现在总结一下今天学的两点内容:

初始化一个Git仓库,使用git init命令。

添加文件到Git仓库,分两步:

  • 第一步,使用命令git add <file>,注意,可反复多次使用,添加多个文件;
  • 第二步,使用命令git commit,完成。

小结

  • 要随时掌握工作区的状态,使用git status命令。
  • 如果git status告诉你有文件被修改过,用git diff可以查看修改内容。

小结

现在总结一下:

  • HEAD指向的版本就是当前版本,因此,Git允许我们在版本的历史之间穿梭,使用命令git reset --hard commit_id
  • 穿梭前,用git log可以查看提交历史,以便确定要回退到哪个版本。
  • 要重返未来,用git reflog查看命令历史,以便确定要回到未来的哪个版本。
小结
git add命令实际上就是把要提交的所有修改放到暂存区(Stage),然后,执行git commit就可以一次性把暂存区的所有修改提交到分支。

小结

又到了小结时间。

场景1:当你改乱了工作区某个文件的内容,想直接丢弃工作区的修改时,用命令git checkout -- file

场景2:当你不但改乱了工作区某个文件的内容,还添加到了暂存区时,想丢弃修改,分两步,第一步用命令git reset HEAD file,就回到了场景1,第二步按场景1操作。

场景3:已经提交了不合适的修改到版本库时,想要撤销本次提交,参考版本回退一节,不过前提是没有推送到远程库。

 

小结

要关联一个远程库,使用命令git remote add origin git@server-name:path/repo-name.git

关联后,使用命令git push -u origin master第一次推送master分支的所有内容;

此后,每次本地提交后,只要有必要,就可以使用命令git push origin master推送最新修改;

分布式版本系统的最大好处之一是在本地工作完全不需要考虑远程库的存在,也就是有没有联网都可以正常工作,而SVN在没有联网的时候是拒绝干活的!当有网络的时候,再把本地提交推送一下就完成了同步,真是太方便了!

小结

Git鼓励大量使用分支:

查看分支:git branch

创建分支:git branch <name>

切换分支:git checkout <name>

创建+切换分支:git checkout -b <name>

合并某分支到当前分支:git merge <name>

删除分支:git branch -d <name>

[转载]详解OpenGL中的各种变换(投影变换,模型变换,视图变换)(二)——投影变换 - caster99 - 博客园

mikel阅读(871)

来源: [转载]详解OpenGL中的各种变换(投影变换,模型变换,视图变换)(二)——投影变换 – caster99 – 博客园

下面介绍投影变换矩阵。这个相比较上一遍的就比较难了。主要分为透视投影矩阵和正交投影矩阵,本文主要介绍透视投影矩阵,正交比较简单,就给出矩阵形式。

(1)透视投影变换矩阵

我们先来说一下透视投影需要哪些参数。如图1所示,深色部分表示最终显示的区域。照相机的z轴是穿过视锥体正中心的,显示区域离相机最近的平面我们称为Znear,最远的平面我们称为Zfar。其中Znear就是最终的投影窗口。所以我们要把Znear的宽映射到坐标[-1,1],把Znear的高映射到坐标[-1,1],把ZnearZfar的深度距离映射到坐标[-1,1]。因为最后的OpenGL绘制的区域其实就是一个从(-1,-1,-1)(1,1,1)的一个立方体。而且这样映射还有个好处,就是绘制的时候靠近Znear的对象要比靠近Zfar的对象大。

图1

根据这些参数我们可以得到投影变换矩阵。首先,对于这个矩阵,我们先来看x轴和y轴。我们结合上图,根据相似三角形可以得到:

图2

我们化简一下可以得到Yproj=Znear*x/zXproj=Znear*y/z。之后我们将齐次坐标的w分量设为z,就可以得到Yproj=Znear*xXproj=Znear*y。再将坐标映射到[-1,1],除以投影窗口的长宽即可。我们得到部分透视投影矩阵:

图3

我们再来看z轴。其实z轴映射也非常简单。我们假设f(z)=A*z+B,当齐次坐标的w分量为z时,那么实际上z轴的坐标为A+B/z。我们根据映射关系得到下面两个式子:

图4

再根据这两个式子,求出AB的值(具体求解就忽略了,得到的结果就是下面矩阵第三行的两个值)。最终得到完整的透视投影变换矩阵:

图5

我们还可以用另一种方式来表达透视投影。这种方式一共有四个变量。

  • 透视的角度fovy。如图6所示,fovy表示的是照相机所看到的范围。
  • 投影窗口的宽高比aspect。如图6所示,aspect就是Znear平面的宽高比。
  • 显示区域离相机最近的距离near和离相机最远的距离far。这两个量与前面都是一样的。

图6

这个表达下的透视投影矩阵如下(计算过程跟上面一种基本一致):

图7

(2)正交投影变换矩阵

正交投影就比较简单了。如图8所示,显示区域就是一立方体。因为没有近大远小的特性,齐次坐标的w分量不需要变化,设为1.0就可以了。另外,我们也需要把x轴,y轴,z轴分别映射到坐标[-1,1]。计算过程也和透视投影变化矩阵类似。

图8
  下面是正交投影变换矩阵:
图9

[转载]详解OpenGL中的各种变换(投影变换,模型变换,视图变换)(一)——模型变换和视图变换 - caster99 - 博客园

mikel阅读(732)

来源: [转载]详解OpenGL中的各种变换(投影变换,模型变换,视图变换)(一)——模型变换和视图变换 – caster99 – 博客园

本文一些用于均参考《OpenGL编程指南(第8版)》,有兴趣的同学可以结合一起看。这篇算是整合补充。

OpenGL采用的是相机模型,就是把视图变换操作类比为使用照相机拍摄照片的过程,具体步骤如下(这里和红宝书有一些改变):

  1. 将准备拍摄的对象移动到场景中指定位置。(模型变换,Model Transform)
  2. 将相机移动到准备拍摄的位置,将它对准某个方向。(视图变换,View Transform)
  3. 设置相机的焦距,或者调整缩放比例。(投影变换,Projection Transform)
  4. 拍摄照片并变换到需要的图片大小。(这个是视口变换,我们这里不做讨论)

在这四个步骤中,前三个都是可以用变换矩阵实现的。看完本文之后基本就可以用自己写的矩阵来代替OpenGL里面的各种变换操作了。至于为什么要按照上述的顺序可以参考下面代码,有兴趣的读者可以调换一下位置试一试,其中投影变换矩阵一定要放在最左边。

1
2
3
4
/*Project:投影变换矩阵
    View:视图变换矩阵
    Model:模型变换矩阵*/
ModelViewProject = Project * View * Model;

 


下面需要知道一些矩阵和齐次坐标的相关知识,网上有很多资料,如果又不知道的可以提前了解下。

这里有必要深入讲解一下齐次坐标的意义。假设一3维向量x,我们对这个向量进行线性变换Tx,但无论T为任意3*3矩阵,都无法完成向量的平移操作(比如x=(0,0,0)Tx无论如何也不可能变换到(1,0,0))。这里我们就需要用到齐次坐标,使用齐次坐标的目的也就是通过增加额外的数值来完成向量的平移操作。熟悉OpenGL的已经知道了,将三维数据植入思维坐标空间当中就行了。就是将x=(0,0,0)转变成x=(0,0,0,1)。T也转变成4*4矩阵。

我们再讨论一下齐次坐标的一个性质, 齐次坐标所表达的其实是方向而不是位置。比如x1=(1,2,3,1)x2=(2,4,6,2)其实在3维坐标系中表示的是同一个位置。此外,最后一个分量w越大,那么齐次坐标将处于更远的位置。当OpenGL准备显示集合体的时候,它会使用左后一个分量除以前三个分量,从而将其次坐标重新变换到3维坐标系中,因此w越大的物体也会显示的越小。w0.0的时候,由于坐标位于无限近的位置,以至于显示可能会呈现出无限大。这个概念非常重要,因为下面投影矩阵就是利用这个概念!

我们接下来说明三个变换中具体包含哪些矩阵。对于一个顶点来说,我们对其先进行模型变换,在进行视图变换和投影变换。我们将这些变换细分一下就可以得到如下代码:

1
2
3
4
5
/*S:缩放 R:旋转 T:平移*/
ModelViewProject = Project
          * ViewR * ViewT
          * ModelS * ModelR * ModelT
gl_position = ModelViewProject * Vertex;

 


下面我就按照顺序逐一介绍一下各个矩阵,先介绍一下模型变换矩阵,这部分我就不细说了,了解的人应该不少。

(1)ModelT 平移矩阵

这个矩阵算是最简单的矩阵,这里举个例子。假设我们要将v=(x,y,z)沿x轴正方向平移2.5,具体计算如下:

图1

(2)ModelR 旋转矩阵

这个矩阵就比较多样了,我以前的博客关于这个矩阵有不少分析,这里也不多说了。下面列出三个欧拉角对应的旋转矩阵(也是最常用的):

图2

(3)ModelS 缩放矩阵

这个矩阵也比较简单,只要把缩放因子factor放在矩阵的对角线上就行了。具体表达如下:

图3

这三个矩阵就组成了模型变换矩阵,根据具体需求可以随意组合平移旋转缩放矩阵,并不一定非要按照上面代码中的顺序。

 


下面介绍视图矩阵,我们可以把这一步假想为设置相机或者人眼(View)的位置。设置相机一般只需要两步,首先把相机移动到固定的位置,然后把当前坐标 系转化成相机坐标系。这里不像模型变换,可以多次旋转平移,这里只需要1个平移操作和1个旋转操作一般就可以了,而且还不需要缩放。

(1)ViewT 平移矩阵

这个矩阵和ModelT正好是相反的。我们可以这样理解,如果要在世界坐标系下的(x,y,z)位置设置相机,那么我们把相机再移回世界坐标系原点的位移就是(-x,-y,-z)。所以我们当以相机为坐标原点的时候,所有在原来坐标系下的物体都要加上这个负的平移分量。那么这个平移矩阵如下:

图4

(2)ViewR 旋转矩阵

我们将原来的坐标系转变成相机坐标系,不仅需要平移到相机位置,还要旋转到相机的朝向。如图5所示,我们要将蓝色的坐标系通过旋转变换成红色的相机坐标 系。由于坐标系的三个基向量都是单位化的,所以最简单的办法就是点乘。做法是点乘相机坐标系的三个基向量,具体看图6的公式。

图5

图6

 

其中V指向相机坐标系的y轴,U指向相机坐标系的x轴,N指向相机坐标系的z轴。

这两个矩阵就组成了视图变换矩阵,将View乘以Model得到的矩阵,在OpenGL固定管线中称为模型视图矩阵,可以通过glMatrixMode(GL_MODELVIEW)进行设置。

[转载]Android 百分比布局库(percent-support-lib) 解析与扩展 - Hongyang - 博客频道 - CSDN.NET

mikel阅读(771)

来源: [转载]Android 百分比布局库(percent-support-lib) 解析与扩展 – Hongyang – 博客频道 – CSDN.NET

转载请标明出处:
http://blog.csdn.net/lmj623565791/article/details/46695347
本文出自:【张鸿洋的博客】


一、概述

周末游戏打得过猛,于是周天熬夜码代码,周一早上浑浑噩噩的发现android-percent-support-lib-sample这个项目,Google终于开始支持百分比的方式布局了,瞬间脉动回来,啊咧咧。对于这种历史性的时刻,不出篇博客难以表达我内心的激动。

还记得不久前,发了篇博客:Android 屏幕适配方案,这篇博客以Web页面设计引出一种适配方案,最终的目的就是可以通过百分比控制控件的大小。当然了,存在一些问题,比如:

  • 对于没有考虑到屏幕尺寸,可能会出现意外的情况;
  • apk的大小会增加;

当然了Android-percent-support这个库,基本可以解决上述问题,是不是有点小激动,稍等,我们先描述下这个support-lib。

这个库提供了:

  • 两种布局供大家使用:
    PercentRelativeLayoutPercentFrameLayout,通过名字就可以看出,这是继承自FrameLayoutRelativeLayout两个容器类;
  • 支持的属性有:

layout_widthPercentlayout_heightPercent
layout_marginPercentlayout_marginLeftPercent
layout_marginTopPercentlayout_marginRightPercent
layout_marginBottomPercentlayout_marginStartPercentlayout_marginEndPercent

可以看到支持宽高,以及margin。

也就是说,大家只要在开发过程中使用PercentRelativeLayoutPercentFrameLayout替换FrameLayoutRelativeLayout即可。

是不是很简单,不过貌似没有LinearLayout,有人会说LinearLayout有weight属性呀。但是,weight属性只能支持一个方向呀~~哈,没事,刚好给我们一个机会去自定义一个PercentLinearLayout

好了,本文分为3个部分:

  • PercentRelativeLayoutPercentFrameLayout的使用
  • 对上述控件源码分析
  • 自定义PercentLinearLayout

二、使用

关于使用,其实及其简单,并且github上也有例子,android-percent-support-lib-sample。我们就简单过一下:

首先记得在build.gradle添加:

 compile 'com.android.support:percent:22.2.0'
  • 1

(一)PercentFrameLayout

<?xml version="1.0" encoding="utf-8"?>
<android.support.percent.PercentFrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_gravity="left|top"
        android:background="#44ff0000"
        android:text="width:30%,height:20%"
        app:layout_heightPercent="20%"
        android:gravity="center"
        app:layout_widthPercent="30%"/>

    <TextView
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_gravity="right|top"
        android:gravity="center"
        android:background="#4400ff00"
        android:text="width:70%,height:20%"
        app:layout_heightPercent="20%"
        app:layout_widthPercent="70%"/>


    <TextView
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_gravity="bottom"
        android:background="#770000ff"
        android:text="width:100%,height:10%"
        android:gravity="center"
        app:layout_heightPercent="10%"
        app:layout_widthPercent="100%"/>


</android.support.percent.PercentFrameLayout>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

3个TextView,很简单,直接看效果图:


(二) PercentRelativeLayout

<?xml version="1.0" encoding="utf-8"?>
<android.support.percent.PercentRelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:clickable="true">

    <TextView
        android:id="@+id/row_one_item_one"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_alignParentTop="true"
        android:background="#7700ff00"
        android:text="w:70%,h:20%"
        android:gravity="center"
        app:layout_heightPercent="20%"
        app:layout_widthPercent="70%"/>

    <TextView
        android:id="@+id/row_one_item_two"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_toRightOf="@+id/row_one_item_one"
        android:background="#396190"
        android:text="w:30%,h:20%"
        app:layout_heightPercent="20%"
        android:gravity="center"
        app:layout_widthPercent="30%"/>


    <ImageView
        android:id="@+id/row_two_item_one"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:src="@drawable/tangyan"
        android:scaleType="centerCrop"
        android:layout_below="@+id/row_one_item_one"
        android:background="#d89695"
        app:layout_heightPercent="70%"/>

    <TextView
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_below="@id/row_two_item_one"
        android:background="#770000ff"
        android:gravity="center"
        android:text="width:100%,height:10%"
        app:layout_heightPercent="10%"
        app:layout_widthPercent="100%"/>


</android.support.percent.PercentRelativeLayout>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55

ok,依然是直接看效果图:

使用没什么好说的,就是直观的看一下。


三、源码分析

其实细想一下,Google只是对我们原本熟悉的RelativeLayout和FrameLayout进行的功能的扩展,使其支持了percent相关的属性。

那么,我们考虑下,如果是我们添加这种扩展,我们会怎么做:

  • 通过LayoutParams获取child设置的percent相关属性的值
  • onMeasure的时候,将child的width,height的值,通过获取的自定义属性的值进行计算(eg:容器的宽 * fraction ),计算后传入给child.measure(w,h);

ok,有了上面的猜想,我们直接看PercentFrameLayout的源码。

public class PercentFrameLayout extends FrameLayout {
    private final PercentLayoutHelper mHelper = new PercentLayoutHelper(this);

    //省略了,两个构造方法

    public PercentFrameLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }



    @Override
    public LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new LayoutParams(getContext(), attrs);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        mHelper.adjustChildren(widthMeasureSpec, heightMeasureSpec);
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (mHelper.handleMeasuredStateTooSmall()) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        mHelper.restoreOriginalParams();
    }

    public static class LayoutParams extends FrameLayout.LayoutParams
            implements PercentLayoutHelper.PercentLayoutParams {
        private PercentLayoutHelper.PercentLayoutInfo mPercentLayoutInfo;

        public LayoutParams(Context c, AttributeSet attrs) {
            super(c, attrs);
            mPercentLayoutInfo = PercentLayoutHelper.getPercentLayoutInfo(c, attrs);
        }
        //省略了一些代码...

        @Override
        public PercentLayoutHelper.PercentLayoutInfo getPercentLayoutInfo() {
            return mPercentLayoutInfo;
        }

        @Override
        protected void setBaseAttributes(TypedArray a, int widthAttr, int heightAttr) {
            PercentLayoutHelper.fetchWidthAndHeight(this, a, widthAttr, heightAttr);
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52

代码是相当的短,可以看到PercentFrameLayout里面首先重写了generateLayoutParams方法,当然了,由于支持了一些新的layout_属性,那么肯定需要定义对应的LayoutParams。


(一)percent相关属性的获取

可以看到PercentFrameLayout.LayoutParams在原有的FrameLayout.LayoutParams基础上,实现了PercentLayoutHelper.PercentLayoutParams接口。

这个接口很简单,只有一个方法:

public interface PercentLayoutParams {
        PercentLayoutInfo getPercentLayoutInfo();
    }
  • 1
  • 2
  • 3

而,这个方法的实现呢,也只有一行:return mPercentLayoutInfo;,那么这个mPercentLayoutInfo在哪完成赋值呢?

看PercentFrameLayout.LayoutParams的构造方法:

public LayoutParams(Context c, AttributeSet attrs) {
            super(c, attrs);
            mPercentLayoutInfo = PercentLayoutHelper.getPercentLayoutInfo(c, attrs);
        }
  • 1
  • 2
  • 3
  • 4

可以看到,将attrs传入给getPercentLayoutInfo方法,那么不用说,这个方法的内部,肯定是获取自定义属性的值,然后将其封装到PercentLayoutInfo对象中,最后返回。

代码如下:

public static PercentLayoutInfo getPercentLayoutInfo(Context context,
            AttributeSet attrs) {
        PercentLayoutInfo info = null;
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.PercentLayout_Layout);
        float value = array.getFraction(R.styleable.PercentLayout_Layout_layout_widthPercent, 1, 1,
                -1f);
        if (value != -1f) {
            if (Log.isLoggable(TAG, Log.VERBOSE)) {
                Log.v(TAG, "percent width: " + value);
            }
            info = info != null ? info : new PercentLayoutInfo();
            info.widthPercent = value;
        }
        value = array.getFraction(R.styleable.PercentLayout_Layout_layout_heightPercent, 1, 1, -1f);
        if (value != -1f) {
            if (Log.isLoggable(TAG, Log.VERBOSE)) {
                Log.v(TAG, "percent height: " + value);
            }
            info = info != null ? info : new PercentLayoutInfo();
            info.heightPercent = value;
        }
        value = array.getFraction(R.styleable.PercentLayout_Layout_layout_marginPercent, 1, 1, -1f);
        if (value != -1f) {
            if (Log.isLoggable(TAG, Log.VERBOSE)) {
                Log.v(TAG, "percent margin: " + value);
            }
            info = info != null ? info : new PercentLayoutInfo();
            info.leftMarginPercent = value;
            info.topMarginPercent = value;
            info.rightMarginPercent = value;
            info.bottomMarginPercent = value;
        }
        value = array.getFraction(R.styleable.PercentLayout_Layout_layout_marginLeftPercent, 1, 1,
                -1f);
        if (value != -1f) {
            if (Log.isLoggable(TAG, Log.VERBOSE)) {
                Log.v(TAG, "percent left margin: " + value);
            }
            info = info != null ? info : new PercentLayoutInfo();
            info.leftMarginPercent = value;
        }
        value = array.getFraction(R.styleable.PercentLayout_Layout_layout_marginTopPercent, 1, 1,
                -1f);
        if (value != -1f) {
            if (Log.isLoggable(TAG, Log.VERBOSE)) {
                Log.v(TAG, "percent top margin: " + value);
            }
            info = info != null ? info : new PercentLayoutInfo();
            info.topMarginPercent = value;
        }
        value = array.getFraction(R.styleable.PercentLayout_Layout_layout_marginRightPercent, 1, 1,
                -1f);
        if (value != -1f) {
            if (Log.isLoggable(TAG, Log.VERBOSE)) {
                Log.v(TAG, "percent right margin: " + value);
            }
            info = info != null ? info : new PercentLayoutInfo();
            info.rightMarginPercent = value;
        }
        value = array.getFraction(R.styleable.PercentLayout_Layout_layout_marginBottomPercent, 1, 1,
                -1f);
        if (value != -1f) {
            if (Log.isLoggable(TAG, Log.VERBOSE)) {
                Log.v(TAG, "percent bottom margin: " + value);
            }
            info = info != null ? info : new PercentLayoutInfo();
            info.bottomMarginPercent = value;
        }
        value = array.getFraction(R.styleable.PercentLayout_Layout_layout_marginStartPercent, 1, 1,
                -1f);
        if (value != -1f) {
            if (Log.isLoggable(TAG, Log.VERBOSE)) {
                Log.v(TAG, "percent start margin: " + value);
            }
            info = info != null ? info : new PercentLayoutInfo();
            info.startMarginPercent = value;
        }
        value = array.getFraction(R.styleable.PercentLayout_Layout_layout_marginEndPercent, 1, 1,
                -1f);
        if (value != -1f) {
            if (Log.isLoggable(TAG, Log.VERBOSE)) {
                Log.v(TAG, "percent end margin: " + value);
            }
            info = info != null ? info : new PercentLayoutInfo();
            info.endMarginPercent = value;
        }
        array.recycle();
        if (Log.isLoggable(TAG, Log.DEBUG)) {
            Log.d(TAG, "constructed: " + info);
        }
        return info;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92

是不是和我们平时的取值很类似,所有的值最终封装到PercentLayoutInfo对象中。

ok,到此我们的属性获取就介绍完成,有了这些属性,是不是onMeasure里面要进行使用呢?


(二) onMeasue中重新计算child的尺寸

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        mHelper.adjustChildren(widthMeasureSpec, heightMeasureSpec);
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (mHelper.handleMeasuredStateTooSmall()) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

可以看到onMeasure中的代码页很少,看来核心的代码都被封装在mHelper的方法中,我们直接看mHelper.adjustChildren方法。

/**
     * Iterates over children and changes their width and height to one calculated from percentage
     * values.
     * @param widthMeasureSpec Width MeasureSpec of the parent ViewGroup.
     * @param heightMeasureSpec Height MeasureSpec of the parent ViewGroup.
     */
    public void adjustChildren(int widthMeasureSpec, int heightMeasureSpec) {
        //...
        int widthHint = View.MeasureSpec.getSize(widthMeasureSpec);
        int heightHint = View.MeasureSpec.getSize(heightMeasureSpec);
        for (int i = 0, N = mHost.getChildCount(); i < N; i++) {
            View view = mHost.getChildAt(i);
            ViewGroup.LayoutParams params = view.getLayoutParams();

            if (params instanceof PercentLayoutParams) {
                PercentLayoutInfo info =
                        ((PercentLayoutParams) params).getPercentLayoutInfo();
                if (Log.isLoggable(TAG, Log.DEBUG)) {
                    Log.d(TAG, "using " + info);
                }
                if (info != null) {
                    if (params instanceof ViewGroup.MarginLayoutParams) {
                        info.fillMarginLayoutParams((ViewGroup.MarginLayoutParams) params,
                                widthHint, heightHint);
                    } else {
                        info.fillLayoutParams(params, widthHint, heightHint);
                    }
                }
            }
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

通过注释也能看出,此方法中遍历所有的孩子,通过百分比的属性重新设置其宽度和高度。

首先在widthHint、heightHint保存容器的宽、高,然后遍历所有的孩子,判断其LayoutParams是否是PercentLayoutParams类型,如果是,通过params.getPercentLayoutInfo拿出info对象。

是否还记得,上面的分析中,PercentLayoutInfo保存了percent相关属性的值。

如果info不为null,则判断是否需要处理margin;我们直接看fillLayoutParams方法(处理margin也是类似的)。

 /**
         * Fills {@code ViewGroup.LayoutParams} dimensions based on percentage values.
         */
        public void fillLayoutParams(ViewGroup.LayoutParams params, int widthHint,
                int heightHint) {
            // Preserve the original layout params, so we can restore them after the measure step.
            mPreservedParams.width = params.width;
            mPreservedParams.height = params.height;

            if (widthPercent >= 0) {
                params.width = (int) (widthHint * widthPercent);
            }
            if (heightPercent >= 0) {
                params.height = (int) (heightHint * heightPercent);
            }
            if (Log.isLoggable(TAG, Log.DEBUG)) {
                Log.d(TAG, "after fillLayoutParams: (" + params.width + ", " + params.height + ")");
            }
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

首先保存原本的width和height,然后重置params的width和height为(int) (widthHint * widthPercent)(int) (heightHint * heightPercent);

到此,其实我们的百分比转换就结束了,理论上就已经实现了对于百分比的支持,不过Google还考虑了一些细节。

我们回到onMeasure方法:

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        mHelper.adjustChildren(widthMeasureSpec, heightMeasureSpec);
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (mHelper.handleMeasuredStateTooSmall()) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

下面还有个mHelper.handleMeasuredStateTooSmall的判断,也就是说,如果你设置的百分比,最终计算出来的MeasuredSize过小的话,会进行一些操作。
代码如下:

public boolean handleMeasuredStateTooSmall() {
        boolean needsSecondMeasure = false;
        for (int i = 0, N = mHost.getChildCount(); i < N; i++) {
            View view = mHost.getChildAt(i);
            ViewGroup.LayoutParams params = view.getLayoutParams();
            if (Log.isLoggable(TAG, Log.DEBUG)) {
                Log.d(TAG, "should handle measured state too small " + view + " " + params);
            }
            if (params instanceof PercentLayoutParams) {
                PercentLayoutInfo info =
                        ((PercentLayoutParams) params).getPercentLayoutInfo();
                if (info != null) {
                    if (shouldHandleMeasuredWidthTooSmall(view, info)) {
                        needsSecondMeasure = true;
                        params.width = ViewGroup.LayoutParams.WRAP_CONTENT;
                    }
                    if (shouldHandleMeasuredHeightTooSmall(view, info)) {
                        needsSecondMeasure = true;
                        params.height = ViewGroup.LayoutParams.WRAP_CONTENT;
                    }
                }
            }
        }
        if (Log.isLoggable(TAG, Log.DEBUG)) {
            Log.d(TAG, "should trigger second measure pass: " + needsSecondMeasure);
        }
        return needsSecondMeasure;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

首先遍历所有的孩子,拿出孩子的layoutparams,如果是PercentLayoutParams实例,则取出info。如果info不为null,调用shouldHandleMeasuredWidthTooSmall判断:

private static boolean shouldHandleMeasuredWidthTooSmall(View view, PercentLayoutInfo info) {
        int state = ViewCompat.getMeasuredWidthAndState(view) & ViewCompat.MEASURED_STATE_MASK;
        return state == ViewCompat.MEASURED_STATE_TOO_SMALL && info.widthPercent >= 0 &&
                info.mPreservedParams.width == ViewGroup.LayoutParams.WRAP_CONTENT;
    }
  • 1
  • 2
  • 3
  • 4
  • 5

这里就是判断,如果你设置的measuredWidth或者measureHeight过小的话,并且你在布局文件中layout_w/h 设置的是WRAP_CONTENT的话,将params.width / height= ViewGroup.LayoutParams.WRAP_CONTENT,然后重新测量。

哈,onMeasure终于结束了~~~现在我觉得应该代码结束了吧,尺寸都设置好了,还需要干嘛么,but,你会发现onLayout也重写了,我们又不改变layout规则,在onLayout里面干什么毛线:

@Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        mHelper.restoreOriginalParams();
    }
  • 1
  • 2
  • 3
  • 4
  • 5

继续看mHelper.restoreOriginalParams

 /**
     * Iterates over children and restores their original dimensions that were changed for
     * percentage values. Calling this method only makes sense if you previously called
     * {@link PercentLayoutHelper#adjustChildren(int, int)}.
     */
    public void restoreOriginalParams() {
        for (int i = 0, N = mHost.getChildCount(); i < N; i++) {
            View view = mHost.getChildAt(i);
            ViewGroup.LayoutParams params = view.getLayoutParams();
            if (Log.isLoggable(TAG, Log.DEBUG)) {
                Log.d(TAG, "should restore " + view + " " + params);
            }
            if (params instanceof PercentLayoutParams) {
                PercentLayoutInfo info =
                        ((PercentLayoutParams) params).getPercentLayoutInfo();
                if (Log.isLoggable(TAG, Log.DEBUG)) {
                    Log.d(TAG, "using " + info);
                }
                if (info != null) {
                    if (params instanceof ViewGroup.MarginLayoutParams) {
                        info.restoreMarginLayoutParams((ViewGroup.MarginLayoutParams) params);
                    } else {
                        info.restoreLayoutParams(params);
                    }
                }
            }
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

噗,原来是重新恢复原本的尺寸值,也就是说onMeasure里面的对值进行了改变,测量完成后。在这个地方,将值又恢复成如果布局文件中的值,上面写的都是0。恢复很简单:


public void restoreLayoutParams(ViewGroup.LayoutParams params) {
            params.width = mPreservedParams.width;
            params.height = mPreservedParams.height;
        }
  • 1
  • 2
  • 3
  • 4
  • 5

你应该没有忘在哪存的把~忘了的话,麻烦Ctrl+F ‘mPreservedParams.width’ 。

也就是说,你去打印上面写法,布局文件中view的v.getLayoutParams().width,这个值应该是0。

这里感觉略微不爽~这个0没撒用处呀,还不如不重置~~

好了,到此就分析完了,其实主要就几个步骤:

  • LayoutParams中属性的获取
  • onMeasure中,改变params.width为百分比计算结果,测量
  • 如果测量值过小且设置的w/h是wrap_content,重新测量
  • onLayout中,重置params.w/h为布局文件中编写的值

可以看到,有了RelativeLayout、FrameLayout的扩展,竟然没有LinearLayout几个意思。好在,我们的核心代码都由PercentLayoutHelper封装了,自己扩展下LinearLayout也不复杂。


三、实现PercentLinearlayout

可能有人会说,有了weight呀,但是weight能做到宽、高同时百分比赋值嘛?

好了,代码很简单,如下:


(一)PercentLinearLayout

package com.juliengenoud.percentsamples;

import android.content.Context;
import android.content.res.TypedArray;
import android.support.percent.PercentLayoutHelper;
import android.util.AttributeSet;
import android.view.ViewGroup;
import android.widget.LinearLayout;

/**
 * Created by zhy on 15/6/30.
 */
public class PercentLinearLayout extends LinearLayout
{

    private PercentLayoutHelper mPercentLayoutHelper;

    public PercentLinearLayout(Context context, AttributeSet attrs)
    {
        super(context, attrs);

        mPercentLayoutHelper = new PercentLayoutHelper(this);
    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        mPercentLayoutHelper.adjustChildren(widthMeasureSpec, heightMeasureSpec);
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (mPercentLayoutHelper.handleMeasuredStateTooSmall())
        {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b)
    {
        super.onLayout(changed, l, t, r, b);
        mPercentLayoutHelper.restoreOriginalParams();
    }

    @Override
    public LayoutParams generateLayoutParams(AttributeSet attrs)
    {
        return new LayoutParams(getContext(), attrs);
    }


    public static class LayoutParams extends LinearLayout.LayoutParams
            implements PercentLayoutHelper.PercentLayoutParams
    {
        private PercentLayoutHelper.PercentLayoutInfo mPercentLayoutInfo;

        public LayoutParams(Context c, AttributeSet attrs)
        {
            super(c, attrs);
            mPercentLayoutInfo = PercentLayoutHelper.getPercentLayoutInfo(c, attrs);
        }

        @Override
        public PercentLayoutHelper.PercentLayoutInfo getPercentLayoutInfo()
        {
            return mPercentLayoutInfo;
        }

        @Override
        protected void setBaseAttributes(TypedArray a, int widthAttr, int heightAttr)
        {
            PercentLayoutHelper.fetchWidthAndHeight(this, a, widthAttr, heightAttr);
        }

        public LayoutParams(int width, int height) {
            super(width, height);
        }


        public LayoutParams(ViewGroup.LayoutParams source) {
            super(source);
        }

        public LayoutParams(MarginLayoutParams source) {
            super(source);
        }

    }

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91

如果你详细看了上面的源码分析,这个代码是不是没撒解释的了~


(二)测试布局

<?xml version="1.0" encoding="utf-8"?>


<com.juliengenoud.percentsamples.PercentLinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="#ff44aacc"
        android:text="width:60%,height:5%"
        android:textColor="#ffffff"
        app:layout_heightPercent="5%"
        app:layout_marginBottomPercent="5%"
        app:layout_widthPercent="60%"/>

    <TextView
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="#ff4400cc"
        android:gravity="center"
        android:textColor="#ffffff"
        android:text="width:70%,height:10%"
        app:layout_heightPercent="10%"
        app:layout_marginBottomPercent="5%"
        app:layout_widthPercent="70%"/>
    <TextView
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="#ff44aacc"
        android:gravity="center"
        android:text="width:80%,height:15%"
        android:textColor="#ffffff"
        app:layout_heightPercent="15%"
        app:layout_marginBottomPercent="5%"
        app:layout_widthPercent="80%"/>
    <TextView
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="#ff4400cc"
        android:gravity="center"
        android:text="width:90%,height:5%"
        android:textColor="#ffffff"
        app:layout_heightPercent="20%"
        app:layout_marginBottomPercent="10%"
        app:layout_widthPercent="90%"/>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:background="#ff44aacc"
        android:gravity="center"
        android:text="width:100%,height:25%"
        android:textColor="#ffffff"
        app:layout_heightPercent="25%"
        app:layout_marginBottomPercent="5%"
        />


</com.juliengenoud.percentsamples.PercentLinearLayout>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66

我们纵向排列的几个TextView,分别设置宽/高都为百分比,且之间的间隔为5%p。


(三)效果图

ok,到此,我们使用、源码分析、扩展PercentLinearLayout就结束了。

添加PercentLinearLayout后的地址:点击查看

扩展下载:android-percent-support-extend 包含Android studio, eclipse项目,以及上述源码。

~~have a nice day ~~

android屏幕适配详解

mikel阅读(980)

官方地址:http://developer.Android.com/guide/practices/screens_support.html

 

一、关于布局适配建议

1、不要使用绝对布局
2、尽量使用match_parent 而不是fill_parent 。
3、能够使用权重的地方尽量使用权重(Android:layout_weight)
4、如果是纯色背景,尽量使用Android的shape 自定义。
5、如果需要在特定分辨率下适配,可以在res目录上新建layout-HxW.xml的文件夹。比如要适配 1080*1800的屏幕(魅族MX3采用此分辨率)则新建layout-1800×1080.xml的文件夹,然后在下面定义布局。Android系统 会优先查找分辨率相同的布局,如果不存在则换使用默认的layout下的布局。

二、术语和概念

四种屏幕尺寸分类:: small, normal, large, and xlarge
四种密度分类: ldpi (low), mdpi (medium), hdpi (high), and xhdpi (extra high)
需要注意的是: xhdpi是从 Android 2.2 (API Level 8)才开始增加的分类.
xlarge是从Android 2.3 (API Level 9)才开始增加的分类.
DPI是“dot per inch”的缩写,每英寸像素数。

一般情况下的普通屏幕:ldpi是120,mdpi是160,hdpi是240,xhdpi是320。

 

三、如何做到自适应屏幕大小呢?

1)界面布局方面

需要根据物理尺寸的大小准备5套布局,layout(放一些通用布局xml文件,比如界面中顶部和底部的布局,不会随着屏幕大小变化,类似windos窗 口的title bar),layout-small(屏幕尺寸小于3英寸左右的布局),layout-normal(屏幕尺寸小于4.5英寸左右),layout- large(4英寸-7英寸之间),layout-xlarge(7-10英寸之间)

2)图片资源方面

需要根据dpi值准备5套图片资源,drawable,drawalbe-ldpi,drawable-mdpi,drawable-hdpi,drawable-xhdpi

Android有个自动匹配机制去选择对应的布局和图片资源

 

四、两种获取屏幕分辨率信息的方法:

DisplayMetrics metrics = new DisplayMetrics();
Display display = activity.getWindowManager().getDefaultDisplay();
display.getMetrics(metrics);
//这里得到的像素值是设备独立像素dp

//DisplayMetrics metrics=activity.getResources().getDisplayMetrics(); 这样获得的参数信息不正确,不要使用这种方式。
不能使用android.content.res.Resources.getSystem().getDisplayMetrics()。这个得到的宽和高是空的。

 

五、关于图片制作

1)关于设计:
设计图先定下一个要设计的尺寸,而且尽量采用在目前最流行的屏幕尺寸(比如目前占屏幕比重比较多的是480系列,也即是480*800或者400*854,下面的图标制作也在次基础上进行比例的换算)上设计。
先了解一下屏幕的级别:
屏幕级别
屏幕密度
比率(相对)
物理大小(英寸)
像素大小
通常的分辨率
ldpi
120
3
0.75
1
120
mdpi
160
4
1
1
160
320*480
hdpi
240
6
1.5
1
240
480*800
xhdpi
320
8
2
1
320
720*1280
xxhdpi
480
12
3
1
480
1080*1800
说明:
屏幕级别:
注意屏幕级别是按照密度分级,和像素没有关系。如果非要让密度和像素扯上关系,则需要一个参照系,android使 用mdpi级别作为标准参照屏幕,也就是说在320*480分辨率的手机上一个密度可以容纳一个像素。然后其他密度级别则在此基础上进行对比。如果理想情 况下,480*800的屏幕一个密度可以容纳1.5个像素。
物理大小:
单位是英寸而不是像素,也就说一个英寸在任何分辨率下显示的大小都是一样的,但是像素在密度不同的手机里面显示的实际的大小是不一样的(这就是为什么android手机需要适配的原因)。
然后就是重点。
假设1像素在160密度下显示1英寸,则1像素在240密度基础上显示大约0.67英寸,在320密度下显示0.5英寸。于是就出现一种情况,在电脑上的一个像素,在不同的手机上看实际的大小不一样。那么怎么让“设计效果”在不同的手机上看起来显示的区域一样呢?
还是假设一个像素在160密度下的显示在一个密度内,也假设就是一英寸。那么需要几个像素才能在240密度级别下显示在一英寸范围内呢?答案是1.5个像素(根据上图的比率换算)。
了解了这个关系,接下来就是图标的制作。
2)关于切图。
关于切图有几个建议:
第一,长宽最好是3的倍数(根据android的推荐logo图标的大小是48(mdpi),72(hdpi),96(xhdpi)得出的最小公约数)。
第二,长宽最好是偶数。因为奇数在进行等比压缩的时候可能有问题。
第三,根据上面两条,如果长宽是6的倍数最理想。
第四,如果可以拉伸而不改变设计意图的情况下,比如纯色背景,则使用android的9path工具制作成.9的图片。
3)关于图标的适配。
然后接下来的一切就和设计稿没什么关系。在切好图的基础上,根据屏幕密度、像素和实际大小的比例关系。假如设计司在 480*800的分辨率下做好了设计图,并且切好图,如果你需要适配720*1280屏幕,该怎么做?根据比例,他们的关系是2:3,于是你需要按照 1.5倍比例制作图标,比如你在480*800的设计稿上切下来一个20*20像素的图,那么你就需要制作一个等比放大成30*30像素的图标,这样同一 个图标在480*800的屏幕和720*1280的屏幕上显示的实际大小才一样。同理,如果你需要适配xxhdpi则需要在20*20的基础上制作一个等 比放大成40*40像素的图标。
4)关于图标的目录,480*800切下来的图我们放在drawable-hdpi目录下,按照2:3放大的图标放在drawable-xhdpi目录下,按照2倍放大的图标放在drawable-xxhdpi目录下。
android会根据手机的密度优先查找对应的目录的资源,
比如408*800分辨率下的手机如果密度是160,则自动加载drawable-hdpi这个目录下的图标,
如果720*1280密度是240的手机自动加载drawable-xhdpi这个目录下的图标。如果没有这个文件夹,则查找和240最接近的对应密度文件夹。
5)其它
接下来要说的估计会让你失望,根据上面的步骤也不能完全解决适配的问题,只能是大概适配,而就算根据上面的步骤大概适配了,实际在手机上的效果也有出入。
比如魅族MX3的分辨率是1080*1800,标准情况下密度是480,但是他的密度大约是524,和480接近, 也就是会查找drawable-xxhdpi这个资源下的文件。也就是说你在480*800分辨率下切图然后按两倍放大的图标在这台手机上显示的效果还是 比实际的小。
而另一个要说的问题是540*960或者640*960,他们的密度很可能是或者接近240也可能是320。于是在480*800的设计稿上切下来的图并且进行的适配制作,在这些手机上显示的实际大小也可能或大或小。
综上所述,我也只是把我的理解和经验分享一下,但是并不能完美适配屏幕,仅仅当做抛砖引玉,如果您路过并且看到这份建议,如果你正好有更好的方案能够进行适配,请不吝赐教。
在代码中获取屏幕像素、屏幕密度
DisplayMetrics metric = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metric);
int width = metric.widthPixels; // 屏幕宽度(像素)
int height = metric.heightPixels; // 屏幕高度(像素)
float density = metric.density; // 屏幕密度(0.75 / 1.0 / 1.5)
int densityDpi = metric.densityDpi; // 屏幕密度DPI(120 / 160 / 240)

DPI是“dot per inch”的缩写,每英寸像素数。
一般情况下的普通屏幕:ldpi是120,mdpi是160,hdpi是240,xhdpi是320。
参考:http://developer.android.com/images/screens_support/screens-ranges.png

 

附加:配置限定符名称

配置 限定符值 说明
MCC和MNC 例如:
mcc310
mcc310-mnc004
mcc208-mnc00
MCC是移动国家代码的英文首字母缩写(The mobile country code),它的后面可选择性的跟随来自设备内的SIM卡的移动网络代码(MNC:mobile network code)。如在任何载体上,mcc310代表美国,mcc310-mnc004代表美国的Venizon公司,mcc208-mnc00代表法国的 Orange公司。
如果设备使用音频连接(GSM 电话),那么MCC和MNC的值来自SIM卡。
也可以单独使用MCC(例如,在应用程序中包含特殊国家合法的资源)。如果仅需要指定语言环境,那么可以使用language和region限定符来替代(稍后讨论)。如果决定要使用MCC和MNC限定符,就要仔细测试,使它能够满足你所期望的工作。
还可以查看配置域mcc和mnc,它们分别指示了当前的移动国家代码和移动网络代码。
mcc:http://developer.android.com/reference/android/content/res/Configuration.html#mcc
mnc:http://developer.android.com/reference/android/content/res/Configuration.html#mnc
语言和地区 例如:
en
fr
en-rUS
fr-rFR
fr-rCA
语言是用两个字母的ISO 639-1语言代码定义的,紧跟其后的是可选的两个ISO-3166-1-appha-2地区代码字母(前面是小写的“r”)。
这个编码不区分大小写,r前缀被用于区分地区部分,不能够单独指定地区。
如果用户改变了系统中的语言设置,那么在应用程序的运行期间也能够改变为对应的语言。
最小宽度 sw<N>dp
例如:
sw320dp
sw600dp
sw720dp
屏幕的基本尺寸,是指最短的可用屏幕区域。具体的说,设备的最小宽度是屏幕可用的宽度和高度中最短的那个(也可以把它看做是屏幕的最小可能的宽度)。这样就可以使用这个限定符来确保应用程序至少有<N>dp的宽度可用于UI界面,而不管屏幕的当前方向。
例 如,如果布局在任何时候都需要至少600dp的最小屏幕尺寸,那么就能够使用这个限定符,在res/layout-sw600dp/目录中创建布局资源。 系统只会在可用屏幕的尺寸至少是600dp的时候才会使用这些资源,而不管600dp是否是被用户认知的高度或宽度。最小宽度是设备的固定屏幕尺寸特征, 当屏幕的方向发生改变时,设备的最小宽度不改变。
设备的最小宽度需要考虑屏幕的装饰和系统UI的占用。例如,如果设备有一些固定的UI元素要沿着 最小宽度的轴向,占用一定的屏幕空间,那么系统声明的最小宽度要比实际的屏幕尺寸要小,因为被系统占用的像素部分对用户应用程序的UI无效。因此,这个值 应该是应用程序布局所需要的最小的实际尺寸(通常,这个值是布局支持的最小宽度,而不管屏幕的当前方向)。
以下是可以使用的通用屏幕尺寸的一些值:
1.320,针对以下屏幕配置的设备:
240x320ldpi(QVGA手持设备)
320x480mdpi(手持设备)
480x800hdpi(高分辨率手持设备)
2.480,针对480x800mdpi的屏幕(平板或手持设备)
3.600,针对600x1024mdip的屏幕(7英寸平板)
4.720,针对720x1280mdip的屏幕(10英寸平板)
当应用程序提供了多个带有不同值的最小宽度限定符资源目录时,系统会使用最接近(不超出)设备最小宽度的那个资源。
这个限定符被添加在API级别13中。
还要看android:requiresSmallestWidthDp属性,它声明了与你的应用程序兼容的最小的最小宽度,并且smallestScreenWidthDp配置字段会持有这个设备最小宽度的值。
可用宽度 w<N>dp
例如:
w720dp
w1024dp
指定最小的可用屏幕宽度,在资源中应该以dp为单位来定义<N>的值。当方向在横向和纵向之间改变时,这个配置值会跟当前的实际的宽度相匹配。
当 应用程序给这个配置提供了多个不同值的资源目录时,系统会使用最接近(不超过)设备当前屏幕宽度的那个配置。这个值需要考虑屏幕装饰占据的空间,因此,如 果设备在显示的左边或右边有一些固定的UI元素,那么使用的宽度值就要比实际的屏幕尺寸小,因为这些固定UI元素的占用,使得应用程序的可用空间减少。
这个特性被添加在API级别13中
还要看screenWidthDp配置字段,它持有当前的屏幕宽度。
可用高度 h<N>dp
例如:
h720dp
h1024dp
指定最小的可用屏幕高度,在资源中应该以dp为单位来定义<N>的值,当方向在横向和纵向直接改变时,这个配置值应该跟当前的实际高度匹配。
当 应用程序给这个配置提供了不同值的多个资源目录时,系统会使用最接近(不超过)设备当前屏幕高度的那个配置。这个要考虑屏幕装饰的占用情况,因此,如果设 备在显示的上方或底部有一些固定的UI元素,那么要使用的高度值要比实际的屏幕尺寸小,因为这些固定UI元素的占用,使得应用程序的可用空间减少。不固定 的屏幕装饰(如电话的状态栏能够在全屏时被隐藏)是不考虑的,像标题栏或操作栏这样的窗口装饰也不考虑,因此应用必须准备处理比它们指定的空间要小的情 况。
这个限定符被添加在API级别13中。
还要看screenHeightDp配置字段,它持有当前屏幕的高度。
屏幕尺寸 small
normal
large
xlarge
small:这种屏类似低分辨率的QVGA屏幕。对于小屏的最小布局尺寸大约是320x426dp。例如QVGA低分辨率和VGA高分辨率。
normal:这种屏类似中等分辨率的HVGA屏幕。对于普通屏幕的最小布局尺寸大约是320x470dp。如,WQVGA低分辨率屏、HVGA中等分辨率屏、WVGA高分辨率屏。
large:这种屏类似中等分辨率的VGA屏幕,对于大屏幕的最小布局尺寸大约是480x640dp。例如VGA和WVGA的中等分辨率屏。
xlarge:这种屏被认为比传统的中等分辨率的HVGA屏幕大。针对xlarge屏的最小布局尺寸大约是720x960dp。在大多数情况下,这种超大屏幕的设备因为太大而要放到背包中来携带,而且最有可能的是平板样式的设备。
注意:使用尺寸限定符不意味着资源仅用于这个尺寸的屏幕。如果没有用限定符提供与当前设备配置相匹配的可选资源,那么系统会使用与配置最接近的资源。
警告:如果所有使用尺寸限定符的资源都比当前屏幕大,那么系统将不会使用它们,并且应用程序会在运行时崩溃(例如,如果所有的布局都被标记了xlarge限定符,而设备却是一个普通尺寸的屏幕)。
这个限定符被添加在API级别4以后的版本中。
屏幕外观 long
notlong
long:长屏幕,如WQVGA、WVGA、FWVGA
notlong:非长屏幕,如QVGA、HVGA、VGA
这个限定符被添加在API级别4以后的版本中
这个限定符完全是基于屏幕的外观比率,不相对屏幕的方向。
还要看screenLayout配置字段,它指示了屏幕是否是长屏。
屏幕方向 port
land
port:纵向设备(垂直)
land:横向设备(水平)
如果用户旋转屏幕,这个限定能够在应用程序运行期间改变。
orientation配置字段指示当前设备的方向。
泊位模式 car
desk
car:设备停靠在汽车中
desk:设备停靠在书桌中
这个限定符被添加在API级别8以后的版本中
如果用户改变了设备的停靠地点,那么能够在应用程序的运行期间改变这个限定。可以使用UiModeManager对象来启用或禁止这种模式。
夜间模式 night
notnight
night:夜间
notnight:白天
被添加在API级别8以后的版本中
如果夜间模式被保留在自动模式中(默认),那么在应用程序运行期间,会基于白天的时间来进行模式的改变。可以使用UiModeManager对象来启用或禁止这种模式。
屏幕像素密度(dpi) ldpi
mdpi
hdpi
xhdpi
nodpi
tvdpi
ldpi:针对大约120dpi的低分辨率屏幕;
mdpi:针对大约160dpi的中等分辨率屏幕(在传统的HVGA上);
hdpi:针对大约240dpi的高分辨率屏幕;
xhdpi:针对大约320dpi的超高分辨率屏幕,被添加在API基本8以后的版本中;
nodpi:这个限定被用于不想根据匹配的设备分辨率进行缩放的位图资源。
tvdpi: 在mdpi和hdpi之间的屏幕,大约是213dpi。这种分组不是主要的分辨率,大多数是为电视来考虑的,并且大多数应用不需要它—提供mdpi和 hdpi资源就可以满足大多数应用程序需要了,并且系统会适当的缩放它们。这个限定符在API级别13以后被引入。
四种主要的分辨率之间的缩放比例是:3:4:6:8(忽略tvdpi分辨率),因此一个9×9的ldpi位图,在mdpi中是12×12、在hdpi中是18×18、在xhdpi中是24×24。
如果感觉在电视或其他某些设备上的图片资源不好看,并且想要试用tvdpi资源,那么缩放因子是1.33*mdpi。例如,一个100px x 100px的mdpi图片的图片应该被放大成133px x 133px的tvdpi图片。
注意:使用分辨率限定符不意味着资源仅适用与对应分辨率的屏幕。如果没有提供与当前设备配置匹配的可选资源,那么系统会使用最接近的资源。
触屏类型 notouch
stylus
finger
notouch:非触屏设备
stylus:有适用手写笔的电阻屏设备
finger:触屏设备
touchscreen配置字段,指示到了设备上的触屏类型。
键盘可用性 keysexposed
keyshidden
keyssoft
keysexposed:设备有可用的键盘。如果设备启用了软键盘,那么即使在硬键盘没有暴露给用户时也可以使用这个限定符。如果没有提供软键盘或者软键盘被禁用,那么只有在硬键盘被暴露给用户时才能够使用这个限定符。
keyshidden:设备有可用的硬键盘,但是被隐藏了,并且设备没有可用的软键盘。
keyssoft:设备有可用的软键盘,不管它是否可见。
如果提供了keysexposed资源,但没有keyssoft资源,那么只要系统有可用的软键盘,系统就会使用keysexposed资源而不管键盘是否可见。
如果用户打开了硬键盘,就可以在应用程序运行期间改变这个限定。
hardKeyboardHidden和keyboardHidden配置字段分别指明硬键盘的可见性以及可见的键盘类型(包括软键盘)。
主要文本输入法 nokeys
qwerty
l2key
nokeys:设备没有用于文本输入的硬键盘;
qwerty:设备有标准的硬键盘,不管用户是否可见;
12key:设备有12个键的硬键盘,不管用户是否可见。
keyboard配置字段指明可用的主要文本输入方法。
导航键的有效性 navexposed
navhidden
navexposed:导航键对用户可用;
navhidden:导航键不可用。
如果用户能够看到导航键,那么在应用程序运行时就能够改变这个限定。
navigationHidden配置字段,指示导航键是否隐藏。
主要的非触屏导航方法 nonav
dpad
trackball
wheel
nonav:除了使用触屏以外,设备没有其他导航设施。
dpad:设备有用于导航的定向板(d-pad)。
trackball:设备有用于导航的轨迹球。
wheel:设备有用于导航的定向滚轮(不常见)。
navigation配置字段指明可用的导航方法类型。
平台版本(API 级别) 例如:
v3
v4
v7
设备支持的API级别。如v1代表API级别1(带有Android1.0或更高版的设备),v4代表API级别4(带有Android1.6或更高版本的设备)
警告:Android1.5和1.6只有在限定符跟平台版本完全匹配时,才能匹配资源

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

mikel阅读(815)

转载请注明出处:http://blog.csdn.net/zhaokaiqiang1992

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

Android屏幕适配出现的原因

在我们学习如何进行屏幕适配之前,我们需要先了解下为什么Android需要进行屏幕适配。

由于Android系统的开放性,任何用户、开发者、OEM厂商、运营商都可以对Android进行定制,修改成他们想要的样子。

但是这种“碎片化”到底到达什么程度呢?

在2012年,OpenSignalMaps(以下简称OSM)发布了第一份Android碎片化报告,统计数据表明,

  • 2012年,支持Android的设备共有3997种。
  • 2013年,支持Android的设备共有11868种。
  • 2014年,支持Android的设备共有18796种。

下面这张图片所显示的内容足以充分说明当今Android系统碎片化问题的严重性,因为该图片中的每一个矩形都代表着一种Android设备。

而随着支持Android系统的设备(手机、平板、电视、手表)的增多,设备碎片化、品牌碎片化、系统碎片化、传感器碎片化和屏幕碎片化的程度也在不断地加深。而我们今天要探讨的,则是对我们开发影响比较大的——屏幕的碎片化。

下面这张图是Android屏幕尺寸的示意图,在这张图里面,蓝色矩形的大小代表不同尺寸,颜色深浅则代表所占百分比的大小。

而与之相对应的,则是下面这张图。这张图显示了IOS设备所需要进行适配的屏幕尺寸和占比。

当然,这张图片只是4,4s,5,5c,5s和平板的尺寸,现在还应该加上新推出的iphone6和plus,但是和Android的屏幕碎片化程度相比而言,还是差的太远。

详细的统计数据请到这里查看

现在你应该很清楚为什么要对Android的屏幕进行适配了吧?屏幕尺寸这么多,为了让我们开发的程序能够比较美观的显示在不同尺寸、分辨率、像素密度(这些概念我会在下面详细讲解)的设备上,那就要在开发的过程中进行处理,至于如何去进行处理,这就是我们今天的主题了。

但是在开始进入主题之前,我们再来探讨一件事情,那就是Android设备的屏幕尺寸,从几寸的智能手机,到10寸的平板电脑,再到几十寸的数字电视,我们应该适配哪些设备呢?

其实这个问题不应该这么考虑,因为对于具有相同像素密度的设备来说,像素越高,尺寸就越大,所以我们可以换个思路,将问题从单纯的尺寸大小转换到像素大小和像素密度的角度来。

下图是2014年初,友盟统计的占比5%以上的6个主流分辨率,可以看出,占比最高的是480*800,320*480的设备竟然也占据了很大比例,但是 和半年前的数据相比较,中低分辨率(320*480、480*800)的比例在减少,而中高分辨率的比例则在不断地增加。虽然每个分辨率所占的比例在变 化,但是总的趋势没变,还是这六种,只是分辨率在不断地提高。

所以说,我们只要尽量适配这几种分辨率,就可以在大部分的手机上正常运行了。

当然了,这只是手机的适配,对于平板设备(电视也可以看做是平板),我们还需要一些其他的处理。

好了,到目前为止,我们已经弄清楚了Android开发为什么要进行适配,以及我们应该适配哪些对象,接下来,终于进入我们的正题了!

首先,我们先要学习几个重要的概念。

重要概念

什么是屏幕尺寸、屏幕分辨率、屏幕像素密度?
什么是dp、dip、dpi、sp、px?他们之间的关系是什么?
什么是mdpi、hdpi、xdpi、xxdpi?如何计算和区分?

在下面的内容中我们将介绍这些概念。

屏幕尺寸

屏幕尺寸指屏幕的对角线的长度,单位是英寸,1英寸=2.54厘米

比如常见的屏幕尺寸有2.4、2.8、3.5、3.7、4.2、5.0、5.5、6.0等

屏幕分辨率

屏幕分辨率是指在横纵向上的像素点数,单位是px,1px=1个像素点。一般以纵向像素*横向像素,如1960*1080。

屏幕像素密度

屏幕像素密度是指每英寸上的像素点数,单位是dpi,即“dot per inch”的缩写。屏幕像素密度与屏幕尺寸和屏幕分辨率有关,在单一变化条件下,屏幕尺寸越小、分辨率越高,像素密度越大,反之越小。

dp、dip、dpi、sp、px

px我们应该是比较熟悉的,前面的分辨率就是用的像素为单位,大多数情况下,比如UI设计、Android原生API都会以px作为统一的计量单位,像是获取屏幕宽高等。

dip和dp是一个意思,都是Density Independent Pixels的缩写,即密度无关像素,上面我们说过,dpi是屏幕像素密度,假如一英寸里面有160个像素,这个屏幕的像素密度就是160dpi,那么在 这种情况下,dp和px如何换算呢?在Android中,规定以160dpi为基准,1dip=1px,如果密度是320dpi,则1dip=2px,以 此类推。

假如同样都是画一条320px的线,在480*800分辨率手机上显示为2/3屏幕宽度,在320*480的手机上则占满了全屏,如果使用dp为单位,在 这两种分辨率下,160dp都显示为屏幕一般的长度。这也是为什么在Android开发中,写布局的时候要尽量使用dp而不是px的原因。

而sp,即scale-independent pixels,与dp类似,但是可以根据文字大小首选项进行放缩,是设置字体大小的御用单位。

mdpi、hdpi、xdpi、xxdpi

其实之前还有个ldpi,但是随着移动设备配置的不断升级,这个像素密度的设备已经很罕见了,所在现在适配时不需考虑。

mdpi、hdpi、xdpi、xxdpi用来修饰Android中的drawable文件夹及values文件夹,用来区分不同像素密度下的图片和dimen值。

那么如何区分呢?Google官方指定按照下列标准进行区分:

名称 像素密度范围
mdpi 120dpi~160dpi
hdpi 160dpi~240dpi
xhdpi 240dpi~320dpi
xxhdpi 320dpi~480dpi
xxxhdpi 480dpi~640dpi

在进行开发的时候,我们需要把合适大小的图片放在合适的文件夹里面。下面以图标设计为例进行介绍。

在设计图标时,对于五种主流的像素密度(MDPI、HDPI、XHDPI、XXHDPI 和 XXXHDPI)应按照 2:3:4:6:8 的比例进行缩放。例如,一个启动图标的尺寸为48×48 dp,这表示在 MDPI 的屏幕上其实际尺寸应为 48×48 px,在 HDPI 的屏幕上其实际大小是 MDPI 的 1.5 倍 (72×72 px),在 XDPI 的屏幕上其实际大小是 MDPI 的 2 倍 (96×96 px),依此类推。

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

下图为图标的各个屏幕密度的对应尺寸

屏幕密度 图标尺寸
mdpi 48x48px
hdpi 72x72px
xhdpi 96x96px
xxhdpi 144x144px
xxxhdpi 192x192px

解决方案

支持各种屏幕尺寸

使用wrap_content、match_parent、weight

要确保布局的灵活性并适应各种尺寸的屏幕,应使用 “wrap_content” 和 “match_parent” 控制某些视图组件的宽度和高度。

使用 “wrap_content”,系统就会将视图的宽度或高度设置成所需的最小尺寸以适应视图中的内容,而 “match_parent”(在低于 API 级别 8 的级别中称为 “fill_parent”)则会展开组件以匹配其父视图的尺寸。

如果使用 “wrap_content” 和 “match_parent” 尺寸值而不是硬编码的尺寸,视图就会相应地仅使用自身所需的空间或展开以填满可用空间。此方法可让布局正确适应各种屏幕尺寸和屏幕方向。

下面是一段示例代码

<code
 class="hljs xml has-numbering" style="display: block; padding: 0px; 
background-color: transparent; color: inherit; box-sizing: border-box; 
font-family: 'Source Code Pro', monospace;font-size:undefined; 
white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 
0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; 
word-wrap: normal; background-position: initial initial; 
background-repeat: initial initial;"><span class="hljs-tag" 
style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span
 class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 
136);">LinearLayout</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">xmlns:android</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"http://schemas.android.com/apk/res/android"</span>
    <span class="hljs-attribute" style="box-sizing: border-box; 
color: rgb(102, 0, 102);">android:orientation</span>=<span 
class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"vertical"</span>
    <span class="hljs-attribute" style="box-sizing: border-box; 
color: rgb(102, 0, 102);">android:layout_width</span>=<span 
class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"match_parent"</span>
    <span class="hljs-attribute" style="box-sizing: border-box; 
color: rgb(102, 0, 102);">android:layout_height</span>=<span
 class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"match_parent"</span>></span>
    <span class="hljs-tag" style="color: rgb(0, 102, 102); 
box-sizing: border-box;"><<span class="hljs-title" 
style="box-sizing: border-box; color: rgb(0, 0, 
136);">LinearLayout</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">android:layout_width</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"match_parent"</span>
                  <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:id</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"@+id/linearLayout1"</span>  
                  <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:gravity</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"center"</span>
                  <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_height</span>=<span class="hljs-value"
 style="box-sizing: border-box; color: rgb(0, 136, 
0);">"50dp"</span>></span>
        <span class="hljs-tag" style="color: rgb(0, 102, 102); 
box-sizing: border-box;"><<span class="hljs-title" 
style="box-sizing: border-box; color: rgb(0, 0, 
136);">ImageView</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">android:id</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"@+id/imageView1"</span>
                   <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_height</span>=<span class="hljs-value"
 style="box-sizing: border-box; color: rgb(0, 136, 
0);">"wrap_content"</span>
                   <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_width</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"wrap_content"</span>
                   <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:src</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"@drawable/logo"</span>
                   <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:paddingRight</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"30dp"</span>
                   <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_gravity</span>=<span 
class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"left"</span>
                   <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_weight</span>=<span class="hljs-value"
 style="box-sizing: border-box; color: rgb(0, 136, 
0);">"0"</span> /></span>
        <span class="hljs-tag" style="color: rgb(0, 102, 102); 
box-sizing: border-box;"><<span class="hljs-title" 
style="box-sizing: border-box; color: rgb(0, 0, 
136);">View</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">android:layout_height</span>=<span class="hljs-value"
 style="box-sizing: border-box; color: rgb(0, 136, 
0);">"wrap_content"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:id</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"@+id/view1"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_width</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"wrap_content"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_weight</span>=<span class="hljs-value"
 style="box-sizing: border-box; color: rgb(0, 136, 
0);">"1"</span> /></span>
        <span class="hljs-tag" style="color: rgb(0, 102, 102); 
box-sizing: border-box;"><<span class="hljs-title" 
style="box-sizing: border-box; color: rgb(0, 0, 
136);">Button</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">android:id</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"@+id/categorybutton"</span>
                <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:background</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"@drawable/button_bg"</span>
                <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_height</span>=<span class="hljs-value"
 style="box-sizing: border-box; color: rgb(0, 136, 
0);">"match_parent"</span>
                <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_weight</span>=<span class="hljs-value"
 style="box-sizing: border-box; color: rgb(0, 136, 
0);">"0"</span>
                <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_width</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"120dp"</span>
                <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 102);">style</span>=<span 
class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"@style/CategoryButtonStyle"</span>/></span>
    <span class="hljs-tag" style="color: rgb(0, 102, 102); 
box-sizing: border-box;"></<span class="hljs-title" 
style="box-sizing: border-box; color: rgb(0, 0, 
136);">LinearLayout</span>></span>

    <span class="hljs-tag" style="color: rgb(0, 102, 102); 
box-sizing: border-box;"><<span class="hljs-title" 
style="box-sizing: border-box; color: rgb(0, 0, 
136);">fragment</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">android:id</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"@+id/headlines"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_height</span>=<span class="hljs-value"
 style="box-sizing: border-box; color: rgb(0, 136, 
0);">"fill_parent"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"com.example.android.newsreader.HeadlinesFragment"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_width</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"match_parent"</span> /></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">LinearLayout</span>></span></code><ul 
class="pre-numbering" style="box-sizing: border-box; position: absolute;
 width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px;
 margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; 
border-right-style: solid; border-right-color: rgb(221, 221, 221); 
list-style: none; text-align: right;"><li style="box-sizing: 
border-box; padding: 0px 5px;">1</li><li style="box-sizing: 
border-box; padding: 0px 5px;">2</li><li style="box-sizing: 
border-box; padding: 0px 5px;">3</li><li style="box-sizing: 
border-box; padding: 0px 5px;">4</li><li style="box-sizing: 
border-box; padding: 0px 5px;">5</li><li style="box-sizing: 
border-box; padding: 0px 5px;">6</li><li style="box-sizing: 
border-box; padding: 0px 5px;">7</li><li style="box-sizing: 
border-box; padding: 0px 5px;">8</li><li style="box-sizing: 
border-box; padding: 0px 5px;">9</li><li style="box-sizing: 
border-box; padding: 0px 5px;">10</li><li style="box-sizing:
 border-box; padding: 0px 5px;">11</li><li 
style="box-sizing: border-box; padding: 0px 5px;">12</li><li
 style="box-sizing: border-box; padding: 0px 
5px;">13</li><li style="box-sizing: border-box; padding: 0px
 5px;">14</li><li style="box-sizing: border-box; padding: 
0px 5px;">15</li><li style="box-sizing: border-box; padding:
 0px 5px;">16</li><li style="box-sizing: border-box; 
padding: 0px 5px;">17</li><li style="box-sizing: border-box;
 padding: 0px 5px;">18</li><li style="box-sizing: 
border-box; padding: 0px 5px;">19</li><li style="box-sizing:
 border-box; padding: 0px 5px;">20</li><li 
style="box-sizing: border-box; padding: 0px 5px;">21</li><li
 style="box-sizing: border-box; padding: 0px 
5px;">22</li><li style="box-sizing: border-box; padding: 0px
 5px;">23</li><li style="box-sizing: border-box; padding: 
0px 5px;">24</li><li style="box-sizing: border-box; padding:
 0px 5px;">25</li><li style="box-sizing: border-box; 
padding: 0px 5px;">26</li><li style="box-sizing: border-box;
 padding: 0px 5px;">27</li><li style="box-sizing: 
border-box; padding: 0px 5px;">28</li><li style="box-sizing:
 border-box; padding: 0px 5px;">29</li><li 
style="box-sizing: border-box; padding: 0px 5px;">30</li><li
 style="box-sizing: border-box; padding: 0px 
5px;">31</li><li style="box-sizing: border-box; padding: 0px
 5px;">32</li></ul>

下图是在横纵屏切换的时候的显示效果,我们可以看到这样可以很好的适配屏幕尺寸的变化。

weight是线性布局的一个独特的属性,我们可以使用这个属性来按照比例对界面进行分配,完成一些特殊的需求。

但是,我们对于这个属性的计算应该如何理解呢?

首先看下面的例子,我们在布局中这样设置我们的界面

我们在布局里面设置为线性布局,横向排列,然后放置两个宽度为0dp的按钮,分别设置weight为1和2,在效果图中,我们可以看到两个按钮按照1:2 的宽度比例正常排列了,这也是我们经常使用到的场景,这是时候很好理解,Button1的宽度就是1/(1+2) = 1/3,Button2的宽度则是2/(1+2) = 2/3,我们可以很清楚的明白这种情景下的占比如何计算。

但是假如我们的宽度不是0dp(wrap_content和0dp的效果相同),则是match_parent呢?

下面是设置为match_parent的效果

我们可以看到,在这种情况下,占比和上面正好相反,这是怎么回事呢?说到这里,我们就不得不提一下weight的计算方法了。

android:layout_weight的真实含义是:如果View设置了该属性并且有效,那么该 View的宽度等于原有宽度(android:layout_width)加上剩余空间的占比。

从这个角度我们来解释一下上面的现象。在上面的代码中,我们设置每个Button的宽度都是match_parent,假设屏幕宽度为L,那么每个Button的宽度也应该都为L,剩余宽度就等于L-(L+L)= -L。

Button1的weight=1,剩余宽度占比为1/(1+2)= 1/3,所以最终宽度为L+1/3*(-L)=2/3L,Button2的计算类似,最终宽度为L+2/3(-L)=1/3L。

这是在水平方向上的,那么在垂直方向上也是这样吗?

下面是测试代码和效果

如果是垂直方向,那么我们应该改变的是layout_height的属性,下面是0dp的显示效果

下面是match_parent的显示效果,结论和水平是完全一样的

虽然说我们演示了match_parent的显示效果,并说明了原因,但是在真正用的时候,我们都是设置某一个属性为0dp,然后按照权重计算所占百分比。

使用相对布局,禁用绝对布局

在开发中,我们大部分时候使用的都是线性布局、相对布局和帧布局,绝对布局由于适配性极差,所以极少使用。

由于各种布局的特点不一样,所以不能说哪个布局好用,到底应该使用什么布局只能根据实际需求来确定。我们可以使用 LinearLayout 的嵌套实例并结合 “wrap_content” 和 “match_parent”,以便构建相当复杂的布局。不过,我们无法通过 LinearLayout 精确控制子视图的特殊关系;系统会将 LinearLayout 中的视图直接并排列出。

如果我们需要将子视图排列出各种效果而不是一条直线,通常更合适的解决方法是使用 RelativeLayout,这样就可以根据各组件之间的特殊关系指定布局了。例如,我们可以将某个子视图对齐到屏幕左侧,同时将另一个视图对齐到屏幕右侧。

下面的代码以官方Demo为例说明。

<code
 class="hljs xml has-numbering" style="display: block; padding: 0px; 
background-color: transparent; color: inherit; box-sizing: border-box; 
font-family: 'Source Code Pro', monospace;font-size:undefined; 
white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 
0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; 
word-wrap: normal; background-position: initial initial; 
background-repeat: initial initial;"><span class="hljs-pi" 
style="color: rgb(0, 102, 102); box-sizing: border-box;"><?xml 
version="1.0" encoding="utf-8"?></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">RelativeLayout</span> 
<span class="hljs-attribute" style="box-sizing: border-box; color: 
rgb(102, 0, 102);">xmlns:android</span>=<span 
class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"http://schemas.android.com/apk/res/android"</span>
    <span class="hljs-attribute" style="box-sizing: border-box; 
color: rgb(102, 0, 102);">android:layout_width</span>=<span 
class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"match_parent"</span>
    <span class="hljs-attribute" style="box-sizing: border-box; 
color: rgb(102, 0, 102);">android:layout_height</span>=<span
 class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"match_parent"</span>></span>
    <span class="hljs-tag" style="color: rgb(0, 102, 102); 
box-sizing: border-box;"><<span class="hljs-title" 
style="box-sizing: border-box; color: rgb(0, 0, 136);">TextView
</span>        <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:id</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"@+id/label"</span>
        <span class="hljs-attribute" style="box-sizing: border-box; 
color: rgb(102, 0, 102);">android:layout_width</span>=<span 
class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"match_parent"</span>
        <span class="hljs-attribute" style="box-sizing: border-box; 
color: rgb(102, 0, 102);">android:layout_height</span>=<span
 class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"wrap_content"</span>
        <span class="hljs-attribute" style="box-sizing: border-box; 
color: rgb(102, 0, 102);">android:text</span>=<span 
class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"Type here:"</span>/></span>
    <span class="hljs-tag" style="color: rgb(0, 102, 102); 
box-sizing: border-box;"><<span class="hljs-title" 
style="box-sizing: border-box; color: rgb(0, 0, 136);">EditText
</span>        <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:id</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"@+id/entry"</span>
        <span class="hljs-attribute" style="box-sizing: border-box; 
color: rgb(102, 0, 102);">android:layout_width</span>=<span 
class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"match_parent"</span>
        <span class="hljs-attribute" style="box-sizing: border-box; 
color: rgb(102, 0, 102);">android:layout_height</span>=<span
 class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"wrap_content"</span>
        <span class="hljs-attribute" style="box-sizing: border-box; 
color: rgb(102, 0, 102);">android:layout_below</span>=<span 
class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"@id/label"</span>/></span>
    <span class="hljs-tag" style="color: rgb(0, 102, 102); 
box-sizing: border-box;"><<span class="hljs-title" 
style="box-sizing: border-box; color: rgb(0, 0, 136);">Button
</span>        <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:id</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"@+id/ok"</span>
        <span class="hljs-attribute" style="box-sizing: border-box; 
color: rgb(102, 0, 102);">android:layout_width</span>=<span 
class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"wrap_content"</span>
        <span class="hljs-attribute" style="box-sizing: border-box; 
color: rgb(102, 0, 102);">android:layout_height</span>=<span
 class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"wrap_content"</span>
        <span class="hljs-attribute" style="box-sizing: border-box; 
color: rgb(102, 0, 102);">android:layout_below</span>=<span 
class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"@id/entry"</span>
        <span class="hljs-attribute" style="box-sizing: border-box; 
color: rgb(102, 0, 
102);">android:layout_alignParentRight</span>=<span 
class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"true"</span>
        <span class="hljs-attribute" style="box-sizing: border-box; 
color: rgb(102, 0, 
102);">android:layout_marginLeft</span>=<span 
class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"10dp"</span>
        <span class="hljs-attribute" style="box-sizing: border-box; 
color: rgb(102, 0, 102);">android:text</span>=<span 
class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"OK"</span> /></span>
    <span class="hljs-tag" style="color: rgb(0, 102, 102); 
box-sizing: border-box;"><<span class="hljs-title" 
style="box-sizing: border-box; color: rgb(0, 0, 136);">Button
</span>        <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_width</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"wrap_content"</span>
        <span class="hljs-attribute" style="box-sizing: border-box; 
color: rgb(102, 0, 102);">android:layout_height</span>=<span
 class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"wrap_content"</span>
        <span class="hljs-attribute" style="box-sizing: border-box; 
color: rgb(102, 0, 
102);">android:layout_toLeftOf</span>=<span 
class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"@id/ok"</span>
        <span class="hljs-attribute" style="box-sizing: border-box; 
color: rgb(102, 0, 
102);">android:layout_alignTop</span>=<span 
class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"@id/ok"</span>
        <span class="hljs-attribute" style="box-sizing: border-box; 
color: rgb(102, 0, 102);">android:text</span>=<span 
class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"Cancel"</span> /></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">RelativeLayout</span>></span></code><ul
 class="pre-numbering" style="box-sizing: border-box; position: 
absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; 
left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; 
border-right-style: solid; border-right-color: rgb(221, 221, 221); 
list-style: none; text-align: right;"><li style="box-sizing: 
border-box; padding: 0px 5px;">1</li><li style="box-sizing: 
border-box; padding: 0px 5px;">2</li><li style="box-sizing: 
border-box; padding: 0px 5px;">3</li><li style="box-sizing: 
border-box; padding: 0px 5px;">4</li><li style="box-sizing: 
border-box; padding: 0px 5px;">5</li><li style="box-sizing: 
border-box; padding: 0px 5px;">6</li><li style="box-sizing: 
border-box; padding: 0px 5px;">7</li><li style="box-sizing: 
border-box; padding: 0px 5px;">8</li><li style="box-sizing: 
border-box; padding: 0px 5px;">9</li><li style="box-sizing: 
border-box; padding: 0px 5px;">10</li><li style="box-sizing:
 border-box; padding: 0px 5px;">11</li><li 
style="box-sizing: border-box; padding: 0px 5px;">12</li><li
 style="box-sizing: border-box; padding: 0px 
5px;">13</li><li style="box-sizing: border-box; padding: 0px
 5px;">14</li><li style="box-sizing: border-box; padding: 
0px 5px;">15</li><li style="box-sizing: border-box; padding:
 0px 5px;">16</li><li style="box-sizing: border-box; 
padding: 0px 5px;">17</li><li style="box-sizing: border-box;
 padding: 0px 5px;">18</li><li style="box-sizing: 
border-box; padding: 0px 5px;">19</li><li style="box-sizing:
 border-box; padding: 0px 5px;">20</li><li 
style="box-sizing: border-box; padding: 0px 5px;">21</li><li
 style="box-sizing: border-box; padding: 0px 
5px;">22</li><li style="box-sizing: border-box; padding: 0px
 5px;">23</li><li style="box-sizing: border-box; padding: 
0px 5px;">24</li><li style="box-sizing: border-box; padding:
 0px 5px;">25</li><li style="box-sizing: border-box; 
padding: 0px 5px;">26</li><li style="box-sizing: border-box;
 padding: 0px 5px;">27</li><li style="box-sizing: 
border-box; padding: 0px 5px;">28</li><li style="box-sizing:
 border-box; padding: 0px 5px;">29</li></ul>

在上面的代码中我们使用了相对布局,并且使用alignXXX等属性指定了子控件的位置,下面是这种布局方式在应对屏幕变化时的表现

在小尺寸屏幕的显示

在平板的大尺寸上的显示效果

虽然控件的大小由于屏幕尺寸的增加而发生了改变,但是我们可以看到,由于使用了相对布局,所以控件之前的位置关系并没有发生什么变化,这说明我们的适配成功了。

使用限定符

使用尺寸限定符

上面所提到的灵活布局或者是相对布局,可以为我们带来的优势就只有这么多了。虽然这些布局可以拉伸组件内外的空间以适应各种屏幕,但它们不一定能为每种屏幕都提供最佳的用户体验。因此,我们的应用不仅仅只实施灵活布局,还应该应针对各种屏幕配置提供一些备用布局。

如何做到这一点呢?我们可以通过使用配置限定符,在运行时根据当前的设备配置自动选择合适的资源了,例如根据各种屏幕尺寸选择不同的布局。

很多应用会在较大的屏幕上实施“双面板”模式,即在一个面板上显示项目列表,而在另一面板上显示对应内容。平板电脑和电视的屏幕已经大到可以同时容纳这两个面板了,但手机屏幕就需要分别显示。因此,我们可以使用以下文件以便实施这些布局:

res/layout/main.xml,单面板(默认)布局:

<code
 class="hljs xml has-numbering" style="display: block; padding: 0px; 
background-color: transparent; color: inherit; box-sizing: border-box; 
font-family: 'Source Code Pro', monospace;font-size:undefined; 
white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 
0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; 
word-wrap: normal; background-position: initial initial; 
background-repeat: initial initial;"><span class="hljs-tag" 
style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span
 class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 
136);">LinearLayout</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">xmlns:android</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"http://schemas.android.com/apk/res/android"</span>
    <span class="hljs-attribute" style="box-sizing: border-box; 
color: rgb(102, 0, 102);">android:orientation</span>=<span 
class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"vertical"</span>
    <span class="hljs-attribute" style="box-sizing: border-box; 
color: rgb(102, 0, 102);">android:layout_width</span>=<span 
class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"match_parent"</span>
    <span class="hljs-attribute" style="box-sizing: border-box; 
color: rgb(102, 0, 102);">android:layout_height</span>=<span
 class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"match_parent"</span>></span>

    <span class="hljs-tag" style="color: rgb(0, 102, 102); 
box-sizing: border-box;"><<span class="hljs-title" 
style="box-sizing: border-box; color: rgb(0, 0, 
136);">fragment</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">android:id</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"@+id/headlines"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_height</span>=<span class="hljs-value"
 style="box-sizing: border-box; color: rgb(0, 136, 
0);">"fill_parent"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"com.example.android.newsreader.HeadlinesFragment"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_width</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"match_parent"</span> /></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">LinearLayout</span>></span></code><ul 
class="pre-numbering" style="box-sizing: border-box; position: absolute;
 width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px;
 margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; 
border-right-style: solid; border-right-color: rgb(221, 221, 221); 
list-style: none; text-align: right;"><li style="box-sizing: 
border-box; padding: 0px 5px;">1</li><li style="box-sizing: 
border-box; padding: 0px 5px;">2</li><li style="box-sizing: 
border-box; padding: 0px 5px;">3</li><li style="box-sizing: 
border-box; padding: 0px 5px;">4</li><li style="box-sizing: 
border-box; padding: 0px 5px;">5</li><li style="box-sizing: 
border-box; padding: 0px 5px;">6</li><li style="box-sizing: 
border-box; padding: 0px 5px;">7</li><li style="box-sizing: 
border-box; padding: 0px 5px;">8</li><li style="box-sizing: 
border-box; padding: 0px 5px;">9</li><li style="box-sizing: 
border-box; padding: 0px 5px;">10</li></ul>

res/layout-large/main.xml,双面板布局:

<code
 class="hljs xml has-numbering" style="display: block; padding: 0px; 
background-color: transparent; color: inherit; box-sizing: border-box; 
font-family: 'Source Code Pro', monospace;font-size:undefined; 
white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 
0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; 
word-wrap: normal; background-position: initial initial; 
background-repeat: initial initial;"><span class="hljs-tag" 
style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span
 class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 
136);">LinearLayout</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">xmlns:android</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"http://schemas.android.com/apk/res/android"</span>
    <span class="hljs-attribute" style="box-sizing: border-box; 
color: rgb(102, 0, 102);">android:layout_width</span>=<span 
class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"fill_parent"</span>
    <span class="hljs-attribute" style="box-sizing: border-box; 
color: rgb(102, 0, 102);">android:layout_height</span>=<span
 class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"fill_parent"</span>
    <span class="hljs-attribute" style="box-sizing: border-box; 
color: rgb(102, 0, 102);">android:orientation</span>=<span 
class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"horizontal"</span>></span>
    <span class="hljs-tag" style="color: rgb(0, 102, 102); 
box-sizing: border-box;"><<span class="hljs-title" 
style="box-sizing: border-box; color: rgb(0, 0, 
136);">fragment</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">android:id</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"@+id/headlines"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_height</span>=<span class="hljs-value"
 style="box-sizing: border-box; color: rgb(0, 136, 
0);">"fill_parent"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"com.example.android.newsreader.HeadlinesFragment"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_width</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"400dp"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_marginRight</span>=<span 
class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"10dp"</span>/></span>
    <span class="hljs-tag" style="color: rgb(0, 102, 102); 
box-sizing: border-box;"><<span class="hljs-title" 
style="box-sizing: border-box; color: rgb(0, 0, 
136);">fragment</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">android:id</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"@+id/article"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_height</span>=<span class="hljs-value"
 style="box-sizing: border-box; color: rgb(0, 136, 
0);">"fill_parent"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"com.example.android.newsreader.ArticleFragment"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_width</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"fill_parent"</span> /></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">LinearLayout</span>></span></code><ul 
class="pre-numbering" style="box-sizing: border-box; position: absolute;
 width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px;
 margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; 
border-right-style: solid; border-right-color: rgb(221, 221, 221); 
list-style: none; text-align: right;"><li style="box-sizing: 
border-box; padding: 0px 5px;">1</li><li style="box-sizing: 
border-box; padding: 0px 5px;">2</li><li style="box-sizing: 
border-box; padding: 0px 5px;">3</li><li style="box-sizing: 
border-box; padding: 0px 5px;">4</li><li style="box-sizing: 
border-box; padding: 0px 5px;">5</li><li style="box-sizing: 
border-box; padding: 0px 5px;">6</li><li style="box-sizing: 
border-box; padding: 0px 5px;">7</li><li style="box-sizing: 
border-box; padding: 0px 5px;">8</li><li style="box-sizing: 
border-box; padding: 0px 5px;">9</li><li style="box-sizing: 
border-box; padding: 0px 5px;">10</li><li style="box-sizing:
 border-box; padding: 0px 5px;">11</li><li 
style="box-sizing: border-box; padding: 0px 5px;">12</li><li
 style="box-sizing: border-box; padding: 0px 
5px;">13</li><li style="box-sizing: border-box; padding: 0px
 5px;">14</li></ul>

请注意第二种布局名称目录中的 large 限定符。系统会在属于较大屏幕(例如 7 英寸或更大的平板电脑)的设备上选择此布局。系统会在较小的屏幕上选择其他布局(无限定符)。

使用最小宽度限定符

在版本低于 3.2 的 Android 设备上,开发人员遇到的问题之一是“较大”屏幕的尺寸范围,该问题会影响戴尔 Streak、早期的 Galaxy Tab 以及大部分 7 英寸平板电脑。即使这些设备的屏幕属于“较大”的尺寸,但很多应用可能会针对此类别中的各种设备(例如 5 英寸和 7 英寸的设备)显示不同的布局。这就是 Android 3.2 版在引入其他限定符的同时引入“最小宽度”限定符的原因。

最小宽度限定符可让您通过指定某个最小宽度(以 dp 为单位)来定位屏幕。例如,标准 7 英寸平板电脑的最小宽度为 600 dp,因此如果您要在此类屏幕上的用户界面中使用双面板(但在较小的屏幕上只显示列表),您可以使用上文中所述的单面板和双面板这两种布局,但您应使用 sw600dp 指明双面板布局仅适用于最小宽度为 600 dp 的屏幕,而不是使用 large 尺寸限定符。

res/layout/main.xml,单面板(默认)布局:

<code
 class="hljs xml has-numbering" style="display: block; padding: 0px; 
background-color: transparent; color: inherit; box-sizing: border-box; 
font-family: 'Source Code Pro', monospace;font-size:undefined; 
white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 
0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; 
word-wrap: normal; background-position: initial initial; 
background-repeat: initial initial;"><span class="hljs-tag" 
style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span
 class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 
136);">LinearLayout</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">xmlns:android</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"http://schemas.android.com/apk/res/android"</span>
    <span class="hljs-attribute" style="box-sizing: border-box; 
color: rgb(102, 0, 102);">android:orientation</span>=<span 
class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"vertical"</span>
    <span class="hljs-attribute" style="box-sizing: border-box; 
color: rgb(102, 0, 102);">android:layout_width</span>=<span 
class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"match_parent"</span>
    <span class="hljs-attribute" style="box-sizing: border-box; 
color: rgb(102, 0, 102);">android:layout_height</span>=<span
 class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"match_parent"</span>></span>

    <span class="hljs-tag" style="color: rgb(0, 102, 102); 
box-sizing: border-box;"><<span class="hljs-title" 
style="box-sizing: border-box; color: rgb(0, 0, 
136);">fragment</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">android:id</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"@+id/headlines"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_height</span>=<span class="hljs-value"
 style="box-sizing: border-box; color: rgb(0, 136, 
0);">"fill_parent"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"com.example.android.newsreader.HeadlinesFragment"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_width</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"match_parent"</span> /></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">LinearLayout</span>></span></code><ul 
class="pre-numbering" style="box-sizing: border-box; position: absolute;
 width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px;
 margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; 
border-right-style: solid; border-right-color: rgb(221, 221, 221); 
list-style: none; text-align: right;"><li style="box-sizing: 
border-box; padding: 0px 5px;">1</li><li style="box-sizing: 
border-box; padding: 0px 5px;">2</li><li style="box-sizing: 
border-box; padding: 0px 5px;">3</li><li style="box-sizing: 
border-box; padding: 0px 5px;">4</li><li style="box-sizing: 
border-box; padding: 0px 5px;">5</li><li style="box-sizing: 
border-box; padding: 0px 5px;">6</li><li style="box-sizing: 
border-box; padding: 0px 5px;">7</li><li style="box-sizing: 
border-box; padding: 0px 5px;">8</li><li style="box-sizing: 
border-box; padding: 0px 5px;">9</li><li style="box-sizing: 
border-box; padding: 0px 5px;">10</li></ul>

res/layout-sw600dp/main.xml,双面板布局:

<code
 class="hljs xml has-numbering" style="display: block; padding: 0px; 
background-color: transparent; color: inherit; box-sizing: border-box; 
font-family: 'Source Code Pro', monospace;font-size:undefined; 
white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 
0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; 
word-wrap: normal; background-position: initial initial; 
background-repeat: initial initial;"><span class="hljs-tag" 
style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span
 class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 
136);">LinearLayout</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">xmlns:android</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"http://schemas.android.com/apk/res/android"</span>
    <span class="hljs-attribute" style="box-sizing: border-box; 
color: rgb(102, 0, 102);">android:layout_width</span>=<span 
class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"fill_parent"</span>
    <span class="hljs-attribute" style="box-sizing: border-box; 
color: rgb(102, 0, 102);">android:layout_height</span>=<span
 class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"fill_parent"</span>
    <span class="hljs-attribute" style="box-sizing: border-box; 
color: rgb(102, 0, 102);">android:orientation</span>=<span 
class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"horizontal"</span>></span>
    <span class="hljs-tag" style="color: rgb(0, 102, 102); 
box-sizing: border-box;"><<span class="hljs-title" 
style="box-sizing: border-box; color: rgb(0, 0, 
136);">fragment</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">android:id</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"@+id/headlines"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_height</span>=<span class="hljs-value"
 style="box-sizing: border-box; color: rgb(0, 136, 
0);">"fill_parent"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"com.example.android.newsreader.HeadlinesFragment"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_width</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"400dp"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_marginRight</span>=<span 
class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"10dp"</span>/></span>
    <span class="hljs-tag" style="color: rgb(0, 102, 102); 
box-sizing: border-box;"><<span class="hljs-title" 
style="box-sizing: border-box; color: rgb(0, 0, 
136);">fragment</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">android:id</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"@+id/article"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_height</span>=<span class="hljs-value"
 style="box-sizing: border-box; color: rgb(0, 136, 
0);">"fill_parent"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"com.example.android.newsreader.ArticleFragment"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_width</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"fill_parent"</span> /></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">LinearLayout</span>></span></code><ul 
class="pre-numbering" style="box-sizing: border-box; position: absolute;
 width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px;
 margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; 
border-right-style: solid; border-right-color: rgb(221, 221, 221); 
list-style: none; text-align: right;"><li style="box-sizing: 
border-box; padding: 0px 5px;">1</li><li style="box-sizing: 
border-box; padding: 0px 5px;">2</li><li style="box-sizing: 
border-box; padding: 0px 5px;">3</li><li style="box-sizing: 
border-box; padding: 0px 5px;">4</li><li style="box-sizing: 
border-box; padding: 0px 5px;">5</li><li style="box-sizing: 
border-box; padding: 0px 5px;">6</li><li style="box-sizing: 
border-box; padding: 0px 5px;">7</li><li style="box-sizing: 
border-box; padding: 0px 5px;">8</li><li style="box-sizing: 
border-box; padding: 0px 5px;">9</li><li style="box-sizing: 
border-box; padding: 0px 5px;">10</li><li style="box-sizing:
 border-box; padding: 0px 5px;">11</li><li 
style="box-sizing: border-box; padding: 0px 5px;">12</li><li
 style="box-sizing: border-box; padding: 0px 
5px;">13</li><li style="box-sizing: border-box; padding: 0px
 5px;">14</li></ul>

也就是说,对于最小宽度大于等于 600 dp 的设备,系统会选择 layout-sw600dp/main.xml(双面板)布局,否则系统就会选择 layout/main.xml(单面板)布局。

但 Android 版本低于 3.2 的设备不支持此技术,原因是这些设备无法将 sw600dp 识别为尺寸限定符,因此我们仍需使用 large 限定符。这样一来,就会有一个名称为 res/layout-large/main.xml 的文件(与 res/layout-sw600dp/main.xml 一样)。但是没有太大关系,我们将马上学习如何避免此类布局文件出现的重复。

使用布局别名

最小宽度限定符仅适用于 Android 3.2 及更高版本。因此,如果我们仍需使用与较低版本兼容的概括尺寸范围(小、正常、大和特大)。例如,如果要将用户界面设计成在手机上显示单面板,但在 7 英寸平板电脑、电视和其他较大的设备上显示多面板,那么我们就需要提供以下文件:

  • res/layout/main.xml: 单面板布局
  • res/layout-large: 多面板布局
  • res/layout-sw600dp: 多面板布局

后两个文件是相同的,因为其中一个用于和 Android 3.2 设备匹配,而另一个则是为使用较低版本 Android 的平板电脑和电视准备的。

要避免平板电脑和电视的文件出现重复(以及由此带来的维护问题),您可以使用别名文件。例如,您可以定义以下布局:

  • res/layout/main.xml,单面板布局
  • res/layout/main_twopanes.xml,双面板布局

然后添加这两个文件:

res/values-large/layout.xml:

<code
 class="hljs xml has-numbering" style="display: block; padding: 0px; 
background-color: transparent; color: inherit; box-sizing: border-box; 
font-family: 'Source Code Pro', monospace;font-size:undefined; 
white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 
0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; 
word-wrap: normal; background-position: initial initial; 
background-repeat: initial initial;"><span class="hljs-tag" 
style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span
 class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 
136);">resources</span>></span>
    <span class="hljs-tag" style="color: rgb(0, 102, 102); 
box-sizing: border-box;"><<span class="hljs-title" 
style="box-sizing: border-box; color: rgb(0, 0, 
136);">item</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"main"</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">type</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"layout"</span>></span>@layout/main_twopanes<span
 class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">item</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">resources</span>></span></code><ul 
class="pre-numbering" style="box-sizing: border-box; position: absolute;
 width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px;
 margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; 
border-right-style: solid; border-right-color: rgb(221, 221, 221); 
list-style: none; text-align: right;"><li style="box-sizing: 
border-box; padding: 0px 5px;">1</li><li style="box-sizing: 
border-box; padding: 0px 5px;">2</li><li style="box-sizing: 
border-box; padding: 0px 5px;">3</li></ul>

res/values-sw600dp/layout.xml:

<code
 class="hljs xml has-numbering" style="display: block; padding: 0px; 
background-color: transparent; color: inherit; box-sizing: border-box; 
font-family: 'Source Code Pro', monospace;font-size:undefined; 
white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 
0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; 
word-wrap: normal; background-position: initial initial; 
background-repeat: initial initial;"><span class="hljs-tag" 
style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span
 class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 
136);">resources</span>></span>
    <span class="hljs-tag" style="color: rgb(0, 102, 102); 
box-sizing: border-box;"><<span class="hljs-title" 
style="box-sizing: border-box; color: rgb(0, 0, 
136);">item</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"main"</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">type</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"layout"</span>></span>@layout/main_twopanes<span
 class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">item</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">resources</span>></span></code><ul 
class="pre-numbering" style="box-sizing: border-box; position: absolute;
 width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px;
 margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; 
border-right-style: solid; border-right-color: rgb(221, 221, 221); 
list-style: none; text-align: right;"><li style="box-sizing: 
border-box; padding: 0px 5px;">1</li><li style="box-sizing: 
border-box; padding: 0px 5px;">2</li><li style="box-sizing: 
border-box; padding: 0px 5px;">3</li></ul>

后两个文件的内容相同,但它们并未实际定义布局。它们只是将 main 设置成了 main_twopanes 的别名。由于这些文件包含 large 和 sw600dp 选择器,因此无论 Android 版本如何,系统都会将这些文件应用到平板电脑和电视上(版本低于 3.2 的平板电脑和电视会匹配 large,版本高于 3.2 的平板电脑和电视则会匹配 sw600dp)。

使用屏幕方向限定符

某些布局会同时支持横向模式和纵向模式,但我们可以通过调整优化其中大部分布局的效果。在新闻阅读器示例应用中,每种屏幕尺寸和屏幕方向下的布局行为方式如下所示:

  • 小屏幕,纵向:单面板,带徽标
  • 小屏幕,横向:单面板,带徽标
  • 7 英寸平板电脑,纵向:单面板,带操作栏
  • 7 英寸平板电脑,横向:双面板,宽,带操作栏
  • 10 英寸平板电脑,纵向:双面板,窄,带操作栏
  • 10 英寸平板电脑,横向:双面板,宽,带操作栏
  • 电视,横向:双面板,宽,带操作栏

因此,这些布局中的每一种都定义在了 res/layout/ 目录下的某个 XML 文件中。为了继续将每个布局分配给各种屏幕配置,该应用会使用布局别名将两者相匹配:

res/layout/onepane.xml:(单面板)

<code
 class="hljs xml has-numbering" style="display: block; padding: 0px; 
background-color: transparent; color: inherit; box-sizing: border-box; 
font-family: 'Source Code Pro', monospace;font-size:undefined; 
white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 
0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; 
word-wrap: normal; background-position: initial initial; 
background-repeat: initial initial;"><span class="hljs-tag" 
style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span
 class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 
136);">LinearLayout</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">xmlns:android</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"http://schemas.android.com/apk/res/android"</span>
    <span class="hljs-attribute" style="box-sizing: border-box; 
color: rgb(102, 0, 102);">android:orientation</span>=<span 
class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"vertical"</span>
    <span class="hljs-attribute" style="box-sizing: border-box; 
color: rgb(102, 0, 102);">android:layout_width</span>=<span 
class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"match_parent"</span>
    <span class="hljs-attribute" style="box-sizing: border-box; 
color: rgb(102, 0, 102);">android:layout_height</span>=<span
 class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"match_parent"</span>></span>

    <span class="hljs-tag" style="color: rgb(0, 102, 102); 
box-sizing: border-box;"><<span class="hljs-title" 
style="box-sizing: border-box; color: rgb(0, 0, 
136);">fragment</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">android:id</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"@+id/headlines"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_height</span>=<span class="hljs-value"
 style="box-sizing: border-box; color: rgb(0, 136, 
0);">"fill_parent"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"com.example.android.newsreader.HeadlinesFragment"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_width</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"match_parent"</span> /></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">LinearLayout</span>></span></code><ul 
class="pre-numbering" style="box-sizing: border-box; position: absolute;
 width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px;
 margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; 
border-right-style: solid; border-right-color: rgb(221, 221, 221); 
list-style: none; text-align: right;"><li style="box-sizing: 
border-box; padding: 0px 5px;">1</li><li style="box-sizing: 
border-box; padding: 0px 5px;">2</li><li style="box-sizing: 
border-box; padding: 0px 5px;">3</li><li style="box-sizing: 
border-box; padding: 0px 5px;">4</li><li style="box-sizing: 
border-box; padding: 0px 5px;">5</li><li style="box-sizing: 
border-box; padding: 0px 5px;">6</li><li style="box-sizing: 
border-box; padding: 0px 5px;">7</li><li style="box-sizing: 
border-box; padding: 0px 5px;">8</li><li style="box-sizing: 
border-box; padding: 0px 5px;">9</li><li style="box-sizing: 
border-box; padding: 0px 5px;">10</li></ul>

res/layout/onepane_with_bar.xml:(单面板带操作栏)

<code
 class="hljs xml has-numbering" style="display: block; padding: 0px; 
background-color: transparent; color: inherit; box-sizing: border-box; 
font-family: 'Source Code Pro', monospace;font-size:undefined; 
white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 
0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; 
word-wrap: normal; background-position: initial initial; 
background-repeat: initial initial;"><span class="hljs-tag" 
style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span
 class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 
136);">LinearLayout</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">xmlns:android</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"http://schemas.android.com/apk/res/android"</span>
    <span class="hljs-attribute" style="box-sizing: border-box; 
color: rgb(102, 0, 102);">android:orientation</span>=<span 
class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"vertical"</span>
    <span class="hljs-attribute" style="box-sizing: border-box; 
color: rgb(102, 0, 102);">android:layout_width</span>=<span 
class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"match_parent"</span>
    <span class="hljs-attribute" style="box-sizing: border-box; 
color: rgb(102, 0, 102);">android:layout_height</span>=<span
 class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"match_parent"</span>></span>
    <span class="hljs-tag" style="color: rgb(0, 102, 102); 
box-sizing: border-box;"><<span class="hljs-title" 
style="box-sizing: border-box; color: rgb(0, 0, 
136);">LinearLayout</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">android:layout_width</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"match_parent"</span>
                  <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:id</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"@+id/linearLayout1"</span>  
                  <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:gravity</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"center"</span>
                  <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_height</span>=<span class="hljs-value"
 style="box-sizing: border-box; color: rgb(0, 136, 
0);">"50dp"</span>></span>
        <span class="hljs-tag" style="color: rgb(0, 102, 102); 
box-sizing: border-box;"><<span class="hljs-title" 
style="box-sizing: border-box; color: rgb(0, 0, 
136);">ImageView</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">android:id</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"@+id/imageView1"</span>
                   <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_height</span>=<span class="hljs-value"
 style="box-sizing: border-box; color: rgb(0, 136, 
0);">"wrap_content"</span>
                   <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_width</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"wrap_content"</span>
                   <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:src</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"@drawable/logo"</span>
                   <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:paddingRight</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"30dp"</span>
                   <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_gravity</span>=<span 
class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"left"</span>
                   <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_weight</span>=<span class="hljs-value"
 style="box-sizing: border-box; color: rgb(0, 136, 
0);">"0"</span> /></span>
        <span class="hljs-tag" style="color: rgb(0, 102, 102); 
box-sizing: border-box;"><<span class="hljs-title" 
style="box-sizing: border-box; color: rgb(0, 0, 
136);">View</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">android:layout_height</span>=<span class="hljs-value"
 style="box-sizing: border-box; color: rgb(0, 136, 
0);">"wrap_content"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:id</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"@+id/view1"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_width</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"wrap_content"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_weight</span>=<span class="hljs-value"
 style="box-sizing: border-box; color: rgb(0, 136, 
0);">"1"</span> /></span>
        <span class="hljs-tag" style="color: rgb(0, 102, 102); 
box-sizing: border-box;"><<span class="hljs-title" 
style="box-sizing: border-box; color: rgb(0, 0, 
136);">Button</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">android:id</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"@+id/categorybutton"</span>
                <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:background</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"@drawable/button_bg"</span>
                <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_height</span>=<span class="hljs-value"
 style="box-sizing: border-box; color: rgb(0, 136, 
0);">"match_parent"</span>
                <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_weight</span>=<span class="hljs-value"
 style="box-sizing: border-box; color: rgb(0, 136, 
0);">"0"</span>
                <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_width</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"120dp"</span>
                <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 102);">style</span>=<span 
class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"@style/CategoryButtonStyle"</span>/></span>
    <span class="hljs-tag" style="color: rgb(0, 102, 102); 
box-sizing: border-box;"></<span class="hljs-title" 
style="box-sizing: border-box; color: rgb(0, 0, 
136);">LinearLayout</span>></span>

    <span class="hljs-tag" style="color: rgb(0, 102, 102); 
box-sizing: border-box;"><<span class="hljs-title" 
style="box-sizing: border-box; color: rgb(0, 0, 
136);">fragment</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">android:id</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"@+id/headlines"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_height</span>=<span class="hljs-value"
 style="box-sizing: border-box; color: rgb(0, 136, 
0);">"fill_parent"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"com.example.android.newsreader.HeadlinesFragment"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_width</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"match_parent"</span> /></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">LinearLayout</span>></span></code><ul 
class="pre-numbering" style="box-sizing: border-box; position: absolute;
 width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px;
 margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; 
border-right-style: solid; border-right-color: rgb(221, 221, 221); 
list-style: none; text-align: right;"><li style="box-sizing: 
border-box; padding: 0px 5px;">1</li><li style="box-sizing: 
border-box; padding: 0px 5px;">2</li><li style="box-sizing: 
border-box; padding: 0px 5px;">3</li><li style="box-sizing: 
border-box; padding: 0px 5px;">4</li><li style="box-sizing: 
border-box; padding: 0px 5px;">5</li><li style="box-sizing: 
border-box; padding: 0px 5px;">6</li><li style="box-sizing: 
border-box; padding: 0px 5px;">7</li><li style="box-sizing: 
border-box; padding: 0px 5px;">8</li><li style="box-sizing: 
border-box; padding: 0px 5px;">9</li><li style="box-sizing: 
border-box; padding: 0px 5px;">10</li><li style="box-sizing:
 border-box; padding: 0px 5px;">11</li><li 
style="box-sizing: border-box; padding: 0px 5px;">12</li><li
 style="box-sizing: border-box; padding: 0px 
5px;">13</li><li style="box-sizing: border-box; padding: 0px
 5px;">14</li><li style="box-sizing: border-box; padding: 
0px 5px;">15</li><li style="box-sizing: border-box; padding:
 0px 5px;">16</li><li style="box-sizing: border-box; 
padding: 0px 5px;">17</li><li style="box-sizing: border-box;
 padding: 0px 5px;">18</li><li style="box-sizing: 
border-box; padding: 0px 5px;">19</li><li style="box-sizing:
 border-box; padding: 0px 5px;">20</li><li 
style="box-sizing: border-box; padding: 0px 5px;">21</li><li
 style="box-sizing: border-box; padding: 0px 
5px;">22</li><li style="box-sizing: border-box; padding: 0px
 5px;">23</li><li style="box-sizing: border-box; padding: 
0px 5px;">24</li><li style="box-sizing: border-box; padding:
 0px 5px;">25</li><li style="box-sizing: border-box; 
padding: 0px 5px;">26</li><li style="box-sizing: border-box;
 padding: 0px 5px;">27</li><li style="box-sizing: 
border-box; padding: 0px 5px;">28</li><li style="box-sizing:
 border-box; padding: 0px 5px;">29</li><li 
style="box-sizing: border-box; padding: 0px 5px;">30</li><li
 style="box-sizing: border-box; padding: 0px 
5px;">31</li><li style="box-sizing: border-box; padding: 0px
 5px;">32</li></ul>

res/layout/twopanes.xml:(双面板,宽布局)

<code
 class="hljs xml has-numbering" style="display: block; padding: 0px; 
background-color: transparent; color: inherit; box-sizing: border-box; 
font-family: 'Source Code Pro', monospace;font-size:undefined; 
white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 
0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; 
word-wrap: normal; background-position: initial initial; 
background-repeat: initial initial;"><span class="hljs-tag" 
style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span
 class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 
136);">LinearLayout</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">xmlns:android</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"http://schemas.android.com/apk/res/android"</span>
    <span class="hljs-attribute" style="box-sizing: border-box; 
color: rgb(102, 0, 102);">android:layout_width</span>=<span 
class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"fill_parent"</span>
    <span class="hljs-attribute" style="box-sizing: border-box; 
color: rgb(102, 0, 102);">android:layout_height</span>=<span
 class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"fill_parent"</span>
    <span class="hljs-attribute" style="box-sizing: border-box; 
color: rgb(102, 0, 102);">android:orientation</span>=<span 
class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"horizontal"</span>></span>
    <span class="hljs-tag" style="color: rgb(0, 102, 102); 
box-sizing: border-box;"><<span class="hljs-title" 
style="box-sizing: border-box; color: rgb(0, 0, 
136);">fragment</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">android:id</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"@+id/headlines"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_height</span>=<span class="hljs-value"
 style="box-sizing: border-box; color: rgb(0, 136, 
0);">"fill_parent"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"com.example.android.newsreader.HeadlinesFragment"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_width</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"400dp"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_marginRight</span>=<span 
class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"10dp"</span>/></span>
    <span class="hljs-tag" style="color: rgb(0, 102, 102); 
box-sizing: border-box;"><<span class="hljs-title" 
style="box-sizing: border-box; color: rgb(0, 0, 
136);">fragment</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">android:id</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"@+id/article"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_height</span>=<span class="hljs-value"
 style="box-sizing: border-box; color: rgb(0, 136, 
0);">"fill_parent"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"com.example.android.newsreader.ArticleFragment"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_width</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"fill_parent"</span> /></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">LinearLayout</span>></span></code><ul 
class="pre-numbering" style="box-sizing: border-box; position: absolute;
 width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px;
 margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; 
border-right-style: solid; border-right-color: rgb(221, 221, 221); 
list-style: none; text-align: right;"><li style="box-sizing: 
border-box; padding: 0px 5px;">1</li><li style="box-sizing: 
border-box; padding: 0px 5px;">2</li><li style="box-sizing: 
border-box; padding: 0px 5px;">3</li><li style="box-sizing: 
border-box; padding: 0px 5px;">4</li><li style="box-sizing: 
border-box; padding: 0px 5px;">5</li><li style="box-sizing: 
border-box; padding: 0px 5px;">6</li><li style="box-sizing: 
border-box; padding: 0px 5px;">7</li><li style="box-sizing: 
border-box; padding: 0px 5px;">8</li><li style="box-sizing: 
border-box; padding: 0px 5px;">9</li><li style="box-sizing: 
border-box; padding: 0px 5px;">10</li><li style="box-sizing:
 border-box; padding: 0px 5px;">11</li><li 
style="box-sizing: border-box; padding: 0px 5px;">12</li><li
 style="box-sizing: border-box; padding: 0px 
5px;">13</li><li style="box-sizing: border-box; padding: 0px
 5px;">14</li></ul>

res/layout/twopanes_narrow.xml:(双面板,窄布局)

<code
 class="hljs xml has-numbering" style="display: block; padding: 0px; 
background-color: transparent; color: inherit; box-sizing: border-box; 
font-family: 'Source Code Pro', monospace;font-size:undefined; 
white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 
0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; 
word-wrap: normal; background-position: initial initial; 
background-repeat: initial initial;"><span class="hljs-tag" 
style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span
 class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 
136);">LinearLayout</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">xmlns:android</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"http://schemas.android.com/apk/res/android"</span>
    <span class="hljs-attribute" style="box-sizing: border-box; 
color: rgb(102, 0, 102);">android:layout_width</span>=<span 
class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"fill_parent"</span>
    <span class="hljs-attribute" style="box-sizing: border-box; 
color: rgb(102, 0, 102);">android:layout_height</span>=<span
 class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"fill_parent"</span>
    <span class="hljs-attribute" style="box-sizing: border-box; 
color: rgb(102, 0, 102);">android:orientation</span>=<span 
class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"horizontal"</span>></span>
    <span class="hljs-tag" style="color: rgb(0, 102, 102); 
box-sizing: border-box;"><<span class="hljs-title" 
style="box-sizing: border-box; color: rgb(0, 0, 
136);">fragment</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">android:id</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"@+id/headlines"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_height</span>=<span class="hljs-value"
 style="box-sizing: border-box; color: rgb(0, 136, 
0);">"fill_parent"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"com.example.android.newsreader.HeadlinesFragment"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_width</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"200dp"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_marginRight</span>=<span 
class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"10dp"</span>/></span>
    <span class="hljs-tag" style="color: rgb(0, 102, 102); 
box-sizing: border-box;"><<span class="hljs-title" 
style="box-sizing: border-box; color: rgb(0, 0, 
136);">fragment</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">android:id</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"@+id/article"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_height</span>=<span class="hljs-value"
 style="box-sizing: border-box; color: rgb(0, 136, 
0);">"fill_parent"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"com.example.android.newsreader.ArticleFragment"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_width</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"fill_parent"</span> /></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">LinearLayout</span>></span></code><ul 
class="pre-numbering" style="box-sizing: border-box; position: absolute;
 width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px;
 margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; 
border-right-style: solid; border-right-color: rgb(221, 221, 221); 
list-style: none; text-align: right;"><li style="box-sizing: 
border-box; padding: 0px 5px;">1</li><li style="box-sizing: 
border-box; padding: 0px 5px;">2</li><li style="box-sizing: 
border-box; padding: 0px 5px;">3</li><li style="box-sizing: 
border-box; padding: 0px 5px;">4</li><li style="box-sizing: 
border-box; padding: 0px 5px;">5</li><li style="box-sizing: 
border-box; padding: 0px 5px;">6</li><li style="box-sizing: 
border-box; padding: 0px 5px;">7</li><li style="box-sizing: 
border-box; padding: 0px 5px;">8</li><li style="box-sizing: 
border-box; padding: 0px 5px;">9</li><li style="box-sizing: 
border-box; padding: 0px 5px;">10</li><li style="box-sizing:
 border-box; padding: 0px 5px;">11</li><li 
style="box-sizing: border-box; padding: 0px 5px;">12</li><li
 style="box-sizing: border-box; padding: 0px 
5px;">13</li><li style="box-sizing: border-box; padding: 0px
 5px;">14</li></ul>

既然我们已定义了所有可能的布局,那就只需使用配置限定符将正确的布局映射到各种配置即可。

现在只需使用布局别名技术即可做到这一点:

res/values/layouts.xml:

<code
 class="hljs xml has-numbering" style="display: block; padding: 0px; 
background-color: transparent; color: inherit; box-sizing: border-box; 
font-family: 'Source Code Pro', monospace;font-size:undefined; 
white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 
0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; 
word-wrap: normal; background-position: initial initial; 
background-repeat: initial initial;"><span class="hljs-tag" 
style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span
 class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 
136);">resources</span>></span>
    <span class="hljs-tag" style="color: rgb(0, 102, 102); 
box-sizing: border-box;"><<span class="hljs-title" 
style="box-sizing: border-box; color: rgb(0, 0, 
136);">item</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"main_layout"</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">type</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"layout"</span>></span>@layout/onepane_with_bar<span
 class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">item</span>></span>
    <span class="hljs-tag" style="color: rgb(0, 102, 102); 
box-sizing: border-box;"><<span class="hljs-title" 
style="box-sizing: border-box; color: rgb(0, 0, 
136);">bool</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"has_two_panes"</span>></span>false<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">bool</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">resources</span>></span></code><ul 
class="pre-numbering" style="box-sizing: border-box; position: absolute;
 width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px;
 margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; 
border-right-style: solid; border-right-color: rgb(221, 221, 221); 
list-style: none; text-align: right;"><li style="box-sizing: 
border-box; padding: 0px 5px;">1</li><li style="box-sizing: 
border-box; padding: 0px 5px;">2</li><li style="box-sizing: 
border-box; padding: 0px 5px;">3</li><li style="box-sizing: 
border-box; padding: 0px 5px;">4</li></ul>

res/values-sw600dp-land/layouts.xml:

<code
 class="hljs xml has-numbering" style="display: block; padding: 0px; 
background-color: transparent; color: inherit; box-sizing: border-box; 
font-family: 'Source Code Pro', monospace;font-size:undefined; 
white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 
0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; 
word-wrap: normal; background-position: initial initial; 
background-repeat: initial initial;"><span class="hljs-tag" 
style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span
 class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 
136);">resources</span>></span>
    <span class="hljs-tag" style="color: rgb(0, 102, 102); 
box-sizing: border-box;"><<span class="hljs-title" 
style="box-sizing: border-box; color: rgb(0, 0, 
136);">item</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"main_layout"</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">type</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"layout"</span>></span>@layout/twopanes<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">item</span>></span>
    <span class="hljs-tag" style="color: rgb(0, 102, 102); 
box-sizing: border-box;"><<span class="hljs-title" 
style="box-sizing: border-box; color: rgb(0, 0, 
136);">bool</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"has_two_panes"</span>></span>true<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">bool</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">resources</span>></span></code><ul 
class="pre-numbering" style="box-sizing: border-box; position: absolute;
 width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px;
 margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; 
border-right-style: solid; border-right-color: rgb(221, 221, 221); 
list-style: none; text-align: right;"><li style="box-sizing: 
border-box; padding: 0px 5px;">1</li><li style="box-sizing: 
border-box; padding: 0px 5px;">2</li><li style="box-sizing: 
border-box; padding: 0px 5px;">3</li><li style="box-sizing: 
border-box; padding: 0px 5px;">4</li></ul>

res/values-sw600dp-port/layouts.xml:

<code
 class="hljs xml has-numbering" style="display: block; padding: 0px; 
background-color: transparent; color: inherit; box-sizing: border-box; 
font-family: 'Source Code Pro', monospace;font-size:undefined; 
white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 
0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; 
word-wrap: normal; background-position: initial initial; 
background-repeat: initial initial;"><span class="hljs-tag" 
style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span
 class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 
136);">resources</span>></span>
    <span class="hljs-tag" style="color: rgb(0, 102, 102); 
box-sizing: border-box;"><<span class="hljs-title" 
style="box-sizing: border-box; color: rgb(0, 0, 
136);">item</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"main_layout"</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">type</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"layout"</span>></span>@layout/onepane<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">item</span>></span>
    <span class="hljs-tag" style="color: rgb(0, 102, 102); 
box-sizing: border-box;"><<span class="hljs-title" 
style="box-sizing: border-box; color: rgb(0, 0, 
136);">bool</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"has_two_panes"</span>></span>false<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">bool</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">resources</span>></span></code><ul 
class="pre-numbering" style="box-sizing: border-box; position: absolute;
 width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px;
 margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; 
border-right-style: solid; border-right-color: rgb(221, 221, 221); 
list-style: none; text-align: right;"><li style="box-sizing: 
border-box; padding: 0px 5px;">1</li><li style="box-sizing: 
border-box; padding: 0px 5px;">2</li><li style="box-sizing: 
border-box; padding: 0px 5px;">3</li><li style="box-sizing: 
border-box; padding: 0px 5px;">4</li></ul>

res/values-large-land/layouts.xml:

<code
 class="hljs xml has-numbering" style="display: block; padding: 0px; 
background-color: transparent; color: inherit; box-sizing: border-box; 
font-family: 'Source Code Pro', monospace;font-size:undefined; 
white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 
0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; 
word-wrap: normal; background-position: initial initial; 
background-repeat: initial initial;"><span class="hljs-tag" 
style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span
 class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 
136);">resources</span>></span>
    <span class="hljs-tag" style="color: rgb(0, 102, 102); 
box-sizing: border-box;"><<span class="hljs-title" 
style="box-sizing: border-box; color: rgb(0, 0, 
136);">item</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"main_layout"</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">type</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"layout"</span>></span>@layout/twopanes<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">item</span>></span>
    <span class="hljs-tag" style="color: rgb(0, 102, 102); 
box-sizing: border-box;"><<span class="hljs-title" 
style="box-sizing: border-box; color: rgb(0, 0, 
136);">bool</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"has_two_panes"</span>></span>true<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">bool</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">resources</span>></span></code><ul 
class="pre-numbering" style="box-sizing: border-box; position: absolute;
 width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px;
 margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; 
border-right-style: solid; border-right-color: rgb(221, 221, 221); 
list-style: none; text-align: right;"><li style="box-sizing: 
border-box; padding: 0px 5px;">1</li><li style="box-sizing: 
border-box; padding: 0px 5px;">2</li><li style="box-sizing: 
border-box; padding: 0px 5px;">3</li><li style="box-sizing: 
border-box; padding: 0px 5px;">4</li></ul>

res/values-large-port/layouts.xml:

<code
 class="hljs xml has-numbering" style="display: block; padding: 0px; 
background-color: transparent; color: inherit; box-sizing: border-box; 
font-family: 'Source Code Pro', monospace;font-size:undefined; 
white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 
0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; 
word-wrap: normal; background-position: initial initial; 
background-repeat: initial initial;"><span class="hljs-tag" 
style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span
 class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 
136);">resources</span>></span>
    <span class="hljs-tag" style="color: rgb(0, 102, 102); 
box-sizing: border-box;"><<span class="hljs-title" 
style="box-sizing: border-box; color: rgb(0, 0, 
136);">item</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"main_layout"</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">type</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"layout"</span>></span>@layout/twopanes_narrow<span
 class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">item</span>></span>
    <span class="hljs-tag" style="color: rgb(0, 102, 102); 
box-sizing: border-box;"><<span class="hljs-title" 
style="box-sizing: border-box; color: rgb(0, 0, 
136);">bool</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"has_two_panes"</span>></span>true<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">bool</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">resources</span>></span></code><ul 
class="pre-numbering" style="box-sizing: border-box; position: absolute;
 width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px;
 margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; 
border-right-style: solid; border-right-color: rgb(221, 221, 221); 
list-style: none; text-align: right;"><li style="box-sizing: 
border-box; padding: 0px 5px;">1</li><li style="box-sizing: 
border-box; padding: 0px 5px;">2</li><li style="box-sizing: 
border-box; padding: 0px 5px;">3</li><li style="box-sizing: 
border-box; padding: 0px 5px;">4</li></ul>

使用自动拉伸位图

支持各种屏幕尺寸通常意味着您的图片资源还必须能适应各种尺寸。例如,无论要应用到什么形状的按钮上,按钮背景都必须能适应。

如果在可以更改尺寸的组件上使用了简单的图片,您很快就会发现显示效果多少有些不太理想,因为系统会在运行时平均地拉伸或收缩您的图片。解决方法为使用自动拉伸位图,这是一种格式特殊的 PNG 文件,其中会指明可以拉伸以及不可以拉伸的区域。

.9的制作,实际上就是在原图片上添加1px的边界,然后按照我们的需求,把对应的位置设置成黑色线,系统就会根据我们的实际需求进行拉伸。

下图是对.9图的四边的含义的解释,左上边代表拉伸区域,右下边代表padding box,就是间隔区域,在下面,我们给出一个例子,方便大家理解。

先看下面两张图,我们理解一下这四条线的含义。

上图和下图的区别,就在于右下边的黑线不一样,具体的效果的区别,看右边的效果图。上图效果图中深蓝色的区域,代表内容区域,我们可以看到是在正中央的, 这是因为我们在右下边的是两个点,这两个点距离上下左右四个方向的距离就是padding的距离,所以深蓝色内容区域在图片正中央,我们再看下图,由于右 下边的黑线是图片长度,所以就没有padding,从效果图上的表现就是深蓝色区域和图片一样大,因此,我们可以利用右下边来控制内容与背景图边缘的 padding。

如果你还不明白,那么我们看下面的效果图,我们分别以图一和图二作为背景图,下面是效果图。

我们可以看到,使用wrap_content属性设置长宽,图一比图二的效果大一圈,这是为什么呢?还记得我上面说的padding吗?

这就是padding的效果提现,怎么证明呢?我们再看下面一张图,给图一添加padding=0,这样背景图设置的padding效果就没了,是不是两个一样大了?

ok,我想你应该明白右下边的黑线的含义了,下面我们再看一下左上边的效果。

下面我们只设置了左上边线,效果图如下

上面的线没有包住图标,下面的线正好包住了图标,从右边的效果图应该可以看出差别,黑线所在的区域就是拉伸区域,上图黑线所在的全是纯色,所以图标不变 形,下面的拉伸区域包裹了图标,所以在拉伸的时候就会对图标进行拉伸,但是这样就会导致图标变形。注意到下面红线区域了嘛?这是系统提示我们的,因为这样 拉伸,不符合要求,所以会提示一下。

支持各种屏幕密度

使用非密度制约像素

由于各种屏幕的像素密度都有所不同,因此相同数量的像素在不同设备上的实际大小也有所差异,这样使用像素定义布局尺寸就会产生问题。因此,请务必使用 dp 或 sp 单位指定尺寸。dp 是一种非密度制约像素,其尺寸与 160 dpi 像素的实际尺寸相同。sp 也是一种基本单位,但它可根据用户的偏好文字大小进行调整(即尺度独立性像素),因此我们应将该测量单位用于定义文字大小。

例如,请使用 dp(而非 px)指定两个视图间的间距:

<code
 class="hljs xml has-numbering" style="display: block; padding: 0px; 
background-color: transparent; color: inherit; box-sizing: border-box; 
font-family: 'Source Code Pro', monospace;font-size:undefined; 
white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 
0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; 
word-wrap: normal; background-position: initial initial; 
background-repeat: initial initial;"><span class="hljs-tag" 
style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span
 class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 
136);">Button</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">android:layout_width</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"wrap_content"</span>
    <span class="hljs-attribute" style="box-sizing: border-box; 
color: rgb(102, 0, 102);">android:layout_height</span>=<span
 class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"wrap_content"</span>
    <span class="hljs-attribute" style="box-sizing: border-box; 
color: rgb(102, 0, 102);">android:text</span>=<span 
class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"@string/clickme"</span>
    <span class="hljs-attribute" style="box-sizing: border-box; 
color: rgb(102, 0, 
102);">android:layout_marginTop</span>=<span 
class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"20dp"</span> /></span></code><ul 
class="pre-numbering" style="box-sizing: border-box; position: absolute;
 width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px;
 margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; 
border-right-style: solid; border-right-color: rgb(221, 221, 221); 
list-style: none; text-align: right;"><li style="box-sizing: 
border-box; padding: 0px 5px;">1</li><li style="box-sizing: 
border-box; padding: 0px 5px;">2</li><li style="box-sizing: 
border-box; padding: 0px 5px;">3</li><li style="box-sizing: 
border-box; padding: 0px 5px;">4</li></ul>

请务必使用 sp 指定文字大小:

<code
 class="hljs xml has-numbering" style="display: block; padding: 0px; 
background-color: transparent; color: inherit; box-sizing: border-box; 
font-family: 'Source Code Pro', monospace;font-size:undefined; 
white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 
0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; 
word-wrap: normal; background-position: initial initial; 
background-repeat: initial initial;"><span class="hljs-tag" 
style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span
 class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 
136);">TextView</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">android:layout_width</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"match_parent"</span>
    <span class="hljs-attribute" style="box-sizing: border-box; 
color: rgb(102, 0, 102);">android:layout_height</span>=<span
 class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"wrap_content"</span>
    <span class="hljs-attribute" style="box-sizing: border-box; 
color: rgb(102, 0, 102);">android:textSize</span>=<span 
class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"20sp"</span> /></span></code><ul 
class="pre-numbering" style="box-sizing: border-box; position: absolute;
 width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px;
 margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; 
border-right-style: solid; border-right-color: rgb(221, 221, 221); 
list-style: none; text-align: right;"><li style="box-sizing: 
border-box; padding: 0px 5px;">1</li><li style="box-sizing: 
border-box; padding: 0px 5px;">2</li><li style="box-sizing: 
border-box; padding: 0px 5px;">3</li></ul>

除了介绍这些最基础的知识之外,我们下面再来讨论一下另外一个问题。

经过上面的介绍,我们都清楚,为了能够规避不同像素密度的陷阱,Google推荐使用dp来代替px作为控件长度的度量单位,但是我们来看下面的一个场景。

假如我们以Nexus5作为书写代码时查看效果的测试机型,Nexus5的总宽度为360dp,我们现在需要在水平方向上放置两个按钮,一个是150dp左对齐,另外一个是200dp右对齐,中间留有10dp间隔,那么在Nexus5上面的显示效果就是下面这样

但是如果在Nexus S或者是Nexus One运行呢?下面是运行结果

可以看到,两个按钮发生了重叠。

我们都已经用了dp了,为什么会出现这种情况呢?

你听我慢慢道来。

虽然说dp可以去除不同像素密度的问题,使得1dp在不同像素密度上面的显示效果相同,但是还是由于Android屏幕设备的多样性,如果使用dp来作为 度量单位,并不是所有的屏幕的宽度都是相同的dp长度,比如说,Nexus S和Nexus One属于hdpi,屏幕宽度是320dp,而Nexus 5属于xxhdpi,屏幕宽度是360dp,Galaxy Nexus属于xhdpi,屏幕宽度是384dp,Nexus 6 属于xxxhdpi,屏幕宽度是410dp。所以说,光Google自己一家的产品就已经有这么多的标准,而且屏幕宽度和像素密度没有任何关联关系,即使 我们使用dp,在320dp宽度的设备和410dp的设备上,还是会有90dp的差别。当然,我们尽量使用match_parent和 wrap_content,尽可能少的用dp来指定控件的具体长宽,再结合上权重,大部分的情况我们都是可以做到适配的。

但是除了这个方法,我们还有没有其他的更彻底的解决方案呢?

我们换另外一个思路来思考这个问题。

下面的方案来自Android Day Day Up 一群的【blue-深圳】,谢谢他的分享精神

因为分辨率不一样,所以不能用px;因为屏幕宽度不一样,所以要小心的用dp,那么我们可不可以用另外一种方法来统一单位,不管分辨率是多大,屏幕宽度用一个固定的值的单位来统计呢?

答案是:当然可以。

我们假设手机屏幕的宽度都是320某单位,那么我们将一个屏幕宽度的总像素数平均分成320份,每一份对应具体的像素就可以了。

具体如何来实现呢?我们看下面的代码

<code
 class="hljs java has-numbering" style="display: block; padding: 0px; 
background-color: transparent; color: inherit; box-sizing: border-box; 
font-family: 'Source Code Pro', monospace;font-size:undefined; 
white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 
0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; 
word-wrap: normal; background-position: initial initial; 
background-repeat: initial initial;"><span class="hljs-keyword" 
style="color: rgb(0, 0, 136); box-sizing: 
border-box;">import</span> java.io.File;
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: 
border-box;">import</span> java.io.FileNotFoundException;
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: 
border-box;">import</span> java.io.FileOutputStream;
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: 
border-box;">import</span> java.io.PrintWriter;

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: 
border-box;">public</span> <span class="hljs-class" 
style="box-sizing: border-box;"><span class="hljs-keyword" 
style="color: rgb(0, 0, 136); box-sizing: 
border-box;">class</span> <span class="hljs-title" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">MakeXml</span> {</span>

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); 
box-sizing: border-box;">private</span> <span 
class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: 
border-box;">final</span> <span class="hljs-keyword" 
style="color: rgb(0, 0, 136); box-sizing: 
border-box;">static</span> String rootPath = <span 
class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: 
border-box;">"C:\\Users\\Administrator\\Desktop\\layoutroot\\values-{0}x{1}\\"</span>;


    <span class="hljs-keyword" style="color: rgb(0, 0, 136); 
box-sizing: border-box;">private</span> <span 
class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: 
border-box;">final</span> <span class="hljs-keyword" 
style="color: rgb(0, 0, 136); box-sizing: 
border-box;">static</span> <span class="hljs-keyword" 
style="color: rgb(0, 0, 136); box-sizing: 
border-box;">float</span> dw = <span class="hljs-number" 
style="color: rgb(0, 102, 102); box-sizing: 
border-box;">320</span>f;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); 
box-sizing: border-box;">private</span> <span 
class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: 
border-box;">final</span> <span class="hljs-keyword" 
style="color: rgb(0, 0, 136); box-sizing: 
border-box;">static</span> <span class="hljs-keyword" 
style="color: rgb(0, 0, 136); box-sizing: 
border-box;">float</span> dh = <span class="hljs-number" 
style="color: rgb(0, 102, 102); box-sizing: 
border-box;">480</span>f;

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); 
box-sizing: border-box;">private</span> <span 
class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: 
border-box;">final</span> <span class="hljs-keyword" 
style="color: rgb(0, 0, 136); box-sizing: 
border-box;">static</span> String WTemplate = <span 
class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: 
border-box;">"<dimen 
name=\"x{0}\">{1}px</dimen>\n"</span>;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); 
box-sizing: border-box;">private</span> <span 
class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: 
border-box;">final</span> <span class="hljs-keyword" 
style="color: rgb(0, 0, 136); box-sizing: 
border-box;">static</span> String HTemplate = <span 
class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: 
border-box;">"<dimen 
name=\"y{0}\">{1}px</dimen>\n"</span>;

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); 
box-sizing: border-box;">public</span> <span 
class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: 
border-box;">static</span> <span class="hljs-keyword" 
style="color: rgb(0, 0, 136); box-sizing: 
border-box;">void</span> <span class="hljs-title" 
style="box-sizing: border-box;">main</span>(String[] args) {
        makeString(<span class="hljs-number" style="color: rgb(0, 
102, 102); box-sizing: border-box;">320</span>, <span 
class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: 
border-box;">480</span>);
        makeString(<span class="hljs-number" style="color: rgb(0, 
102, 102); box-sizing: border-box;">480</span>,<span 
class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: 
border-box;">800</span>);
        makeString(<span class="hljs-number" style="color: rgb(0, 
102, 102); box-sizing: border-box;">480</span>, <span 
class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: 
border-box;">854</span>);
        makeString(<span class="hljs-number" style="color: rgb(0, 
102, 102); box-sizing: border-box;">540</span>, <span 
class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: 
border-box;">960</span>);
        makeString(<span class="hljs-number" style="color: rgb(0, 
102, 102); box-sizing: border-box;">600</span>, <span 
class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: 
border-box;">1024</span>);
        makeString(<span class="hljs-number" style="color: rgb(0, 
102, 102); box-sizing: border-box;">720</span>, <span 
class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: 
border-box;">1184</span>);
        makeString(<span class="hljs-number" style="color: rgb(0, 
102, 102); box-sizing: border-box;">720</span>, <span 
class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: 
border-box;">1196</span>);
        makeString(<span class="hljs-number" style="color: rgb(0, 
102, 102); box-sizing: border-box;">720</span>, <span 
class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: 
border-box;">1280</span>);
        makeString(<span class="hljs-number" style="color: rgb(0, 
102, 102); box-sizing: border-box;">768</span>, <span 
class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: 
border-box;">1024</span>);
        makeString(<span class="hljs-number" style="color: rgb(0, 
102, 102); box-sizing: border-box;">800</span>, <span 
class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: 
border-box;">1280</span>);
        makeString(<span class="hljs-number" style="color: rgb(0, 
102, 102); box-sizing: border-box;">1080</span>, <span 
class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: 
border-box;">1812</span>);
        makeString(<span class="hljs-number" style="color: rgb(0, 
102, 102); box-sizing: border-box;">1080</span>, <span 
class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: 
border-box;">1920</span>);
        makeString(<span class="hljs-number" style="color: rgb(0, 
102, 102); box-sizing: border-box;">1440</span>, <span 
class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: 
border-box;">2560</span>);
    }

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); 
box-sizing: border-box;">public</span> <span 
class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: 
border-box;">static</span> <span class="hljs-keyword" 
style="color: rgb(0, 0, 136); box-sizing: 
border-box;">void</span> <span class="hljs-title" 
style="box-sizing: border-box;">makeString</span>(<span 
class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: 
border-box;">int</span> w, <span class="hljs-keyword" 
style="color: rgb(0, 0, 136); box-sizing: 
border-box;">int</span> h) {

        StringBuffer sb = <span class="hljs-keyword" style="color: 
rgb(0, 0, 136); box-sizing: border-box;">new</span> 
StringBuffer();
        sb.append(<span class="hljs-string" style="color: rgb(0, 136,
 0); box-sizing: border-box;">"<?xml version=\"1.0\" 
encoding=\"utf-8\"?>\n"</span>);
        sb.append(<span class="hljs-string" style="color: rgb(0, 136,
 0); box-sizing: border-box;">"<resources>"</span>);
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); 
box-sizing: border-box;">float</span> cellw = w / dw;
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); 
box-sizing: border-box;">for</span> (<span 
class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: 
border-box;">int</span> i = <span class="hljs-number" 
style="color: rgb(0, 102, 102); box-sizing: 
border-box;">1</span>; i < <span class="hljs-number" 
style="color: rgb(0, 102, 102); box-sizing: 
border-box;">320</span>; i++) {
            sb.append(WTemplate.replace(<span class="hljs-string" 
style="color: rgb(0, 136, 0); box-sizing: 
border-box;">"{0}"</span>, i + <span class="hljs-string" 
style="color: rgb(0, 136, 0); box-sizing: 
border-box;">""</span>).replace(<span class="hljs-string" 
style="color: rgb(0, 136, 0); box-sizing: 
border-box;">"{1}"</span>,
                    change(cellw * i) + <span class="hljs-string" 
style="color: rgb(0, 136, 0); box-sizing: 
border-box;">""</span>));
        }
        sb.append(WTemplate.replace(<span class="hljs-string" 
style="color: rgb(0, 136, 0); box-sizing: 
border-box;">"{0}"</span>, <span class="hljs-string" 
style="color: rgb(0, 136, 0); box-sizing: 
border-box;">"320"</span>).replace(<span class="hljs-string"
 style="color: rgb(0, 136, 0); box-sizing: 
border-box;">"{1}"</span>, w + <span class="hljs-string" 
style="color: rgb(0, 136, 0); box-sizing: 
border-box;">""</span>));
        sb.append(<span class="hljs-string" style="color: rgb(0, 136,
 0); box-sizing: border-box;">"</resources>"</span>);

        StringBuffer sb2 = <span class="hljs-keyword" style="color: 
rgb(0, 0, 136); box-sizing: border-box;">new</span> 
StringBuffer();
        sb2.append(<span class="hljs-string" style="color: rgb(0, 
136, 0); box-sizing: border-box;">"<?xml version=\"1.0\" 
encoding=\"utf-8\"?>\n"</span>);
        sb2.append(<span class="hljs-string" style="color: rgb(0, 
136, 0); box-sizing: border-box;">"<resources>"</span>);
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); 
box-sizing: border-box;">float</span> cellh = h / dh;
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); 
box-sizing: border-box;">for</span> (<span 
class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: 
border-box;">int</span> i = <span class="hljs-number" 
style="color: rgb(0, 102, 102); box-sizing: 
border-box;">1</span>; i < <span class="hljs-number" 
style="color: rgb(0, 102, 102); box-sizing: 
border-box;">480</span>; i++) {
            sb2.append(HTemplate.replace(<span class="hljs-string" 
style="color: rgb(0, 136, 0); box-sizing: 
border-box;">"{0}"</span>, i + <span class="hljs-string" 
style="color: rgb(0, 136, 0); box-sizing: 
border-box;">""</span>).replace(<span class="hljs-string" 
style="color: rgb(0, 136, 0); box-sizing: 
border-box;">"{1}"</span>,
                    change(cellh * i) + <span class="hljs-string" 
style="color: rgb(0, 136, 0); box-sizing: 
border-box;">""</span>));
        }
        sb2.append(HTemplate.replace(<span class="hljs-string" 
style="color: rgb(0, 136, 0); box-sizing: 
border-box;">"{0}"</span>, <span class="hljs-string" 
style="color: rgb(0, 136, 0); box-sizing: 
border-box;">"480"</span>).replace(<span class="hljs-string"
 style="color: rgb(0, 136, 0); box-sizing: 
border-box;">"{1}"</span>, h + <span class="hljs-string" 
style="color: rgb(0, 136, 0); box-sizing: 
border-box;">""</span>));
        sb2.append(<span class="hljs-string" style="color: rgb(0, 
136, 0); box-sizing: border-box;">"</resources>"</span>);

        String path = rootPath.replace(<span class="hljs-string" 
style="color: rgb(0, 136, 0); box-sizing: 
border-box;">"{0}"</span>, h + <span class="hljs-string" 
style="color: rgb(0, 136, 0); box-sizing: 
border-box;">""</span>).replace(<span class="hljs-string" 
style="color: rgb(0, 136, 0); box-sizing: 
border-box;">"{1}"</span>, w + <span class="hljs-string" 
style="color: rgb(0, 136, 0); box-sizing: 
border-box;">""</span>);
        File rootFile = <span class="hljs-keyword" style="color: 
rgb(0, 0, 136); box-sizing: border-box;">new</span> File(path);
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); 
box-sizing: border-box;">if</span> (!rootFile.exists()) {
            rootFile.mkdirs();
        }
        File layxFile = <span class="hljs-keyword" style="color: 
rgb(0, 0, 136); box-sizing: border-box;">new</span> File(path +
 <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: 
border-box;">"lay_x.xml"</span>);
        File layyFile = <span class="hljs-keyword" style="color: 
rgb(0, 0, 136); box-sizing: border-box;">new</span> File(path +
 <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: 
border-box;">"lay_y.xml"</span>);
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); 
box-sizing: border-box;">try</span> {
            PrintWriter pw = <span class="hljs-keyword" style="color:
 rgb(0, 0, 136); box-sizing: border-box;">new</span> 
PrintWriter(<span class="hljs-keyword" style="color: rgb(0, 0, 136); 
box-sizing: border-box;">new</span> 
FileOutputStream(layxFile));
            pw.print(sb.toString());
            pw.close();
            pw = <span class="hljs-keyword" style="color: rgb(0, 0, 
136); box-sizing: border-box;">new</span> PrintWriter(<span 
class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: 
border-box;">new</span> FileOutputStream(layyFile));
            pw.print(sb2.toString());
            pw.close();
        } <span class="hljs-keyword" style="color: rgb(0, 0, 136); 
box-sizing: border-box;">catch</span> (FileNotFoundException e)
 {
            e.printStackTrace();
        }

    }

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); 
box-sizing: border-box;">public</span> <span 
class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: 
border-box;">static</span> <span class="hljs-keyword" 
style="color: rgb(0, 0, 136); box-sizing: 
border-box;">float</span> <span class="hljs-title" 
style="box-sizing: border-box;">change</span>(<span 
class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: 
border-box;">float</span> a) {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); 
box-sizing: border-box;">int</span> temp = (<span 
class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: 
border-box;">int</span>) (a * <span class="hljs-number" 
style="color: rgb(0, 102, 102); box-sizing: 
border-box;">100</span>);
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); 
box-sizing: border-box;">return</span> temp / <span 
class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: 
border-box;">100</span>f;
    }
}
</code><ul class="pre-numbering" style="box-sizing: border-box;
 position: absolute; width: 50px; background-color: rgb(238, 238, 238); 
top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; 
border-right-width: 1px; border-right-style: solid; border-right-color: 
rgb(221, 221, 221); list-style: none; text-align: right;"><li 
style="box-sizing: border-box; padding: 0px 5px;">1</li><li 
style="box-sizing: border-box; padding: 0px 5px;">2</li><li 
style="box-sizing: border-box; padding: 0px 5px;">3</li><li 
style="box-sizing: border-box; padding: 0px 5px;">4</li><li 
style="box-sizing: border-box; padding: 0px 5px;">5</li><li 
style="box-sizing: border-box; padding: 0px 5px;">6</li><li 
style="box-sizing: border-box; padding: 0px 5px;">7</li><li 
style="box-sizing: border-box; padding: 0px 5px;">8</li><li 
style="box-sizing: border-box; padding: 0px 5px;">9</li><li 
style="box-sizing: border-box; padding: 0px 5px;">10</li><li
 style="box-sizing: border-box; padding: 0px 
5px;">11</li><li style="box-sizing: border-box; padding: 0px
 5px;">12</li><li style="box-sizing: border-box; padding: 
0px 5px;">13</li><li style="box-sizing: border-box; padding:
 0px 5px;">14</li><li style="box-sizing: border-box; 
padding: 0px 5px;">15</li><li style="box-sizing: border-box;
 padding: 0px 5px;">16</li><li style="box-sizing: 
border-box; padding: 0px 5px;">17</li><li style="box-sizing:
 border-box; padding: 0px 5px;">18</li><li 
style="box-sizing: border-box; padding: 0px 5px;">19</li><li
 style="box-sizing: border-box; padding: 0px 
5px;">20</li><li style="box-sizing: border-box; padding: 0px
 5px;">21</li><li style="box-sizing: border-box; padding: 
0px 5px;">22</li><li style="box-sizing: border-box; padding:
 0px 5px;">23</li><li style="box-sizing: border-box; 
padding: 0px 5px;">24</li><li style="box-sizing: border-box;
 padding: 0px 5px;">25</li><li style="box-sizing: 
border-box; padding: 0px 5px;">26</li><li style="box-sizing:
 border-box; padding: 0px 5px;">27</li><li 
style="box-sizing: border-box; padding: 0px 5px;">28</li><li
 style="box-sizing: border-box; padding: 0px 
5px;">29</li><li style="box-sizing: border-box; padding: 0px
 5px;">30</li><li style="box-sizing: border-box; padding: 
0px 5px;">31</li><li style="box-sizing: border-box; padding:
 0px 5px;">32</li><li style="box-sizing: border-box; 
padding: 0px 5px;">33</li><li style="box-sizing: border-box;
 padding: 0px 5px;">34</li><li style="box-sizing: 
border-box; padding: 0px 5px;">35</li><li style="box-sizing:
 border-box; padding: 0px 5px;">36</li><li 
style="box-sizing: border-box; padding: 0px 5px;">37</li><li
 style="box-sizing: border-box; padding: 0px 
5px;">38</li><li style="box-sizing: border-box; padding: 0px
 5px;">39</li><li style="box-sizing: border-box; padding: 
0px 5px;">40</li><li style="box-sizing: border-box; padding:
 0px 5px;">41</li><li style="box-sizing: border-box; 
padding: 0px 5px;">42</li><li style="box-sizing: border-box;
 padding: 0px 5px;">43</li><li style="box-sizing: 
border-box; padding: 0px 5px;">44</li><li style="box-sizing:
 border-box; padding: 0px 5px;">45</li><li 
style="box-sizing: border-box; padding: 0px 5px;">46</li><li
 style="box-sizing: border-box; padding: 0px 
5px;">47</li><li style="box-sizing: border-box; padding: 0px
 5px;">48</li><li style="box-sizing: border-box; padding: 
0px 5px;">49</li><li style="box-sizing: border-box; padding:
 0px 5px;">50</li><li style="box-sizing: border-box; 
padding: 0px 5px;">51</li><li style="box-sizing: border-box;
 padding: 0px 5px;">52</li><li style="box-sizing: 
border-box; padding: 0px 5px;">53</li><li style="box-sizing:
 border-box; padding: 0px 5px;">54</li><li 
style="box-sizing: border-box; padding: 0px 5px;">55</li><li
 style="box-sizing: border-box; padding: 0px 
5px;">56</li><li style="box-sizing: border-box; padding: 0px
 5px;">57</li><li style="box-sizing: border-box; padding: 
0px 5px;">58</li><li style="box-sizing: border-box; padding:
 0px 5px;">59</li><li style="box-sizing: border-box; 
padding: 0px 5px;">60</li><li style="box-sizing: border-box;
 padding: 0px 5px;">61</li><li style="box-sizing: 
border-box; padding: 0px 5px;">62</li><li style="box-sizing:
 border-box; padding: 0px 5px;">63</li><li 
style="box-sizing: border-box; padding: 0px 5px;">64</li><li
 style="box-sizing: border-box; padding: 0px 
5px;">65</li><li style="box-sizing: border-box; padding: 0px
 5px;">66</li><li style="box-sizing: border-box; padding: 
0px 5px;">67</li><li style="box-sizing: border-box; padding:
 0px 5px;">68</li><li style="box-sizing: border-box; 
padding: 0px 5px;">69</li><li style="box-sizing: border-box;
 padding: 0px 5px;">70</li><li style="box-sizing: 
border-box; padding: 0px 5px;">71</li><li style="box-sizing:
 border-box; padding: 0px 5px;">72</li><li 
style="box-sizing: border-box; padding: 0px 5px;">73</li><li
 style="box-sizing: border-box; padding: 0px 
5px;">74</li><li style="box-sizing: border-box; padding: 0px
 5px;">75</li><li style="box-sizing: border-box; padding: 
0px 5px;">76</li><li style="box-sizing: border-box; padding:
 0px 5px;">77</li><li style="box-sizing: border-box; 
padding: 0px 5px;">78</li><li style="box-sizing: border-box;
 padding: 0px 5px;">79</li><li style="box-sizing: 
border-box; padding: 0px 5px;">80</li><li style="box-sizing:
 border-box; padding: 0px 5px;">81</li></ul>

代码应该很好懂,我们将一个屏幕宽度分为320份,高度480份,然后按照实际像素对每一个单位进行复制,放在对应values- widthxheight文件夹下面的lax.xml和lay.xml里面,这样就可以统一所有你想要的分辨率的单位了,下面是生成的一个320*480 分辨率的文件,因为宽高分割之后总分数和像素数相同,所以x1就是1px,以此类推

<code
 class="hljs xml has-numbering" style="display: block; padding: 0px; 
background-color: transparent; color: inherit; box-sizing: border-box; 
font-family: 'Source Code Pro', monospace;font-size:undefined; 
white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 
0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; 
word-wrap: normal; background-position: initial initial; 
background-repeat: initial initial;"><span class="hljs-pi" 
style="color: rgb(0, 102, 102); box-sizing: border-box;"><?xml 
version="1.0" encoding="utf-8"?></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">resources</span>></span><span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x1"</span>></span>1.0px<span class="hljs-tag"
 style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x2"</span>></span>2.0px<span class="hljs-tag"
 style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x3"</span>></span>3.0px<span class="hljs-tag"
 style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x4"</span>></span>4.0px<span class="hljs-tag"
 style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x5"</span>></span>5.0px<span class="hljs-tag"
 style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x6"</span>></span>6.0px<span class="hljs-tag"
 style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x7"</span>></span>7.0px<span class="hljs-tag"
 style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x8"</span>></span>8.0px<span class="hljs-tag"
 style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x9"</span>></span>9.0px<span class="hljs-tag"
 style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x10"</span>></span>10.0px<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
...省略好多行
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x300"</span>></span>300.0px<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x301"</span>></span>301.0px<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x302"</span>></span>302.0px<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x303"</span>></span>303.0px<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x304"</span>></span>304.0px<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x305"</span>></span>305.0px<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x306"</span>></span>306.0px<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x307"</span>></span>307.0px<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x308"</span>></span>308.0px<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x309"</span>></span>309.0px<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x310"</span>></span>310.0px<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x311"</span>></span>311.0px<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x312"</span>></span>312.0px<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x313"</span>></span>313.0px<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x314"</span>></span>314.0px<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x315"</span>></span>315.0px<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x316"</span>></span>316.0px<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x317"</span>></span>317.0px<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x318"</span>></span>318.0px<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x319"</span>></span>319.0px<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x320"</span>></span>320px<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">resources</span>></span></code><ul 
class="pre-numbering" style="box-sizing: border-box; position: absolute;
 width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px;
 margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; 
border-right-style: solid; border-right-color: rgb(221, 221, 221); 
list-style: none; text-align: right;"><li style="box-sizing: 
border-box; padding: 0px 5px;">1</li><li style="box-sizing: 
border-box; padding: 0px 5px;">2</li><li style="box-sizing: 
border-box; padding: 0px 5px;">3</li><li style="box-sizing: 
border-box; padding: 0px 5px;">4</li><li style="box-sizing: 
border-box; padding: 0px 5px;">5</li><li style="box-sizing: 
border-box; padding: 0px 5px;">6</li><li style="box-sizing: 
border-box; padding: 0px 5px;">7</li><li style="box-sizing: 
border-box; padding: 0px 5px;">8</li><li style="box-sizing: 
border-box; padding: 0px 5px;">9</li><li style="box-sizing: 
border-box; padding: 0px 5px;">10</li><li style="box-sizing:
 border-box; padding: 0px 5px;">11</li><li 
style="box-sizing: border-box; padding: 0px 5px;">12</li><li
 style="box-sizing: border-box; padding: 0px 
5px;">13</li><li style="box-sizing: border-box; padding: 0px
 5px;">14</li><li style="box-sizing: border-box; padding: 
0px 5px;">15</li><li style="box-sizing: border-box; padding:
 0px 5px;">16</li><li style="box-sizing: border-box; 
padding: 0px 5px;">17</li><li style="box-sizing: border-box;
 padding: 0px 5px;">18</li><li style="box-sizing: 
border-box; padding: 0px 5px;">19</li><li style="box-sizing:
 border-box; padding: 0px 5px;">20</li><li 
style="box-sizing: border-box; padding: 0px 5px;">21</li><li
 style="box-sizing: border-box; padding: 0px 
5px;">22</li><li style="box-sizing: border-box; padding: 0px
 5px;">23</li><li style="box-sizing: border-box; padding: 
0px 5px;">24</li><li style="box-sizing: border-box; padding:
 0px 5px;">25</li><li style="box-sizing: border-box; 
padding: 0px 5px;">26</li><li style="box-sizing: border-box;
 padding: 0px 5px;">27</li><li style="box-sizing: 
border-box; padding: 0px 5px;">28</li><li style="box-sizing:
 border-box; padding: 0px 5px;">29</li><li 
style="box-sizing: border-box; padding: 0px 5px;">30</li><li
 style="box-sizing: border-box; padding: 0px 
5px;">31</li><li style="box-sizing: border-box; padding: 0px
 5px;">32</li><li style="box-sizing: border-box; padding: 
0px 5px;">33</li><li style="box-sizing: border-box; padding:
 0px 5px;">34</li></ul>

那么1080*1960分辨率下是什么样子呢?我们可以看下,由于1080和320是3.37倍的关系,所以x1=3.37px

<code
 class="hljs xml has-numbering" style="display: block; padding: 0px; 
background-color: transparent; color: inherit; box-sizing: border-box; 
font-family: 'Source Code Pro', monospace;font-size:undefined; 
white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 
0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; 
word-wrap: normal; background-position: initial initial; 
background-repeat: initial initial;"><span class="hljs-pi" 
style="color: rgb(0, 102, 102); box-sizing: border-box;"><?xml 
version="1.0" encoding="utf-8"?></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">resources</span>></span><span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x1"</span>></span>3.37px<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x2"</span>></span>6.75px<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x3"</span>></span>10.12px<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x4"</span>></span>13.5px<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x5"</span>></span>16.87px<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x6"</span>></span>20.25px<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x7"</span>></span>23.62px<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x8"</span>></span>27.0px<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x9"</span>></span>30.37px<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x10"</span>></span>33.75px<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
...省略好多行
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x300"</span>></span>1012.5px<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x301"</span>></span>1015.87px<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x302"</span>></span>1019.25px<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x303"</span>></span>1022.62px<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x304"</span>></span>1026.0px<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x305"</span>></span>1029.37px<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x306"</span>></span>1032.75px<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x307"</span>></span>1036.12px<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x308"</span>></span>1039.5px<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x309"</span>></span>1042.87px<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x310"</span>></span>1046.25px<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x311"</span>></span>1049.62px<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x312"</span>></span>1053.0px<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x313"</span>></span>1056.37px<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x314"</span>></span>1059.75px<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x315"</span>></span>1063.12px<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x316"</span>></span>1066.5px<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x317"</span>></span>1069.87px<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x318"</span>></span>1073.25px<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x319"</span>></span>1076.62px<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"><<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 136);">dimen</span> <span 
class="hljs-attribute" style="box-sizing: border-box; color: rgb(102, 0,
 102);">name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"x320"</span>></span>1080px<span 
class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">dimen</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">resources</span>></span></code><ul 
class="pre-numbering" style="box-sizing: border-box; position: absolute;
 width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px;
 margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; 
border-right-style: solid; border-right-color: rgb(221, 221, 221); 
list-style: none; text-align: right;"><li style="box-sizing: 
border-box; padding: 0px 5px;">1</li><li style="box-sizing: 
border-box; padding: 0px 5px;">2</li><li style="box-sizing: 
border-box; padding: 0px 5px;">3</li><li style="box-sizing: 
border-box; padding: 0px 5px;">4</li><li style="box-sizing: 
border-box; padding: 0px 5px;">5</li><li style="box-sizing: 
border-box; padding: 0px 5px;">6</li><li style="box-sizing: 
border-box; padding: 0px 5px;">7</li><li style="box-sizing: 
border-box; padding: 0px 5px;">8</li><li style="box-sizing: 
border-box; padding: 0px 5px;">9</li><li style="box-sizing: 
border-box; padding: 0px 5px;">10</li><li style="box-sizing:
 border-box; padding: 0px 5px;">11</li><li 
style="box-sizing: border-box; padding: 0px 5px;">12</li><li
 style="box-sizing: border-box; padding: 0px 
5px;">13</li><li style="box-sizing: border-box; padding: 0px
 5px;">14</li><li style="box-sizing: border-box; padding: 
0px 5px;">15</li><li style="box-sizing: border-box; padding:
 0px 5px;">16</li><li style="box-sizing: border-box; 
padding: 0px 5px;">17</li><li style="box-sizing: border-box;
 padding: 0px 5px;">18</li><li style="box-sizing: 
border-box; padding: 0px 5px;">19</li><li style="box-sizing:
 border-box; padding: 0px 5px;">20</li><li 
style="box-sizing: border-box; padding: 0px 5px;">21</li><li
 style="box-sizing: border-box; padding: 0px 
5px;">22</li><li style="box-sizing: border-box; padding: 0px
 5px;">23</li><li style="box-sizing: border-box; padding: 
0px 5px;">24</li><li style="box-sizing: border-box; padding:
 0px 5px;">25</li><li style="box-sizing: border-box; 
padding: 0px 5px;">26</li><li style="box-sizing: border-box;
 padding: 0px 5px;">27</li><li style="box-sizing: 
border-box; padding: 0px 5px;">28</li><li style="box-sizing:
 border-box; padding: 0px 5px;">29</li><li 
style="box-sizing: border-box; padding: 0px 5px;">30</li><li
 style="box-sizing: border-box; padding: 0px 
5px;">31</li><li style="box-sizing: border-box; padding: 0px
 5px;">32</li><li style="box-sizing: border-box; padding: 
0px 5px;">33</li><li style="box-sizing: border-box; padding:
 0px 5px;">34</li></ul>

无论在什么分辨率下,x320都是代表屏幕宽度,y480都是代表屏幕高度。

那么,我们应该如何使用呢?

首先,我们要把生成的所有values文件夹放到res目录下,当设计师把UI高清设计图给你之后,你就可以根据设计图上的尺寸,以某一个分辨率的机型为基础,找到对应像素数的单位,然后设置给控件即可。

下图还是两个Button,不同的是,我们把单位换成了我们在values文件夹下dimen的值,这样在你指定的分辨率下,不管宽度是320dp、360dp,还是410dp,就都可以完全适配了。

但是,还是有个问题,为什么下面的三个没有适配呢?

这是因为由于在生成的values文件夹里,没有对应的分辨率,其实一开始是报错的,因为默认的values没有对应dimen,所以我只能在默认 values里面也创建对应文件,但是里面的数据却不好处理,因为不知道分辨率,我只好默认为x1=1dp保证尽量兼容。这也是这个解决方案的几个弊端, 对于没有生成对应分辨率文件的手机,会使用默认values文件夹,如果默认文件夹没有,就会出现问题。

所以说,这个方案虽然是一劳永逸,但是由于实际上还是使用的px作为长度的度量单位,所以多少和google的要求有所背离,不好说以后会不会出现什么不 可预测的问题。其次,如果要使用这个方案,你必须尽可能多的包含所有的分辨率,因为这个是使用这个方案的基础,如果有分辨率缺少,会造成显示效果很差,甚 至出错的风险,而这又势必会增加软件包的大小和维护的难度,所以大家自己斟酌,择优使用。

更多信息可参考鸿洋的新文章Android 屏幕适配方案

提供备用位图

由于 Android 可在具有各种屏幕密度的设备上运行,因此我们提供的位图资源应始终可以满足各类普遍密度范围的要求:低密度、中等密度、高密度以及超高密度。这将有助于我们的图片在所有屏幕密度上都能得到出色的质量和效果。

要生成这些图片,我们应先提取矢量格式的原始资源,然后根据以下尺寸范围针对各密度生成相应的图片。

  • xhdpi:2.0
  • hdpi:1.5
  • mdpi:1.0(最低要求)
  • ldpi:0.75

也就是说,如果我们为 xhdpi 设备生成了 200×200 px尺寸的图片,就应该使用同一资源为 hdpi、mdpi 和 ldpi 设备分别生成 150×150、100×100 和 75×75 尺寸的图片。

然后,将生成的图片文件放在 res/ 下的相应子目录中(mdpi、hdpi、xhdpi、xxhdpi),系统就会根据运行您应用的设备的屏幕密度自动选择合适的图片。

这样一来,只要我们引用 @drawable/id,系统都能根据相应屏幕的 dpi 选取合适的位图。

还记得我们上面提到的图标设计尺寸吗?和这个其实是一个意思。

但是还有个问题需要注意下,如果是.9图或者是不需要多个分辨率的图片,就放在drawable文件夹即可,对应分辨率的图片要正确的放在合适的文件夹,否则会造成图片拉伸等问题。

实施自适应用户界面流程

前面我们介绍过,如何根据设备特点显示恰当的布局,但是这样做,会使得用户界面流程可能会有所不同。例如,如果应用处于双面板模式下,点击左侧面板上的项 即可直接在右侧面板上显示相关内容;而如果该应用处于单面板模式下,点击相关的内容应该跳转到另外一个Activity进行后续的处理。所以我们应该按照 下面的流程,一步步的完成自适应界面的实现。

确定当前布局

由于每种布局的实施都会稍有不同,因此我们需要先确定当前向用户显示的布局。例如,我们可以先了解用户所处的是“单面板”模式还是“双面板”模式。要做到这一点,可以通过查询指定视图是否存在以及是否已显示出来。

<code
 class="hljs java has-numbering" style="display: block; padding: 0px; 
background-color: transparent; color: inherit; box-sizing: border-box; 
font-family: 'Source Code Pro', monospace;font-size:undefined; 
white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 
0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; 
word-wrap: normal; background-position: initial initial; 
background-repeat: initial initial;"><span class="hljs-keyword" 
style="color: rgb(0, 0, 136); box-sizing: 
border-box;">public</span> <span class="hljs-class" 
style="box-sizing: border-box;"><span class="hljs-keyword" 
style="color: rgb(0, 0, 136); box-sizing: 
border-box;">class</span> <span class="hljs-title" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">NewsReaderActivity</span> <span class="hljs-keyword" 
style="color: rgb(0, 0, 136); box-sizing: 
border-box;">extends</span> <span class="hljs-title" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">FragmentActivity</span> {</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); 
box-sizing: border-box;">boolean</span> mIsDualPane;

    <span class="hljs-annotation" style="color: rgb(155, 133, 157); 
box-sizing: border-box;">@Override</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); 
box-sizing: border-box;">public</span> <span 
class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: 
border-box;">void</span> <span class="hljs-title" 
style="box-sizing: border-box;">onCreate</span>(Bundle 
savedInstanceState) {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); 
box-sizing: 
border-box;">super</span>.onCreate(savedInstanceState);
        setContentView(R.layout.main_layout);

        View articleView = findViewById(R.id.article);
        mIsDualPane = articleView != <span class="hljs-keyword" 
style="color: rgb(0, 0, 136); box-sizing: 
border-box;">null</span> &&
                        articleView.getVisibility() == View.VISIBLE;
    }
}</code><ul class="pre-numbering" style="box-sizing: 
border-box; position: absolute; width: 50px; background-color: rgb(238, 
238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; 
border-right-width: 1px; border-right-style: solid; border-right-color: 
rgb(221, 221, 221); list-style: none; text-align: right;"><li 
style="box-sizing: border-box; padding: 0px 5px;">1</li><li 
style="box-sizing: border-box; padding: 0px 5px;">2</li><li 
style="box-sizing: border-box; padding: 0px 5px;">3</li><li 
style="box-sizing: border-box; padding: 0px 5px;">4</li><li 
style="box-sizing: border-box; padding: 0px 5px;">5</li><li 
style="box-sizing: border-box; padding: 0px 5px;">6</li><li 
style="box-sizing: border-box; padding: 0px 5px;">7</li><li 
style="box-sizing: border-box; padding: 0px 5px;">8</li><li 
style="box-sizing: border-box; padding: 0px 5px;">9</li><li 
style="box-sizing: border-box; padding: 0px 5px;">10</li><li
 style="box-sizing: border-box; padding: 0px 
5px;">11</li><li style="box-sizing: border-box; padding: 0px
 5px;">12</li><li style="box-sizing: border-box; padding: 
0px 5px;">13</li></ul>

请注意,这段代码用于查询“报道”面板是否可用,与针对具体布局的硬编码查询相比,这段代码的灵活性要大得多。

再举一个适应各种组件的存在情况的方法示例:在对这些组件执行操作前先查看它们是否可用。例如,新闻阅读器示例应用中有一个用于打开菜单的按钮,但只有在 版本低于 3.0 的 Android 上运行该应用时,这个按钮才会存在,因为 API 级别 11 或更高级别中的 ActionBar 已取代了该按钮的功能。因此,您可以使用以下代码为此按钮添加事件侦听器:

<code
 class="hljs avrasm has-numbering" style="display: block; padding: 0px; 
background-color: transparent; color: inherit; box-sizing: border-box; 
font-family: 'Source Code Pro', monospace;font-size:undefined; 
white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 
0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; 
word-wrap: normal; background-position: initial initial; 
background-repeat: initial initial;">Button catButton = (Button) 
findViewById(R<span class="hljs-preprocessor" style="color: rgb(68, 
68, 68); box-sizing: border-box;">.id</span><span 
class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: 
border-box;">.categorybutton</span>)<span 
class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: 
border-box;">;</span>
OnClickListener listener = <span class="hljs-comment" style="color: 
rgb(136, 0, 0); box-sizing: border-box;">/* create your listener here
 */</span><span class="hljs-comment" style="color: rgb(136, 0, 
0); box-sizing: border-box;">;</span>
if (catButton != null) {
    catButton<span class="hljs-preprocessor" style="color: rgb(68, 
68, 68); box-sizing: 
border-box;">.setOnClickListener</span>(listener)<span 
class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: 
border-box;">;</span>
}</code><ul class="pre-numbering" style="box-sizing: 
border-box; position: absolute; width: 50px; background-color: rgb(238, 
238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; 
border-right-width: 1px; border-right-style: solid; border-right-color: 
rgb(221, 221, 221); list-style: none; text-align: right;"><li 
style="box-sizing: border-box; padding: 0px 5px;">1</li><li 
style="box-sizing: border-box; padding: 0px 5px;">2</li><li 
style="box-sizing: border-box; padding: 0px 5px;">3</li><li 
style="box-sizing: border-box; padding: 0px 5px;">4</li><li 
style="box-sizing: border-box; padding: 0px 
5px;">5</li></ul>

根据当前布局做出响应

有些操作可能会因当前的具体布局而产生不同的结果。例如,在新闻阅读器示例中,如果用户界面处于双面板模式下,那么点击标题列表中的标题就会在右侧面板中打开相应报道;但如果用户界面处于单面板模式下,那么上述操作就会启动一个独立活动:

<code
 class="hljs axapta has-numbering" style="display: block; padding: 0px; 
background-color: transparent; color: inherit; box-sizing: border-box; 
font-family: 'Source Code Pro', monospace;font-size:undefined; 
white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 
0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; 
word-wrap: normal; background-position: initial initial; 
background-repeat: initial initial;">@Override
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: 
border-box;">public</span> <span class="hljs-keyword" 
style="color: rgb(0, 0, 136); box-sizing: 
border-box;">void</span> onHeadlineSelected(<span 
class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: 
border-box;">int</span> <span class="hljs-keyword" 
style="color: rgb(0, 0, 136); box-sizing: 
border-box;">index</span>) {
    mArtIndex = <span class="hljs-keyword" style="color: rgb(0, 0, 
136); box-sizing: border-box;">index</span>;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); 
box-sizing: border-box;">if</span> (mIsDualPane) {
        <span class="hljs-comment" style="color: rgb(136, 0, 0); 
box-sizing: border-box;">/* display article on the right pane 
*/</span>
        mArticleFragment.displayArticle(mCurrentCat.getArticle(<span 
class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: 
border-box;">index</span>));
    } <span class="hljs-keyword" style="color: rgb(0, 0, 136); 
box-sizing: border-box;">else</span> {
        <span class="hljs-comment" style="color: rgb(136, 0, 0); 
box-sizing: border-box;">/* start a separate activity */</span>
        Intent intent = <span class="hljs-keyword" style="color: 
rgb(0, 0, 136); box-sizing: border-box;">new</span> 
Intent(<span class="hljs-keyword" style="color: rgb(0, 0, 136); 
box-sizing: border-box;">this</span>, ArticleActivity.class);
        intent.putExtra(<span class="hljs-string" style="color: 
rgb(0, 136, 0); box-sizing: border-box;">"catIndex"</span>, 
mCatIndex);
        intent.putExtra(<span class="hljs-string" style="color: 
rgb(0, 136, 0); box-sizing: border-box;">"artIndex"</span>, 
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: 
border-box;">index</span>);
        startActivity(intent);
    }
}</code><ul class="pre-numbering" style="box-sizing: 
border-box; position: absolute; width: 50px; background-color: rgb(238, 
238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; 
border-right-width: 1px; border-right-style: solid; border-right-color: 
rgb(221, 221, 221); list-style: none; text-align: right;"><li 
style="box-sizing: border-box; padding: 0px 5px;">1</li><li 
style="box-sizing: border-box; padding: 0px 5px;">2</li><li 
style="box-sizing: border-box; padding: 0px 5px;">3</li><li 
style="box-sizing: border-box; padding: 0px 5px;">4</li><li 
style="box-sizing: border-box; padding: 0px 5px;">5</li><li 
style="box-sizing: border-box; padding: 0px 5px;">6</li><li 
style="box-sizing: border-box; padding: 0px 5px;">7</li><li 
style="box-sizing: border-box; padding: 0px 5px;">8</li><li 
style="box-sizing: border-box; padding: 0px 5px;">9</li><li 
style="box-sizing: border-box; padding: 0px 5px;">10</li><li
 style="box-sizing: border-box; padding: 0px 
5px;">11</li><li style="box-sizing: border-box; padding: 0px
 5px;">12</li><li style="box-sizing: border-box; padding: 
0px 5px;">13</li><li style="box-sizing: border-box; padding:
 0px 5px;">14</li></ul>

同样,如果该应用处于双面板模式下,就应设置带导航标签的操作栏;但如果该应用处于单面板模式下,就应使用下拉菜单设置导航栏。因此我们的代码还应确定哪种情况比较合适:

<code
 class="hljs avrasm has-numbering" style="display: block; padding: 0px; 
background-color: transparent; color: inherit; box-sizing: border-box; 
font-family: 'Source Code Pro', monospace;font-size:undefined; 
white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 
0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; 
word-wrap: normal; background-position: initial initial; 
background-repeat: initial initial;">final String CATEGORIES[] = { 
<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: 
border-box;">"热门报道"</span>, <span class="hljs-string" 
style="color: rgb(0, 136, 0); box-sizing: 
border-box;">"政治"</span>, <span class="hljs-string" 
style="color: rgb(0, 136, 0); box-sizing: 
border-box;">"经济"</span>, <span class="hljs-string" 
style="color: rgb(0, 136, 0); box-sizing: 
border-box;">"Technology"</span> }<span class="hljs-comment"
 style="color: rgb(136, 0, 0); box-sizing: 
border-box;">;</span>

public void onCreate(Bundle savedInstanceState) {
    ....
    if (mIsDualPane) {
        <span class="hljs-comment" style="color: rgb(136, 0, 0); 
box-sizing: border-box;">/* use tabs for navigation */</span>
        actionBar<span class="hljs-preprocessor" style="color: 
rgb(68, 68, 68); box-sizing: 
border-box;">.setNavigationMode</span>(android<span 
class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: 
border-box;">.app</span><span class="hljs-preprocessor" 
style="color: rgb(68, 68, 68); box-sizing: 
border-box;">.ActionBar</span><span 
class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: 
border-box;">.NAVIGATION</span>_MODE_TABS)<span 
class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: 
border-box;">;</span>
        int i<span class="hljs-comment" style="color: rgb(136, 0, 0);
 box-sizing: border-box;">;</span>
        for (i = <span class="hljs-number" style="color: rgb(0, 102, 
102); box-sizing: border-box;">0</span><span 
class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: 
border-box;">; i < CATEGORIES.length; i++) {</span>
            actionBar<span class="hljs-preprocessor" style="color: 
rgb(68, 68, 68); box-sizing: 
border-box;">.addTab</span>(actionBar<span 
class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: 
border-box;">.newTab</span>()<span class="hljs-preprocessor"
 style="color: rgb(68, 68, 68); box-sizing: 
border-box;">.setText</span>(
                CATEGORIES[i])<span class="hljs-preprocessor" 
style="color: rgb(68, 68, 68); box-sizing: 
border-box;">.setTabListener</span>(handler))<span 
class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: 
border-box;">;</span>
        }
        actionBar<span class="hljs-preprocessor" style="color: 
rgb(68, 68, 68); box-sizing: 
border-box;">.setSelectedNavigationItem</span>(selTab)<span 
class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: 
border-box;">;</span>
    }
    else {
        <span class="hljs-comment" style="color: rgb(136, 0, 0); 
box-sizing: border-box;">/* use list navigation (spinner) 
*/</span>
        actionBar<span class="hljs-preprocessor" style="color: 
rgb(68, 68, 68); box-sizing: 
border-box;">.setNavigationMode</span>(android<span 
class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: 
border-box;">.app</span><span class="hljs-preprocessor" 
style="color: rgb(68, 68, 68); box-sizing: 
border-box;">.ActionBar</span><span 
class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: 
border-box;">.NAVIGATION</span>_MODE_LIST)<span 
class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: 
border-box;">;</span>
        SpinnerAdapter adap = new ArrayAdapter(this,
                R<span class="hljs-preprocessor" style="color: 
rgb(68, 68, 68); box-sizing: 
border-box;">.layout</span><span class="hljs-preprocessor" 
style="color: rgb(68, 68, 68); box-sizing: 
border-box;">.headline</span>_item, CATEGORIES)<span 
class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: 
border-box;">;</span>
        actionBar<span class="hljs-preprocessor" style="color: 
rgb(68, 68, 68); box-sizing: 
border-box;">.setListNavigationCallbacks</span>(adap, 
handler)<span class="hljs-comment" style="color: rgb(136, 0, 0); 
box-sizing: border-box;">;</span>
    }
}</code><ul class="pre-numbering" style="box-sizing: 
border-box; position: absolute; width: 50px; background-color: rgb(238, 
238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; 
border-right-width: 1px; border-right-style: solid; border-right-color: 
rgb(221, 221, 221); list-style: none; text-align: right;"><li 
style="box-sizing: border-box; padding: 0px 5px;">1</li><li 
style="box-sizing: border-box; padding: 0px 5px;">2</li><li 
style="box-sizing: border-box; padding: 0px 5px;">3</li><li 
style="box-sizing: border-box; padding: 0px 5px;">4</li><li 
style="box-sizing: border-box; padding: 0px 5px;">5</li><li 
style="box-sizing: border-box; padding: 0px 5px;">6</li><li 
style="box-sizing: border-box; padding: 0px 5px;">7</li><li 
style="box-sizing: border-box; padding: 0px 5px;">8</li><li 
style="box-sizing: border-box; padding: 0px 5px;">9</li><li 
style="box-sizing: border-box; padding: 0px 5px;">10</li><li
 style="box-sizing: border-box; padding: 0px 
5px;">11</li><li style="box-sizing: border-box; padding: 0px
 5px;">12</li><li style="box-sizing: border-box; padding: 
0px 5px;">13</li><li style="box-sizing: border-box; padding:
 0px 5px;">14</li><li style="box-sizing: border-box; 
padding: 0px 5px;">15</li><li style="box-sizing: border-box;
 padding: 0px 5px;">16</li><li style="box-sizing: 
border-box; padding: 0px 5px;">17</li><li style="box-sizing:
 border-box; padding: 0px 5px;">18</li><li 
style="box-sizing: border-box; padding: 0px 5px;">19</li><li
 style="box-sizing: border-box; padding: 0px 
5px;">20</li><li style="box-sizing: border-box; padding: 0px
 5px;">21</li><li style="box-sizing: border-box; padding: 
0px 5px;">22</li></ul>

重复使用其他活动中的片段

多屏幕设计中的重复模式是指,对于某些屏幕配置,已实施界面的一部分会用作面板;但对于其他配置,这部分就会以独立活动的形式存在。例如,在新闻阅读器示例中,对于较大的屏幕,新闻报道文本会显示在右侧面板中;但对于较小的屏幕,这些文本就会以独立活动的形式存在。

在类似情况下,通常可以在多个活动中重复使用相同的 Fragment 子类以避免代码重复。例如,在双面板布局中使用了 ArticleFragment:

<code
 class="hljs xml has-numbering" style="display: block; padding: 0px; 
background-color: transparent; color: inherit; box-sizing: border-box; 
font-family: 'Source Code Pro', monospace;font-size:undefined; 
white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 
0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; 
word-wrap: normal; background-position: initial initial; 
background-repeat: initial initial;"><span class="hljs-tag" 
style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span
 class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 
136);">LinearLayout</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">xmlns:android</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"http://schemas.android.com/apk/res/android"</span>
    <span class="hljs-attribute" style="box-sizing: border-box; 
color: rgb(102, 0, 102);">android:layout_width</span>=<span 
class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"fill_parent"</span>
    <span class="hljs-attribute" style="box-sizing: border-box; 
color: rgb(102, 0, 102);">android:layout_height</span>=<span
 class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"fill_parent"</span>
    <span class="hljs-attribute" style="box-sizing: border-box; 
color: rgb(102, 0, 102);">android:orientation</span>=<span 
class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"horizontal"</span>></span>
    <span class="hljs-tag" style="color: rgb(0, 102, 102); 
box-sizing: border-box;"><<span class="hljs-title" 
style="box-sizing: border-box; color: rgb(0, 0, 
136);">fragment</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">android:id</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"@+id/headlines"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_height</span>=<span class="hljs-value"
 style="box-sizing: border-box; color: rgb(0, 136, 
0);">"fill_parent"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"com.example.android.newsreader.HeadlinesFragment"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_width</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"400dp"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_marginRight</span>=<span 
class="hljs-value" style="box-sizing: border-box; color: rgb(0, 136, 
0);">"10dp"</span>/></span>
    <span class="hljs-tag" style="color: rgb(0, 102, 102); 
box-sizing: border-box;"><<span class="hljs-title" 
style="box-sizing: border-box; color: rgb(0, 0, 
136);">fragment</span> <span class="hljs-attribute" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">android:id</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"@+id/article"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_height</span>=<span class="hljs-value"
 style="box-sizing: border-box; color: rgb(0, 136, 
0);">"fill_parent"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:name</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"com.example.android.newsreader.ArticleFragment"</span>
              <span class="hljs-attribute" style="box-sizing: 
border-box; color: rgb(102, 0, 
102);">android:layout_width</span>=<span class="hljs-value" 
style="box-sizing: border-box; color: rgb(0, 136, 
0);">"fill_parent"</span> /></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: 
border-box;"></<span class="hljs-title" style="box-sizing: 
border-box; color: rgb(0, 0, 
136);">LinearLayout</span>></span></code><ul 
class="pre-numbering" style="box-sizing: border-box; position: absolute;
 width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px;
 margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; 
border-right-style: solid; border-right-color: rgb(221, 221, 221); 
list-style: none; text-align: right;"><li style="box-sizing: 
border-box; padding: 0px 5px;">1</li><li style="box-sizing: 
border-box; padding: 0px 5px;">2</li><li style="box-sizing: 
border-box; padding: 0px 5px;">3</li><li style="box-sizing: 
border-box; padding: 0px 5px;">4</li><li style="box-sizing: 
border-box; padding: 0px 5px;">5</li><li style="box-sizing: 
border-box; padding: 0px 5px;">6</li><li style="box-sizing: 
border-box; padding: 0px 5px;">7</li><li style="box-sizing: 
border-box; padding: 0px 5px;">8</li><li style="box-sizing: 
border-box; padding: 0px 5px;">9</li><li style="box-sizing: 
border-box; padding: 0px 5px;">10</li><li style="box-sizing:
 border-box; padding: 0px 5px;">11</li><li 
style="box-sizing: border-box; padding: 0px 5px;">12</li><li
 style="box-sizing: border-box; padding: 0px 
5px;">13</li><li style="box-sizing: border-box; padding: 0px
 5px;">14</li></ul>

然后又在小屏幕的Activity布局中重复使用了它 :

<code
 class="hljs avrasm has-numbering" style="display: block; padding: 0px; 
background-color: transparent; color: inherit; box-sizing: border-box; 
font-family: 'Source Code Pro', monospace;font-size:undefined; 
white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 
0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; 
word-wrap: normal; background-position: initial initial; 
background-repeat: initial initial;">ArticleFragment frag = new 
ArticleFragment()<span class="hljs-comment" style="color: rgb(136, 0,
 0); box-sizing: border-box;">;</span>
getSupportFragmentManager()<span class="hljs-preprocessor" 
style="color: rgb(68, 68, 68); box-sizing: 
border-box;">.beginTransaction</span>()<span 
class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: 
border-box;">.add</span>(android<span 
class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: 
border-box;">.R</span><span class="hljs-preprocessor" 
style="color: rgb(68, 68, 68); box-sizing: 
border-box;">.id</span><span class="hljs-preprocessor" 
style="color: rgb(68, 68, 68); box-sizing: 
border-box;">.content</span>, frag)<span 
class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: 
border-box;">.commit</span>()<span class="hljs-comment" 
style="color: rgb(136, 0, 0); box-sizing: 
border-box;">;</span></code><ul class="pre-numbering" 
style="box-sizing: border-box; position: absolute; width: 50px; 
background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; 
padding: 6px 0px 40px; border-right-width: 1px; border-right-style: 
solid; border-right-color: rgb(221, 221, 221); list-style: none; 
text-align: right;"><li style="box-sizing: border-box; padding: 
0px 5px;">1</li><li style="box-sizing: border-box; padding: 
0px 5px;">2</li></ul>

当然,这与在 XML 布局中声明片段的效果是一样的,但在这种情况下却没必要使用 XML 布局,因为报道片段是此活动中的唯一组件。

请务必在设计片段时注意,不要针对具体活动创建强耦合。要做到这一点,通常可以定义一个接口,该接口概括了相关片段与其主活动交互所需的全部方式,然后让主活动实施该界面:

例如,新闻阅读器应用的 HeadlinesFragment 会精确执行以下代码:

<code
 class="hljs java has-numbering" style="display: block; padding: 0px; 
background-color: transparent; color: inherit; box-sizing: border-box; 
font-family: 'Source Code Pro', monospace;font-size:undefined; 
white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 
0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; 
word-wrap: normal; background-position: initial initial; 
background-repeat: initial initial;"><span class="hljs-keyword" 
style="color: rgb(0, 0, 136); box-sizing: 
border-box;">public</span> <span class="hljs-class" 
style="box-sizing: border-box;"><span class="hljs-keyword" 
style="color: rgb(0, 0, 136); box-sizing: 
border-box;">class</span> <span class="hljs-title" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">HeadlinesFragment</span> <span class="hljs-keyword" 
style="color: rgb(0, 0, 136); box-sizing: 
border-box;">extends</span> <span class="hljs-title" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">ListFragment</span> {</span>
    ...
    OnHeadlineSelectedListener mHeadlineSelectedListener = <span 
class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: 
border-box;">null</span>;

    <span class="hljs-comment" style="color: rgb(136, 0, 0); 
box-sizing: border-box;">/* Must be implemented by host activity 
*/</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); 
box-sizing: border-box;">public</span> <span 
class="hljs-class" style="box-sizing: border-box;"><span 
class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: 
border-box;">interface</span> <span class="hljs-title" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">OnHeadlineSelectedListener</span> {</span>
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); 
box-sizing: border-box;">public</span> <span 
class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: 
border-box;">void</span> <span class="hljs-title" 
style="box-sizing: 
border-box;">onHeadlineSelected</span>(<span 
class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: 
border-box;">int</span> index);
    }
    ...

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); 
box-sizing: border-box;">public</span> <span 
class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: 
border-box;">void</span> <span class="hljs-title" 
style="box-sizing: 
border-box;">setOnHeadlineSelectedListener</span>(OnHeadlineSelectedListener
 listener) {
        mHeadlineSelectedListener = listener;
    }
}</code><ul class="pre-numbering" style="box-sizing: 
border-box; position: absolute; width: 50px; background-color: rgb(238, 
238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; 
border-right-width: 1px; border-right-style: solid; border-right-color: 
rgb(221, 221, 221); list-style: none; text-align: right;"><li 
style="box-sizing: border-box; padding: 0px 5px;">1</li><li 
style="box-sizing: border-box; padding: 0px 5px;">2</li><li 
style="box-sizing: border-box; padding: 0px 5px;">3</li><li 
style="box-sizing: border-box; padding: 0px 5px;">4</li><li 
style="box-sizing: border-box; padding: 0px 5px;">5</li><li 
style="box-sizing: border-box; padding: 0px 5px;">6</li><li 
style="box-sizing: border-box; padding: 0px 5px;">7</li><li 
style="box-sizing: border-box; padding: 0px 5px;">8</li><li 
style="box-sizing: border-box; padding: 0px 5px;">9</li><li 
style="box-sizing: border-box; padding: 0px 5px;">10</li><li
 style="box-sizing: border-box; padding: 0px 
5px;">11</li><li style="box-sizing: border-box; padding: 0px
 5px;">12</li><li style="box-sizing: border-box; padding: 
0px 5px;">13</li><li style="box-sizing: border-box; padding:
 0px 5px;">14</li></ul>

然后,如果用户选择某个标题,相关片段就会通知由主活动指定的侦听器(而不是通知某个硬编码的具体活动):

<code
 class="hljs java has-numbering" style="display: block; padding: 0px; 
background-color: transparent; color: inherit; box-sizing: border-box; 
font-family: 'Source Code Pro', monospace;font-size:undefined; 
white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 
0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; 
word-wrap: normal; background-position: initial initial; 
background-repeat: initial initial;"><span class="hljs-keyword" 
style="color: rgb(0, 0, 136); box-sizing: 
border-box;">public</span> <span class="hljs-class" 
style="box-sizing: border-box;"><span class="hljs-keyword" 
style="color: rgb(0, 0, 136); box-sizing: 
border-box;">class</span> <span class="hljs-title" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">HeadlinesFragment</span> <span class="hljs-keyword" 
style="color: rgb(0, 0, 136); box-sizing: 
border-box;">extends</span> <span class="hljs-title" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">ListFragment</span> {</span>
    ...
    <span class="hljs-annotation" style="color: rgb(155, 133, 157); 
box-sizing: border-box;">@Override</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); 
box-sizing: border-box;">public</span> <span 
class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: 
border-box;">void</span> <span class="hljs-title" 
style="box-sizing: 
border-box;">onItemClick</span>(AdapterView<?> parent,
                            View view, <span class="hljs-keyword" 
style="color: rgb(0, 0, 136); box-sizing: 
border-box;">int</span> position, <span class="hljs-keyword"
 style="color: rgb(0, 0, 136); box-sizing: 
border-box;">long</span> id) {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); 
box-sizing: border-box;">if</span> (<span 
class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: 
border-box;">null</span> != mHeadlineSelectedListener) {
            mHeadlineSelectedListener.onHeadlineSelected(position);
        }
    }
    ...
}</code><ul class="pre-numbering" style="box-sizing: 
border-box; position: absolute; width: 50px; background-color: rgb(238, 
238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; 
border-right-width: 1px; border-right-style: solid; border-right-color: 
rgb(221, 221, 221); list-style: none; text-align: right;"><li 
style="box-sizing: border-box; padding: 0px 5px;">1</li><li 
style="box-sizing: border-box; padding: 0px 5px;">2</li><li 
style="box-sizing: border-box; padding: 0px 5px;">3</li><li 
style="box-sizing: border-box; padding: 0px 5px;">4</li><li 
style="box-sizing: border-box; padding: 0px 5px;">5</li><li 
style="box-sizing: border-box; padding: 0px 5px;">6</li><li 
style="box-sizing: border-box; padding: 0px 5px;">7</li><li 
style="box-sizing: border-box; padding: 0px 5px;">8</li><li 
style="box-sizing: border-box; padding: 0px 5px;">9</li><li 
style="box-sizing: border-box; padding: 0px 5px;">10</li><li
 style="box-sizing: border-box; padding: 0px 
5px;">11</li></ul>

除此之外,我们还可以使用第三方框架,比如说使用“订阅-发布”模式的EventBus来更多的优化组件之间的通信,减少耦合。

处理屏幕配置变化

如果我们使用独立Activity实施界面的独立部分,那么请注意,我们可能需要对特定配置变化(例如屏幕方向的变化)做出响应,以便保持界面的一致性。

例如,在运行 Android 3.0 或更高版本的标准 7 英寸平板电脑上,如果新闻阅读器示例应用运行在纵向模式下,就会在使用独立活动显示新闻报道;但如果该应用运行在横向模式下,就会使用双面板布局。

也就是说,如果用户处于纵向模式下且屏幕上显示的是用于阅读报道的活动,那么就需要在检测到屏幕方向变化(变成横向模式)后执行相应操作,即停止上述活动并返回主活动,以便在双面板布局中显示相关内容:

<code
 class="hljs java has-numbering" style="display: block; padding: 0px; 
background-color: transparent; color: inherit; box-sizing: border-box; 
font-family: 'Source Code Pro', monospace;font-size:undefined; 
white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 
0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; 
word-wrap: normal; background-position: initial initial; 
background-repeat: initial initial;"><span class="hljs-keyword" 
style="color: rgb(0, 0, 136); box-sizing: 
border-box;">public</span> <span class="hljs-class" 
style="box-sizing: border-box;"><span class="hljs-keyword" 
style="color: rgb(0, 0, 136); box-sizing: 
border-box;">class</span> <span class="hljs-title" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">ArticleActivity</span> <span class="hljs-keyword" 
style="color: rgb(0, 0, 136); box-sizing: 
border-box;">extends</span> <span class="hljs-title" 
style="box-sizing: border-box; color: rgb(102, 0, 
102);">FragmentActivity</span> {</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); 
box-sizing: border-box;">int</span> mCatIndex, mArtIndex;

    <span class="hljs-annotation" style="color: rgb(155, 133, 157); 
box-sizing: border-box;">@Override</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); 
box-sizing: border-box;">protected</span> <span 
class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: 
border-box;">void</span> <span class="hljs-title" 
style="box-sizing: border-box;">onCreate</span>(Bundle 
savedInstanceState) {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); 
box-sizing: 
border-box;">super</span>.onCreate(savedInstanceState);
        mCatIndex = getIntent().getExtras().getInt(<span 
class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: 
border-box;">"catIndex"</span>, <span class="hljs-number" 
style="color: rgb(0, 102, 102); box-sizing: 
border-box;">0</span>);
        mArtIndex = getIntent().getExtras().getInt(<span 
class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: 
border-box;">"artIndex"</span>, <span class="hljs-number" 
style="color: rgb(0, 102, 102); box-sizing: 
border-box;">0</span>);

        <span class="hljs-comment" style="color: rgb(136, 0, 0); 
box-sizing: border-box;">// If should be in two-pane mode, finish to 
return to main activity</span>
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); 
box-sizing: border-box;">if</span> 
(getResources().getBoolean(R.bool.has_two_panes)) {
            finish();
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); 
box-sizing: border-box;">return</span>;
        }
        ...
}</code><ul class="pre-numbering" style="box-sizing: 
border-box; position: absolute; width: 50px; background-color: rgb(238, 
238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; 
border-right-width: 1px; border-right-style: solid; border-right-color: 
rgb(221, 221, 221); list-style: none; text-align: right;"><li 
style="box-sizing: border-box; padding: 0px 5px;">1</li><li 
style="box-sizing: border-box; padding: 0px 5px;">2</li><li 
style="box-sizing: border-box; padding: 0px 5px;">3</li><li 
style="box-sizing: border-box; padding: 0px 5px;">4</li><li 
style="box-sizing: border-box; padding: 0px 5px;">5</li><li 
style="box-sizing: border-box; padding: 0px 5px;">6</li><li 
style="box-sizing: border-box; padding: 0px 5px;">7</li><li 
style="box-sizing: border-box; padding: 0px 5px;">8</li><li 
style="box-sizing: border-box; padding: 0px 5px;">9</li><li 
style="box-sizing: border-box; padding: 0px 5px;">10</li><li
 style="box-sizing: border-box; padding: 0px 
5px;">11</li><li style="box-sizing: border-box; padding: 0px
 5px;">12</li><li style="box-sizing: border-box; padding: 
0px 5px;">13</li><li style="box-sizing: border-box; padding:
 0px 5px;">14</li><li style="box-sizing: border-box; 
padding: 0px 5px;">15</li><li style="box-sizing: border-box;
 padding: 0px 5px;">16</li></ul>

通过上面几个步骤,我们就完全可以建立一个可以根据用户界面配置进行自适应的App了。

最佳实践

关于高清设计图尺寸

Google官方给出的高清设计图尺寸有两种方案,一种是以mdpi设计,然后对应放大得到更高分辨率的图片,另外一种则是以高分辨率作为设计大小,然后按照倍数对应缩小到小分辨率的图片。

根据经验,我更推荐第二种方法,因为小分辨率在生成高分辨率图片的时候,会出现像素丢失,我不知道是不是有方法可以阻止这种情况发生。

而分辨率可以以1280*720或者是1960*1080作为主要分辨率进行设计。

ImageView的ScaleType属性

设置不同的ScaleType会得到不同的显示效果,一般情况下,设置为centerCrop能获得较好的适配效果。

动态设置

有一些情况下,我们需要动态的设置控件大小或者是位置,比如说popwindow的显示位置和偏移量等,这个时候我们可以动态的获取当前的屏幕属性,然后设置合适的数值

<code
 class="hljs cs has-numbering" style="display: block; padding: 0px; 
background-color: transparent; color: inherit; box-sizing: border-box; 
font-family: 'Source Code Pro', monospace;font-size:undefined; 
white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 
0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; 
word-wrap: normal; background-position: initial initial; 
background-repeat: initial initial;"><span class="hljs-keyword" 
style="color: rgb(0, 0, 136); box-sizing: 
border-box;">public</span> <span class="hljs-keyword" 
style="color: rgb(0, 0, 136); box-sizing: 
border-box;">class</span> ScreenSizeUtil {

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); 
box-sizing: border-box;">public</span> <span 
class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: 
border-box;">static</span> <span class="hljs-keyword" 
style="color: rgb(0, 0, 136); box-sizing: 
border-box;">int</span> <span class="hljs-title" 
style="box-sizing: border-box;">getScreenWidth</span>(Activity 
activity) {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); 
box-sizing: border-box;">return</span> 
activity.getWindowManager().getDefaultDisplay().getWidth();
    }

    <span class="hljs-keyword" style="color: rgb(0, 0, 136); 
box-sizing: border-box;">public</span> <span 
class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: 
border-box;">static</span> <span class="hljs-keyword" 
style="color: rgb(0, 0, 136); box-sizing: 
border-box;">int</span> <span class="hljs-title" 
style="box-sizing: border-box;">getScreenHeight</span>(Activity
 activity) {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); 
box-sizing: border-box;">return</span> 
activity.getWindowManager().getDefaultDisplay().getHeight();
    }

}</code><ul class="pre-numbering" style="box-sizing: 
border-box; position: absolute; width: 50px; background-color: rgb(238, 
238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; 
border-right-width: 1px; border-right-style: solid; border-right-color: 
rgb(221, 221, 221); list-style: none; text-align: right;"><li 
style="box-sizing: border-box; padding: 0px 5px;">1</li><li 
style="box-sizing: border-box; padding: 0px 5px;">2</li><li 
style="box-sizing: border-box; padding: 0px 5px;">3</li><li 
style="box-sizing: border-box; padding: 0px 5px;">4</li><li 
style="box-sizing: border-box; padding: 0px 5px;">5</li><li 
style="box-sizing: border-box; padding: 0px 5px;">6</li><li 
style="box-sizing: border-box; padding: 0px 5px;">7</li><li 
style="box-sizing: border-box; padding: 0px 5px;">8</li><li 
style="box-sizing: border-box; padding: 0px 5px;">9</li><li 
style="box-sizing: border-box; padding: 0px 5px;">10</li><li
 style="box-sizing: border-box; padding: 0px 
5px;">11</li></ul>

更多参考资料

如何安装Eclipse WTP插件_chuansir_新浪博客,chuansir,

mikel阅读(814)

如何安装Eclipse WTP插件_chuansir_新浪博客,chuansir,

1.打开如下网页:http://www.eclipse.org/webtools/,找到需要安装的WTP版本

2.点开相应的版本链接,点击“Download”

3.打开具体版本的网页链接

4.注意如下几项:

  Required Prerequisites and Handy Extras   安装WTP的先决条件及便利的扩展

    Eclipse Platform (Platform, JDT)

    EMF v2.4 Runtime Minimum executable code.

    EMF XSD v2.4 Runtime Minimum executable code.

    Graphical Editing Framework (GEF)

    Data Tools Platform (DTP) (required only for EJB or JPT development)

    —————————————————————————————————–

   EMF v2.4 Source and Docs Additional download with Source and Documentation.

   EMF XSD v2.4 Source and Docs Additional download with Source and Documentation.

   Eclipse Test Framework (required only for Automated JUnit tests)

   Eclipse releng tool (required only for committers to more easily “release” code to a build)

   Third Party code from Orbit. Not required and is currently much more than needed for WTP, but    some committers like using to create a PDE target.

   Web Tools Platform Complete                      Web 工具平台

Web App Developers: This non-SDK package is for most users. It includes the runnable code and end-user documentation for those using the tools to develop web applications.

Tool Developers: The SDK package includes source code and developer documentation for those using WTP as a platform to build more tools, as well as everything that is in the non-SDK version.

                                The Automated Test zip contains the unit tests.

      

   Web Standard Tools                                     Web标准工具

Web App Developers: This non-SDK package is for most users. It includes the runnable code and end-user documentation for those using the tools to develop web applications. In particular, non-Java oriented Web Apps (such as HTML, XML, CSS, etc).

Tool Developers: The SDK package includes source code and developer documentation for those using WST as a platform to build more tools, as well as everything that is in the non-SDK version.

The Automated Test zip contains the unit tests.

             

以上三项包括了安装WTP所需要的全部软件及插件。

安装步骤及建议

1.安装java开发环境,jdk1.5以上。

2.安装Eclipse开发环境

3.安装Required Prerequisites and Handy Extras下的插件,解压压缩包中的plugins、features目录下的文件到Eclipse安装目录下的plugins、features目录下即可。

注意Eclipse的不同版本要求相应版本的插件,否则插件不能正常使用。

4.安装Web Tools Platform Complete 、Web Standard Tools下的插件。

5.官方网站提供了在Eclipse开发平台下,在线安装WTP的方法

   If you are just getting started with Eclipse or Eclipse Web Tools, you may want to first install from the Ganymede update site, as it would have everything you need to get started.

This Web Tools Platform update site does assume you have all the pre-reqs installed.(在安装WTP之前必须安装Required Prerequisites and Handy Extras 中的Required Prerequisites部分。

Beyond the basic Web Tools Platform, this site offers the SDK version of Web Tools and also the XSL Incubating Component.

To use this update site in your existing installation of Eclipse, add the following URL as a remote update site in your update manager, if it does not already have it.

    http://download.eclipse.org/webtools/updates/