android 平板适配

首次进行平板开发,从一开始就在琢磨适配是怎么弄的,百度、google、群一大圈,还是没人告诉具体是怎么做的,都是基本的概念性的讲述怎么适配,写了一个界面发现存在很大适配问题,最后找到了几篇有价值的博客,文章末尾有链接;

先了解点基本概念:

px:pixel,像素,电子屏幕上组成一幅图画或照片的最基本单元;

dip : Density independent pixels ,设备无关像素,是安卓开发用的长度单位,1dp表示在屏幕像素点密度为160ppi时1px长度;

dp :就是dip;

sp: scale-independent pixel,安卓开发用的字体大小单位,一般情况下可认为sp=dp;

pt: point,点,印刷行业常用单位,等于1/72英寸,ios也适用这个作为大小单位;

ppi: pixel per inch,每英寸像素数,该值越高,则屏幕越细腻;

dpi :dots per inch , 直接来说就是一英寸多少个像素点。常见取值 120,160,240。我一般称作像素密度,简称密度;

density : 直接翻译的话貌似叫 密度。常见取值 1.5 , 1.0 。和标准dpi的比例(160px/inc);

分辨率 : 横纵2个方向的像素点的数量,常见取值 480X800 ,320X480;

这里引用文档的屏幕尺寸限定符描述:

官方文档:https://developer.android.com/guide/practices/screens_support

新的屏幕尺寸限定符(Android3.2 之后引入)

屏幕特性

限定符

描述

最小宽度限定符

sw<N>dp

例如sw600dp, sw720dp

屏幕的最小尺寸,就是屏幕可用区域的最小尺寸,是指屏幕可用高度或宽度的最小值(你可以默认是屏幕的最小宽度).你能用这个限定符确保,无论屏幕方向如何,这个限定符修饰下的布局需要的屏幕最小尺寸是Ndp.

例如,如果你的布局在运行时需要的最小屏幕宽度是600dp,则你可以利用这个限定符创建布局资源目录res/layout-sw600dp.只有当屏幕的最小宽度或最小高度是600dp时,系统才会使用这些布局文件或者资源文件.最小屏幕宽度是固定设备的特有屏幕尺寸,当屏幕方向发生变化时,设备的最小宽度值不变.

设备的最小宽度值要考虑屏幕的尺寸和系统UI.例如,如果在屏幕上有一些系统持久化UI元素,则系统的最小宽度值要比实现的屏幕尺寸小一些,因为这些系统的UI元素你的应用是无法使用到的.

当你使用之前的广义限定符是,你可以定义连续的一系列限定符.用最小宽度来决定广义屏幕尺寸是有意义的,是因为宽度是影响你UI设计的关键因素.UI在竖直方向上会经常滚动,但是在水平方向上往往是固定的布局.可见不论是适配手机或者平板,宽度往往都是布局的关键因素.因此,你需要关心你手机上的最小宽度值.

屏幕可用宽度

w<N>dp

Examples:

w720p

w1024p

指定资源使用时需要的最小宽度.当屏幕方向发生变化时,系统会调整这个值,使其始终为你UI显示的宽度.

这个属性经常被用来判断当前是否需要显示多屏布局,因为哪怕用户当前正在使用平板,你也可能不希望用户在平板竖屏时显示多个屏幕的布局样式.这时,你就可以使用这个限定符来标明你布局需要的最小宽度

屏幕可用高度

h<N>dp

Examples:

h720dp

h1024dp

etc.

标明资源使用时需要的最小高度.当屏幕发生旋转时,系统会自动选择当前大的一方作为高度值.大部分应用很少需要这个限定符,因此不做过多讲解

我的项目中建立这么几个values文件夹存放dimens(我的项目强制使用横屏,所以后面加了-land),那具体设备是获得那一个文件夹的尺寸呢?每一个文件夹中的尺寸一样吗?难道需要自己创建这么多文件夹里面的dimens文件慢慢添加吗?

如果横竖屏、不同屏幕设备有不同布局界面,也可以对应创建不同的layout文件夹;

第一问题:获取那个文件夹下的资源:

通过公式 sw*160/dpi 计算出结果之后,选择一个比这个结果小,而又最接近这个值的dp(即文件夹下的内容)。

sw*160/dpi计算示例:

比如

分辨率1280*800, sw 是800

分辨率1920*1080, sw 是1080

dpi获取方法:

1、 adb shell getprop ro.sf.lcd_density 获得

2、代码中

DisplayMetrics dm = new DisplayMetrics();

getWindowManager().getDefaultDisplay().getMetrics(dm);

int  dpi = dm.density*160;

       分辨率

sw

   dpi= ro.sf.lcd_density  

         sw *160/dpi    =  dp

1280*720     

720

213     

720*160/213=540.84 =       sw480dp

1280*800

800

320

800*160/320=400 =       sw340dp

1024*768     

768

160    

768*160/160 =768 =            sw720dp

800*480      

480

120      

480*160/120 =640=             sw600dp

