zoukankan      html  css  js  c++  java
  • Android屏幕适配讲解与实战(原创)

    文章大纲

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

     

    一、屏幕适配是什么

      Android中屏幕适配就是通过对尺寸单位、图片、文字、布局这四种类型的资源进行合理的设计和规划,在布局时合理利用各种类型的资源,让布局拥有适应能力,能在各种设备下保持良好的展现效果。

    二、常见屏幕适配方法介绍

    1 屏幕尺寸

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

    2 屏幕分辨率

      屏幕分辨率是指横纵向上的像素点数,单位是px,1px=1个像素点,一般以纵向像素横向像素,如19201080,分辨率越高,显示效果越好。

    3 屏幕像素密度

      屏幕像素密度是指每英寸上的像素点数,单位是dpi,屏幕像素密度与屏幕尺寸和屏幕分辨率有关。

    4. px、dp、sp

    (1)安卓里面获取屏幕宽和高,也是以px作为单位的。
    (2)在160dpi(即分辨率是480*320)基准下,1dip=1px(也就是px不能适配所有机型),如下图所示,要充满屏幕,箭头的px值是不一样的。1dp=那个机型dpi/160px。所以用dp会比px好。

     

    (3)在使用sp(设置文字的)时候,使用偶数,不要使用奇数或者小数,最最推荐的是12.14.18,22sp的文字大小(尽量不要使用12sp以下的大小,用户可能看不清楚)。

    5. mdpi,hdpi,xdpi,xxdpi

    安卓软件运行时,会自动根据屏幕像素去不同文件夹加载对应图片。

     

    三、屏幕适配实战

    1. 使用dp设置控件大小,sp设置字体大小(不可行)

    activity_main2.xml布局代码如下:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".MainActivity">
    
        <Button
            android:layout_width="200dp"
            android:layout_height="50dp"
            android:textSize="20sp"
            android:text="按钮1"/>
    
        <Button
            android:layout_width="200dp"
            android:layout_height="50dp"
            android:layout_marginTop="20dp"
            android:textSize="20sp"
            android:text="按钮2"/>
    
    </LinearLayout>
    

    运行结果如下:

     

    得出结论:即使使用dp设置控件大小,sp设置字体大小,也是无法适配所有手机的。因为这是谷歌自己的一个标准。dp是根据屏幕像素和分辨率一起来解决的。但是有些手机像素和分辨率不是对应关系,所以不行。

    2. weight属性使用

    activity_main3.xml布局代码如下:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal"
        tools:context=".MainActivity">
    
        <Button
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:textSize="20sp"
            android:text="按钮1"/>
    
        <Button
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="2"
            android:textSize="20sp"
            android:text="按钮2"/>
    
    </LinearLayout>
    

    运行结果如下:

     

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

     

    如果将xml中的android:layout_weight属性值1和2互换,则结果是相反的,有兴趣伙伴可以下载源码看看效果。

    3. 使用自动拉伸位图.9图

    什么是.9图
      因为Android有太多的分辨率了,当圆角矩形控件在被拉伸放大的时候,圆角的部分就会出现模糊的情况。而点九切图就不同,它可以保证不管你上下还是左右拉伸,放大都可以保持原有的清晰度。
    .9图存放位置

     

    4. 屏幕方向限定符large

      比如我们想在屏幕竖屏时候加载什么布局,在屏幕横线时候加载什么布局。在手机加载什么布局,在平板电脑加载什么布局。
      该文章暂不展开讨论,将在Fragment使用中进行讲解。

    5.多文件适配(重要)

      大家经过上面的学习之后,已经知道有些手机像素和分辨率不是对应关系,无法使用dp等单位来解决,那么我们可以以某个常见的屏幕分辨率作为基准,自定义需要适配到的屏幕分辨率的xml文件,如下图所示:

     
     

    使用生成器生成对应的文件
    生成器代码(使用320*480作为基准)如下:

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

    运行代码,结果会在项目的res文件夹中生成对应的内容,如下图所示:

     
     

    温馨提示:上图每个文件夹是以320*480作为基准进行放大缩小后的px值

    将上面生成的文件夹复制到实际项目中
    复制所有文件夹,右击studio中的res文件夹进行粘贴

     

    xml布局中进行引用

    activity_main4.xml代码如下:
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".MainActivity">
    
        <Button
            android:layout_width="@dimen/x200"
            android:layout_height="@dimen/y30"
            android:text="按钮1"/>
    
        <Button
            android:layout_width="@dimen/x200"
            android:layout_height="@dimen/y30"
            android:layout_marginTop="@dimen/y30"
            android:text="按钮2"/>
    
    </LinearLayout>
    

    运行结果如下图所示:

     

    温馨提示:

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

    四、项目源码下载

    链接:https://pan.baidu.com/s/1xDRVaSS9Kk9OGLzloBeneA
    提取码:0zyt

     
  • 相关阅读:
    树状数组
    #135. 二维树状数组 3:区间修改,区间查询
    poj 2155 (二维树状数组 区间修改 求某点值)
    #133. 二维树状数组 1:单点修改,区间查询
    poj 3468 (区间修改 区间查询)
    树状数组 模板
    1535:【例 1】数列操作
    最通俗全面理解application context中的context是什么意思
    牛客哈理工小乐乐下象棋(深度理解bfs好题)
    牛客哈理工小乐乐打游戏(bfs深度理解好题)
  • 原文地址:https://www.cnblogs.com/WUXIAOCHANG/p/10544545.html
Copyright © 2011-2022 走看看