800*480    

480

160    

480*160/160 =480=             sw480dp

比如第一条数据,计算sw*160/dpi的值是540.84,就会去找sw540的文件夹资源,找不到就会向下找,找到sw480dp的文件夹

第二个问题:每一个文件夹中的尺寸一样吗?难道需要自己创建这么多文件夹里面的dimens文件慢慢添加吗?一会回答

里面的值肯定不一样,也不需要一个一个计算一个一个添加,创建一个类DimenTool,自动帮你计算同步;

注意⚠️:要添加dp和sp只需要在values文件夹下的dimens文件添加,然后运行DimenTool工具类即可达到同步(可以根据自己需要的尺寸在DimenTool类中修改,里面的换算比例暂时还不知道是怎么换算来的,引用时注意下,网上有很多不同的换算比例)

/**
 * Created by zyt on 2018/7/11.
 * 自动计算dimens的工具
 */

public class DimenTool {

    public static void gen() {

        File file = new File("./app/src/main/res/values/dimens.xml");
        BufferedReader reader = null;
        StringBuilder sw480 = new StringBuilder();
        StringBuilder sw600 = new StringBuilder();
        StringBuilder sw720 = new StringBuilder();
        StringBuilder sw800 = new StringBuilder();
        StringBuilder w820 = new StringBuilder();


        try {
            System.out.println("生成不同分辨率:");
            reader = new BufferedReader(new FileReader(file));
            String tempString;
            int line = 1;
            // 一次读入一行,直到读入null为文件结束

            while ((tempString = reader.readLine()) != null) {

                if (tempString.contains("</dimen>")) {
                    //tempString = tempString.replaceAll(" ", "");
                    String start = tempString.substring(0, tempString.indexOf(">") + 1);
                    String end = tempString.substring(tempString.lastIndexOf("<") - 2);
                    double num = Double.valueOf(tempString.substring(tempString.indexOf(">") + 1, tempString.indexOf("</dimen>") - 2));
//这里的换算比例现在还不知道为什么是这样,等找到了在更新上来
                    sw480.append(start).append((int) Math.round(num * 0.6)).append(end).append("\n");
                    sw600.append(start).append((int) Math.round(num * 0.75)).append(end).append("\n");
                    sw720.append(start).append((int) Math.round(num * 0.9)).append(end).append("\n");
                    sw800.append(tempString).append("\n");
                    w820.append(tempString).append("\n");

                } else {
                    sw480.append(tempString).append("\n");
                    sw600.append(tempString).append("\n");
                    sw720.append(tempString).append("\n");
                    sw800.append(tempString).append("\n");
                    w820.append(tempString).append("\n");
                }
                line++;
            }
            reader.close();
            System.out.println("<!--  sw480 -->");
            System.out.println(sw480);
            System.out.println("<!--  sw600 -->");
            System.out.println(sw600);

            System.out.println("<!--  sw720 -->");
            System.out.println(sw720);
            System.out.println("<!--  sw800 -->");
            System.out.println(sw800);

            String sw480file = "./app/src/main/res/values-sw480dp-land/dimens.xml";
            String sw600file = "./app/src/main/res/values-sw600dp-land/dimens.xml";
            String sw720file = "./app/src/main/res/values-sw720dp-land/dimens.xml";
            String sw800file = "./app/src/main/res/values-sw800dp-land/dimens.xml";
            String w820file = "./app/src/main/res/values-w820dp/dimens.xml";
            writeFile(sw480file, sw480.toString());
            writeFile(sw600file, sw600.toString());
            writeFile(sw720file, sw720.toString());
            writeFile(sw800file, sw800.toString());
            writeFile(w820file, w820.toString());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
        }
    }

    public static void writeFile(String file, String text) {
        PrintWriter out = null;
        try {
            out = new PrintWriter(new BufferedWriter(new FileWriter(file)));
            out.println(text);
        } catch (IOException e) {
            e.printStackTrace();
        }

        out.close();
    }

    public static void main(String[] args) {
        gen();
    }
}

最后再补充一些其他适配知识:

我们常说的mdpi、hdpi、xhdpi、xxhdpi、xxxhdpi对应使用的是多少像素密度呢,看下图:

应用启动图标的适配

至少要提供一个xxxhdpi类型的启动图标,因为Android会帮你自动缩小图标到对应的别的分辨率上(放大是会变模糊的)

最后直接推荐使用今日头条的android适配终极武器(修改手机的设备密度 density):

https://github.com/JessYanCoding/AndroidAutoSize

关于比较好的一篇博客:骚年你的屏幕适配方式该升级了!-今日头条适配方案 - 掘金

参考链接:

Android(density屏幕密度)_hhuleaves的博客-CSDN博客_ro.sf.lcd_density

最清晰的Android多屏幕适配方案 - soaringEveryday - 博客园

Android开发中如何获得正确的layout资源(layout-sw480dp layout-sw600dp-land layout-sw720dp-port)_Felix.Ma的博客-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值