精华内容
下载资源
问答
  • 基于 lOSAndroid 手 机设备应用程序交 互适配设计研究报 第九届西安高新挑战杯陕西省 大学生课外学术科技作品竞赛申报作品 作品名称基于IOSAndroid手机设备应用程序交互适配 设计研究报告 所属领域白然科学类学术...
  • 什么是屏幕适配

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

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

    展开全文
  • Android 屏幕适配方案

    万次阅读 多人点赞 2015-05-04 13:08:47
    转载请标明出处: ... 本文出自:【张鸿洋的博客】 1、概述大家在Android开发时,肯定会...如果我们换个角度我们看下这个问题,知道大家有没有了解过web前端开发,或者说大家对于网页都陌生吧,其实适配的问题在we

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

    1、概述

    大家在Android开发时,肯定会觉得屏幕适配是个尤其痛苦的事,各种屏幕尺寸适配起来蛋疼无比。如果我们换个角度我们看下这个问题,不知道大家有没有了解过web前端开发,或者说大家对于网页都不陌生吧,其实适配的问题在web页面的设计中理论上也存在,为什么这么说呢?电脑的显示器的分辨率、包括手机分辨率,我敢说分辨率的种类远超过Android设备的分辨率,那么有一个很奇怪的现象:

    为什么Web页面设计人员从来没有说过,尼玛适配好麻烦?

    那么,到底是什么原因,让网页的设计可以在千差万别的分辨率的分辨率中依旧能给用户一个优质的体验呢?带着这个疑惑,我问了下媳妇(前端人员),媳妇睁大眼睛问我:什么叫适配?fc,尼玛,看来的确没有这类问题。后来再我仔细的追问后,她告诉我,噢,这个尺寸呀,我都是设置为20%的~~追根到底,其实就是一个原因,网页提供了百分比计算大小。

    同样的,大家拿到UI给的设计图以后,是不是抱怨过尼玛你标识的都是px,我项目里面用dp,这什么玩意,和UI人员解释,UI妹妹也不理解。那么本例同样可以解决Android工程师和UI妹妹间的矛盾~UI给出一个固定尺寸的设计稿,然后你在编写布局的时候不用思考,无脑照抄上面标识的像素值,就能达到完美适配,理想丰不丰满~~。

    然而,Android对于不同的屏幕给出的适配方案是dp,那么dp与百分比的差距到底在哪里?

    2、dp vs 百分比

    • dp

    我们首先看下dp的定义:

    Density-independent pixel (dp)独立像素密度。标准是160dip.即1dp对应1个pixel,计算公式如:px = dp * (dpi / 160),屏幕密度越大,1dp对应 的像素点越多。
    上面的公式中有个dpi,dpi为DPI是Dots Per Inch(每英寸所打印的点数),也就是当设备的dpi为160的时候1px=1dp;

    好了,上述这些概念记不记得住没关系,只要记住一点dp是与像素无关的,在实际使用中1dp大约等于1/160inch。

    那么dp究竟解决了适配上的什么问题?可以看出1dp = 1/160inch;那么它至少能解决一个问题,就是你在布局文件写某个View的宽和高为160dp*160dp,这个View在任何分辨率的屏幕中,显示的尺寸大小是大约是一致的(可能不精确),大概是 1 inch * 1 inch。

    但是,这样并不能够解决所有的适配问题:

    • 呈现效果仍旧会有差异,仅仅是相近而已
    • 当设备的物理尺寸存在差异的时候,dp就显得无能为力了。为4.3寸屏幕准备的UI,运行在5.0寸的屏幕上,很可能在右侧和下侧存在大量的空白。而5.0寸的UI运行到4.3寸的设备上,很可能显示不下。

    以上两点,来自参考链接1

    一句话,总结下,dp能够让同一数值在不同的分辨率展示出大致相同的尺寸大小。但是当设备的尺寸差异较大的时候,就无能为力了。适配的问题还需要我们自己去做,于是我们可能会这么做:

    <?xml version="1.0" encoding="utf-8"?>  
    <resources>  
        <!-- values-hdpi 480X800 -->  
        <dimen name="imagewidth">120dip</dimen>      
    </resources>  
    
    <resources>  
        <!-- values-hdpi-1280x800 -->  
        <dimen name="imagewidth">220dip</dimen>      
    </resources>  
    
    
    <?xml version="1.0" encoding="utf-8"?>  
    <resources>  
        <!-- values-hdpi  480X320 -->  
        <dimen name="imagewidth">80dip</dimen>      
    </resources> 

    上述代码片段来自网络,也就是说,我们为了优质的用户体验,依然需要去针对不同的dpi设置,编写多套数值文件。

    可以看出,dp并没有能解决适配问题。下面看百分比。

    • 百分比
      这个概念不用说了,web中支持控件的宽度可以去参考父控件的宽度去设置百分比,最外层控件的宽度参考屏幕尺寸设置百分比,那么其实中Android设备中,只需要支持控件能够参考屏幕的百分比去计算宽高就足够了。

    比如,我现在以下几个需求:

    • 对于图片展示的Banner,为了起到该有的效果,我希望在任何手机上显示的高度为屏幕高度的1/4
    • 我的首页分上下两栏,我希望每个栏目的屏幕高度为11/24,中间间隔为1/12
    • slidingmenu的宽度为屏幕宽度的80%

    当然了这仅仅是从一个大的层面上来说,其实小范围布局,可能百分比将会更加有用。

    那么现在不支持百分比,实现上述的需求,可能需要1、代码去动态计算(很多人直接pass了,太麻烦);2、利用weight(weight必须依赖Linearlayout,而且并不能适用于任何场景)

    再比如:我的某个浮动按钮的高度和宽度希望是屏幕高度的1/12,我的某个Button的宽度希望是屏幕宽度的1/3。

    上述的所有的需求,利用dp是无法完成的,我们希望控件的尺寸可以按照下列方式编写:

       <Button
            android:text="@string/hello_world"
            android:layout_width="20%w"
            android:layout_height="10%h"/>

    利用屏幕的宽和高的比例去定义View的宽和高。

    好了,到此我们可以看到dp与百分比的区别,而百分比能够更好的解决我们的适配问题。

    • some 适配tips

    我们再来看看一些适配的tips

    1. 多用match_parent
    2. 多用weight
    3. 自定义view解决

    其实上述3点tip,归根结底还是利用百分比,match_parent相当于100%参考父控件;weight即按比例分配;自定义view无非是因为里面多数尺寸是按照百分比计算的;

    通过这些tips,我们更加的看出如果能在Android中引入百分比的机制,将能解决大多数的适配问题,下面我们就来看看如何能够让Android支持百分比的概念。

    3、百分比的引入

    1、引入

    其实我们的解决方案,就是在项目中针对你所需要适配的手机屏幕的分辨率各自简历一个文件夹。

    如下图:

    然后我们根据一个基准,为基准的意思就是:

    比如480*320的分辨率为基准

    • 宽度为320,将任何分辨率的宽度分为320份,取值为x1-x320
    • 高度为480,将任何分辨率的高度分为480份,取值为y1-y480

    例如对于800*480的宽度480:

    可以看到x1 = 480 / 基准 = 480 / 320 = 1.5 ;

    其他分辨率类似~~
    你可能会问,这么多文件,难道我们要手算,然后自己编写?不要怕,下文会说。

    那么,你可能有个疑问,这么写有什么好处呢?

    假设我现在需要在屏幕中心有个按钮,宽度和高度为我们屏幕宽度的1/2,我可以怎么编写布局文件呢?

    <FrameLayout >
    
        <Button
            android:layout_gravity="center"
            android:gravity="center"
            android:text="@string/hello_world"
            android:layout_width="@dimen/x160"
            android:layout_height="@dimen/x160"/>
    
    </FrameLayout>
    

    可以看到我们的宽度和高度定义为x160,其实就是宽度的50%;
    那么效果图:

    可以看到不论在什么分辨率的机型,我们的按钮的宽和高始终是屏幕宽度的一半。

    • 对于设计图

    假设现在的UI的设计图是按照480*320设计的,且上面的宽和高的标识都是px的值,你可以直接将px转化为x[1-320],y[1-480],这样写出的布局基本就可以全分辨率适配了。

    你可能会问:设计师设计图的分辨率不固定怎么办?下文会说~

    • 对于上文提出的几个dp做不到的

    你可以通过在引入百分比后,自己试试~~

    好了,有个最主要的问题,我们没有说,就是分辨率这么多,尼玛难道我们要自己计算,然后手写?

    2、自动生成工具

    好了,其实这样的文件夹手写也可以,按照你们需要支持的分辨率,然后编写一套,以后一直使用。

    当然了,作为程序员的我们,怎么能做这么low的工作,肯定要程序来实现:

    那么实现需要以下步骤:

    1. 分析需要的支持的分辨率

    对于主流的分辨率我已经集成到了我们的程序中,当然对于特殊的,你可以通过参数指定。关于屏幕分辨率信息,可以通过该网站查询:http://screensiz.es/phone

    1. 编写自动生成文件的程序

    代码如下

    import java.io.File;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.PrintWriter;
    
    /**
     * Created by zhy on 15/5/3.
     */
    public class GenerateValueFiles {
    
        private int baseW;
        private int baseH;
    
        private String dirStr = "./res";
    
        private final static String WTemplate = "<dimen name=\"x{0}\">{1}px</dimen>\n";
        private final static String HTemplate = "<dimen name=\"y{0}\">{1}px</dimen>\n";
    
        /**
         * {0}-HEIGHT
         */
        private final static String VALUE_TEMPLATE = "values-{0}x{1}";
    
        private static final String SUPPORT_DIMESION = "320,480;480,800;480,854;540,960;600,1024;720,1184;720,1196;720,1280;768,1024;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());
    
        }
    
        /**
         * @param supportStr
         *            w,h_...w,h;
         * @return
         */
        private String validateInput(String supportStr) {
            StringBuffer sb = new StringBuffer();
            String[] vals = supportStr.split("_");
            int w = -1;
            int h = -1;
            String[] wh;
            for (String val : vals) {
                try {
                    if (val == null || val.trim().length() == 0)
                        continue;
    
                    wh = val.split(",");
                    w = Integer.parseInt(wh[0]);
                    h = Integer.parseInt(wh[1]);
                } catch (Exception e) {
                    System.out.println("skip invalidate params : w,h = " + val);
                    continue;
                }
                sb.append(w + "," + h + ";");
            }
    
            return sb.toString();
        }
    
        public void generate() {
            String[] vals = supportStr.split(";");
            for (String val : vals) {
                String[] wh = val.split(",");
                generateXmlFile(Integer.parseInt(wh[0]), Integer.parseInt(wh[1]));
            }
    
        }
    
        private void generateXmlFile(int w, int h) {
    
            StringBuffer sbForWidth = new StringBuffer();
            sbForWidth.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
            sbForWidth.append("<resources>");
            float cellw = w * 1.0f / baseW;
    
            System.out.println("width : " + w + "," + baseW + "," + cellw);
            for (int i = 1; i < baseW; i++) {
                sbForWidth.append(WTemplate.replace("{0}", i + "").replace("{1}",
                        change(cellw * i) + ""));
            }
            sbForWidth.append(WTemplate.replace("{0}", baseW + "").replace("{1}",
                    w + ""));
            sbForWidth.append("</resources>");
    
            StringBuffer sbForHeight = new StringBuffer();
            sbForHeight.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
            sbForHeight.append("<resources>");
            float cellh = h *1.0f/ baseH;
            System.out.println("height : "+ h + "," + baseH + "," + cellh);
            for (int i = 1; i < baseH; i++) {
                sbForHeight.append(HTemplate.replace("{0}", i + "").replace("{1}",
                        change(cellh * i) + ""));
            }
            sbForHeight.append(HTemplate.replace("{0}", baseH + "").replace("{1}",
                    h + ""));
            sbForHeight.append("</resources>");
    
            File fileDir = new File(dirStr + File.separator
                    + VALUE_TEMPLATE.replace("{0}", h + "")//
                            .replace("{1}", w + ""));
            fileDir.mkdir();
    
            File layxFile = new File(fileDir.getAbsolutePath(), "lay_x.xml");
            File layyFile = new File(fileDir.getAbsolutePath(), "lay_y.xml");
            try {
                PrintWriter pw = new PrintWriter(new FileOutputStream(layxFile));
                pw.print(sbForWidth.toString());
                pw.close();
                pw = new PrintWriter(new FileOutputStream(layyFile));
                pw.print(sbForHeight.toString());
                pw.close();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
        }
    
        public static float change(float a) {
            int temp = (int) (a * 100);
            return temp / 100f;
        }
    
        public static void main(String[] args) {
            int baseW = 320;
            int baseH = 400;
            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();
        }
    
    }

    同时我提供了jar包,默认情况下,双击即可生成,使用说明:

    下载地址见文末,内置了常用的分辨率,默认基准为480*320,当然对于特殊需求,通过命令行指定即可:

    例如:基准 1280 * 800 ,额外支持尺寸:1152 * 735;4500 * 3200;

    按照

    java -jar xx.jar width height width,height_width,height

    上述格式即可。

    到此,我们通过编写一个工具,根据某基准尺寸,生成所有需要适配分辨率的values文件,做到了编写布局文件时,可以参考屏幕的分辨率;在UI给出的设计图,可以快速的按照其标识的px单位进行编写布局。基本解决了适配的问题。

    本方案思想已经有公司投入使用,个人认为还是很不错的,如果大家有更好的方案来解决屏幕适配的问题,欢迎留言探讨或者直接贴出好文链接,大家可以将自己的经验进行分享,这样才能壮大我们的队伍~~。

    注:本方案思想来自Android Day Day Up 一群的【blue-深圳】,经其同意编写此文,上述程序也很大程度上借鉴了其分享的源码。在此标识感谢,预祝其创业成功!

    ===>后期更新

    Google已经添加了百分比支持库,详情请看:Android 百分比布局库(percent-support-lib) 解析与扩展

    ok~

    群号:463081660,欢迎入群

    下载地址

    微信公众号:hongyangAndroid
    (欢迎关注,第一时间推送博文信息)

    参考链接

    Android多屏幕适配学习笔记

    开源,原创,实用Android 屏幕适配方案分享

    展开全文
  • 屏幕适配之图片适配

    千次阅读 2017-09-19 09:19:56
    下面首先说明下我们为什么要屏幕适配:(此片博文有亮点!) 首先上一张图片直接说明问题所在; 看到了吧,自己写的自定义控件,在不同分辨率手机上显示,就会出现这个情况;你要是用户你还会用嘛!不会;

    屏幕适配总共有6种(我知道的):图片适配,dimens适配,布局(Layout)适配,权重适配,百分比适配;

    今天只说图片适配:图片适配主要是根据不同的手机密度,设置显示不同大小的图片;

    下面首先说明下我们为什么要屏幕适配:(此片博文有亮点!得意

    首先上一张图片直接说明问题所在;


    看到了吧,自己写的自定义控件,在不同分辨率手机上显示,就会出现这个情况;你要是用户你还会用嘛!不会;

    下面呢,咱就改变着中情况——图片适配;

    首先说下屏幕适配的定义:

    使得某一元素在android不同尺寸.不同分辨率的手机上显示效果,通俗的理解为一个软件需要在不同设备上显示相同

    的效果,就需要进行屏幕适配;

    如果不做屏幕适配就如上图所示;

    要做好屏幕适配就必须会这些算法:


    图片适配:根据主流的分辨率去切一套图,不要太多,主要是因为图片的体积非常大,
    会使app体积也很大,那么打包的apk就很大;
    原因:在不同密度的手机上,图片的大小会不一致,导致图片会变形;
    解决:把不同的分辨率手机,所需要的图片,放到对应的mipmap文件下即可,系统会根据用户手机自动进行适配
    注意了!亮点来了:这是在做开发中无意中发现的·


    对这个内存做个简单的解析;




    这里看内存消耗非常方便;

    注意:把合适的图片放到对应的文件夹,可以节省内存,把高分辨率的图片放到低分辨率的文件夹下,会导致内存消耗随着差值越大,消耗越大 
    提示:如果条件有限,就按照高分辨率的切一套图,放到高分辨率的文件夹下,这样就可以极大节省内存;
    下面在继续说一下图片适配中的.9图适配:

    在一些聊天的应用开发时会遇到一下情况:

    这个呢就需要用到.9图的适配:

    制作.9图,必须是png格式的;放置在drawable文件夹下;
    如果是.9图或者不需要多个屏幕分辨率的图片,放到drawable文件夹下即可,
    对应分辨率的图片要放到正确的文件夹下,否则会有内存消耗过大;显示在手机上也会不好看;
    改完png以后,点住图片右击,下面会有一个生成.9图,


    还需要进行拉伸:



    完成后运行:


    OK!完成;后续其他的适配也会继续更新;

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

    万次阅读 多人点赞 2015-05-19 11:34:17
    Android的屏幕适配一直以来都在折磨着我们这些开发者,本篇文章以Google的官方文档为基础,全面而深入的讲解了Android屏幕适配的原因、重要概念、解决方案及最佳实践,我相信如果你能认真的学习本文,对于Android的...

    转载请注明出处: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官方指定按照下列标准进行区分:

    名称像素密度范围
    mdpi120dpi~160dpi
    hdpi160dpi~240dpi
    xhdpi240dpi~320dpi
    xxhdpi320dpi~480dpi
    xxxhdpi480dpi~640dpi

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

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

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

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

    屏幕密度图标尺寸
    mdpi48x48px
    hdpi72x72px
    xhdpi96x96px
    xxhdpi144x144px
    xxxhdpi192x192px

    解决方案

    支持各种屏幕尺寸

    使用wrap_content、match_parent、weight

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

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

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

    下面是一段示例代码

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <LinearLayout android:layout_width="match_parent"
                      android:id="@+id/linearLayout1"  
                      android:gravity="center"
                      android:layout_height="50dp">
            <ImageView android:id="@+id/imageView1"
                       android:layout_height="wrap_content"
                       android:layout_width="wrap_content"
                       android:src="@drawable/logo"
                       android:paddingRight="30dp"
                       android:layout_gravity="left"
                       android:layout_weight="0" />
            <View android:layout_height="wrap_content"
                  android:id="@+id/view1"
                  android:layout_width="wrap_content"
                  android:layout_weight="1" />
            <Button android:id="@+id/categorybutton"
                    android:background="@drawable/button_bg"
                    android:layout_height="match_parent"
                    android:layout_weight="0"
                    android:layout_width="120dp"
                    style="@style/CategoryButtonStyle"/>
        </LinearLayout>
    
        <fragment android:id="@+id/headlines"
                  android:layout_height="fill_parent"
                  android:name="com.example.android.newsreader.HeadlinesFragment"
                  android:layout_width="match_parent" />
    </LinearLayout>

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

    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为例说明。

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <TextView
            android:id="@+id/label"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Type here:"/>
        <EditText
            android:id="@+id/entry"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@id/label"/>
        <Button
            android:id="@+id/ok"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/entry"
            android:layout_alignParentRight="true"
            android:layout_marginLeft="10dp"
            android:text="OK" />
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_toLeftOf="@id/ok"
            android:layout_alignTop="@id/ok"
            android:text="Cancel" />
    </RelativeLayout>

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

    在小尺寸屏幕的显示

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

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

    使用限定符

    使用尺寸限定符

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

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

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

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

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <fragment android:id="@+id/headlines"
                  android:layout_height="fill_parent"
                  android:name="com.example.android.newsreader.HeadlinesFragment"
                  android:layout_width="match_parent" />
    </LinearLayout>

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

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="horizontal">
        <fragment android:id="@+id/headlines"
                  android:layout_height="fill_parent"
                  android:name="com.example.android.newsreader.HeadlinesFragment"
                  android:layout_width="400dp"
                  android:layout_marginRight="10dp"/>
        <fragment android:id="@+id/article"
                  android:layout_height="fill_parent"
                  android:name="com.example.android.newsreader.ArticleFragment"
                  android:layout_width="fill_parent" />
    </LinearLayout>

    请注意第二种布局名称目录中的 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,单面板(默认)布局:

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <fragment android:id="@+id/headlines"
                  android:layout_height="fill_parent"
                  android:name="com.example.android.newsreader.HeadlinesFragment"
                  android:layout_width="match_parent" />
    </LinearLayout>

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

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="horizontal">
        <fragment android:id="@+id/headlines"
                  android:layout_height="fill_parent"
                  android:name="com.example.android.newsreader.HeadlinesFragment"
                  android:layout_width="400dp"
                  android:layout_marginRight="10dp"/>
        <fragment android:id="@+id/article"
                  android:layout_height="fill_parent"
                  android:name="com.example.android.newsreader.ArticleFragment"
                  android:layout_width="fill_parent" />
    </LinearLayout>

    也就是说,对于最小宽度大于等于 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:

    <resources>
        <item name="main" type="layout">@layout/main_twopanes</item>
    </resources>

    res/values-sw600dp/layout.xml:

    <resources>
        <item name="main" type="layout">@layout/main_twopanes</item>
    </resources>

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

    使用屏幕方向限定符

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

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

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

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

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <fragment android:id="@+id/headlines"
                  android:layout_height="fill_parent"
                  android:name="com.example.android.newsreader.HeadlinesFragment"
                  android:layout_width="match_parent" />
    </LinearLayout>

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

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <LinearLayout android:layout_width="match_parent"
                      android:id="@+id/linearLayout1"  
                      android:gravity="center"
                      android:layout_height="50dp">
            <ImageView android:id="@+id/imageView1"
                       android:layout_height="wrap_content"
                       android:layout_width="wrap_content"
                       android:src="@drawable/logo"
                       android:paddingRight="30dp"
                       android:layout_gravity="left"
                       android:layout_weight="0" />
            <View android:layout_height="wrap_content"
                  android:id="@+id/view1"
                  android:layout_width="wrap_content"
                  android:layout_weight="1" />
            <Button android:id="@+id/categorybutton"
                    android:background="@drawable/button_bg"
                    android:layout_height="match_parent"
                    android:layout_weight="0"
                    android:layout_width="120dp"
                    style="@style/CategoryButtonStyle"/>
        </LinearLayout>
    
        <fragment android:id="@+id/headlines"
                  android:layout_height="fill_parent"
                  android:name="com.example.android.newsreader.HeadlinesFragment"
                  android:layout_width="match_parent" />
    </LinearLayout>

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

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="horizontal">
        <fragment android:id="@+id/headlines"
                  android:layout_height="fill_parent"
                  android:name="com.example.android.newsreader.HeadlinesFragment"
                  android:layout_width="400dp"
                  android:layout_marginRight="10dp"/>
        <fragment android:id="@+id/article"
                  android:layout_height="fill_parent"
                  android:name="com.example.android.newsreader.ArticleFragment"
                  android:layout_width="fill_parent" />
    </LinearLayout>

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

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="horizontal">
        <fragment android:id="@+id/headlines"
                  android:layout_height="fill_parent"
                  android:name="com.example.android.newsreader.HeadlinesFragment"
                  android:layout_width="200dp"
                  android:layout_marginRight="10dp"/>
        <fragment android:id="@+id/article"
                  android:layout_height="fill_parent"
                  android:name="com.example.android.newsreader.ArticleFragment"
                  android:layout_width="fill_parent" />
    </LinearLayout>

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

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

    res/values/layouts.xml:

    <resources>
        <item name="main_layout" type="layout">@layout/onepane_with_bar</item>
        <bool name="has_two_panes">false</bool>
    </resources>

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

    <resources>
        <item name="main_layout" type="layout">@layout/twopanes</item>
        <bool name="has_two_panes">true</bool>
    </resources>

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

    <resources>
        <item name="main_layout" type="layout">@layout/onepane</item>
        <bool name="has_two_panes">false</bool>
    </resources>

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

    <resources>
        <item name="main_layout" type="layout">@layout/twopanes</item>
        <bool name="has_two_panes">true</bool>
    </resources>

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

    <resources>
        <item name="main_layout" type="layout">@layout/twopanes_narrow</item>
        <bool name="has_two_panes">true</bool>
    </resources>

    使用自动拉伸位图

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

    如果在可以更改尺寸的组件上使用了简单的图片,您很快就会发现显示效果多少有些不太理想,因为系统会在运行时平均地拉伸或收缩您的图片。解决方法为使用自动拉伸位图,这是一种格式特殊的 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)指定两个视图间的间距:

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

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

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

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

    经过上面的介绍,我们都清楚,为了能够规避不同像素密度的陷阱,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份,每一份对应具体的像素就可以了。

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

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

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

    <?xml version="1.0" encoding="utf-8"?>
    <resources><dimen name="x1">1.0px</dimen>
    <dimen name="x2">2.0px</dimen>
    <dimen name="x3">3.0px</dimen>
    <dimen name="x4">4.0px</dimen>
    <dimen name="x5">5.0px</dimen>
    <dimen name="x6">6.0px</dimen>
    <dimen name="x7">7.0px</dimen>
    <dimen name="x8">8.0px</dimen>
    <dimen name="x9">9.0px</dimen>
    <dimen name="x10">10.0px</dimen>
    ...省略好多行
    <dimen name="x300">300.0px</dimen>
    <dimen name="x301">301.0px</dimen>
    <dimen name="x302">302.0px</dimen>
    <dimen name="x303">303.0px</dimen>
    <dimen name="x304">304.0px</dimen>
    <dimen name="x305">305.0px</dimen>
    <dimen name="x306">306.0px</dimen>
    <dimen name="x307">307.0px</dimen>
    <dimen name="x308">308.0px</dimen>
    <dimen name="x309">309.0px</dimen>
    <dimen name="x310">310.0px</dimen>
    <dimen name="x311">311.0px</dimen>
    <dimen name="x312">312.0px</dimen>
    <dimen name="x313">313.0px</dimen>
    <dimen name="x314">314.0px</dimen>
    <dimen name="x315">315.0px</dimen>
    <dimen name="x316">316.0px</dimen>
    <dimen name="x317">317.0px</dimen>
    <dimen name="x318">318.0px</dimen>
    <dimen name="x319">319.0px</dimen>
    <dimen name="x320">320px</dimen>
    </resources>

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

    <?xml version="1.0" encoding="utf-8"?>
    <resources><dimen name="x1">3.37px</dimen>
    <dimen name="x2">6.75px</dimen>
    <dimen name="x3">10.12px</dimen>
    <dimen name="x4">13.5px</dimen>
    <dimen name="x5">16.87px</dimen>
    <dimen name="x6">20.25px</dimen>
    <dimen name="x7">23.62px</dimen>
    <dimen name="x8">27.0px</dimen>
    <dimen name="x9">30.37px</dimen>
    <dimen name="x10">33.75px</dimen>
    ...省略好多行
    <dimen name="x300">1012.5px</dimen>
    <dimen name="x301">1015.87px</dimen>
    <dimen name="x302">1019.25px</dimen>
    <dimen name="x303">1022.62px</dimen>
    <dimen name="x304">1026.0px</dimen>
    <dimen name="x305">1029.37px</dimen>
    <dimen name="x306">1032.75px</dimen>
    <dimen name="x307">1036.12px</dimen>
    <dimen name="x308">1039.5px</dimen>
    <dimen name="x309">1042.87px</dimen>
    <dimen name="x310">1046.25px</dimen>
    <dimen name="x311">1049.62px</dimen>
    <dimen name="x312">1053.0px</dimen>
    <dimen name="x313">1056.37px</dimen>
    <dimen name="x314">1059.75px</dimen>
    <dimen name="x315">1063.12px</dimen>
    <dimen name="x316">1066.5px</dimen>
    <dimen name="x317">1069.87px</dimen>
    <dimen name="x318">1073.25px</dimen>
    <dimen name="x319">1076.62px</dimen>
    <dimen name="x320">1080px</dimen>
    </resources>

    无论在什么分辨率下,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 设备生成了 200x200 px尺寸的图片,就应该使用同一资源为 hdpi、mdpi 和 ldpi 设备分别生成 150x150、100x100 和 75x75 尺寸的图片。

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

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

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

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

    实施自适应用户界面流程

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

    确定当前布局

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

    public class NewsReaderActivity extends FragmentActivity {
        boolean mIsDualPane;
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main_layout);
    
            View articleView = findViewById(R.id.article);
            mIsDualPane = articleView != null &&
                            articleView.getVisibility() == View.VISIBLE;
        }
    }

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

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

    Button catButton = (Button) findViewById(R.id.categorybutton);
    OnClickListener listener = /* create your listener here */;
    if (catButton != null) {
        catButton.setOnClickListener(listener);
    }

    根据当前布局做出响应

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

    @Override
    public void onHeadlineSelected(int index) {
        mArtIndex = index;
        if (mIsDualPane) {
            /* display article on the right pane */
            mArticleFragment.displayArticle(mCurrentCat.getArticle(index));
        } else {
            /* start a separate activity */
            Intent intent = new Intent(this, ArticleActivity.class);
            intent.putExtra("catIndex", mCatIndex);
            intent.putExtra("artIndex", index);
            startActivity(intent);
        }
    }

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

    final String CATEGORIES[] = { "热门报道", "政治", "经济", "Technology" };
    
    public void onCreate(Bundle savedInstanceState) {
        ....
        if (mIsDualPane) {
            /* use tabs for navigation */
            actionBar.setNavigationMode(android.app.ActionBar.NAVIGATION_MODE_TABS);
            int i;
            for (i = 0; i < CATEGORIES.length; i++) {
                actionBar.addTab(actionBar.newTab().setText(
                    CATEGORIES[i]).setTabListener(handler));
            }
            actionBar.setSelectedNavigationItem(selTab);
        }
        else {
            /* use list navigation (spinner) */
            actionBar.setNavigationMode(android.app.ActionBar.NAVIGATION_MODE_LIST);
            SpinnerAdapter adap = new ArrayAdapter(this,
                    R.layout.headline_item, CATEGORIES);
            actionBar.setListNavigationCallbacks(adap, handler);
        }
    }

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

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

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

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="horizontal">
        <fragment android:id="@+id/headlines"
                  android:layout_height="fill_parent"
                  android:name="com.example.android.newsreader.HeadlinesFragment"
                  android:layout_width="400dp"
                  android:layout_marginRight="10dp"/>
        <fragment android:id="@+id/article"
                  android:layout_height="fill_parent"
                  android:name="com.example.android.newsreader.ArticleFragment"
                  android:layout_width="fill_parent" />
    </LinearLayout>

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

    ArticleFragment frag = new ArticleFragment();
    getSupportFragmentManager().beginTransaction().add(android.R.id.content, frag).commit();

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

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

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

    public class HeadlinesFragment extends ListFragment {
        ...
        OnHeadlineSelectedListener mHeadlineSelectedListener = null;
    
        /* Must be implemented by host activity */
        public interface OnHeadlineSelectedListener {
            public void onHeadlineSelected(int index);
        }
        ...
    
        public void setOnHeadlineSelectedListener(OnHeadlineSelectedListener listener) {
            mHeadlineSelectedListener = listener;
        }
    }

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

    public class HeadlinesFragment extends ListFragment {
        ...
        @Override
        public void onItemClick(AdapterView<?> parent,
                                View view, int position, long id) {
            if (null != mHeadlineSelectedListener) {
                mHeadlineSelectedListener.onHeadlineSelected(position);
            }
        }
        ...
    }

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

    处理屏幕配置变化

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

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

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

    public class ArticleActivity extends FragmentActivity {
        int mCatIndex, mArtIndex;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            mCatIndex = getIntent().getExtras().getInt("catIndex", 0);
            mArtIndex = getIntent().getExtras().getInt("artIndex", 0);
    
            // If should be in two-pane mode, finish to return to main activity
            if (getResources().getBoolean(R.bool.has_two_panes)) {
                finish();
                return;
            }
            ...
    }

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

    最佳实践

    关于高清设计图尺寸

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

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

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

    ImageView的ScaleType属性

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

    动态设置

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

    public class ScreenSizeUtil {
    
        public static int getScreenWidth(Activity activity) {
            return activity.getWindowManager().getDefaultDisplay().getWidth();
        }
    
        public static int getScreenHeight(Activity activity) {
            return activity.getWindowManager().getDefaultDisplay().getHeight();
        }
    
    }

    更多参考资料


    尊重原创,转载请注明:From 凯子哥(http://blog.csdn.net/zhaokaiqiang1992) 侵权必究!

    关注我的微博,可以获得更多精彩内容

    展开全文
  • 基本一直都在做移动端的开发,rem布局也写了很久,不过对于实现的原理有些...viewport和移动端适配的关系 flexible.js原理 vw vh flexible.js VS vw vh 布局小例子----常见困惑 iphone6尺寸是375*667,那给div设...
  • Android 屏幕适配之dimens适配

    万次阅读 热门讨论 2017-05-23 10:23:02
    在过去多个项目中一直使用dimens适配,这种适配方式的优点很明显,不用管什么dp还是dpi这些东西,只需要以一种屏幕分辨率为基准(例如1280x720,相当于把屏幕宽分成720份,高分成1280份),生成对应屏幕分辨率的的dimens文件...
  • 屏幕适配,rom适配和版本适配

    千次阅读 2017-10-19 09:53:00
    1,不同android api版本的兼容 2,不同厂商定制系统的兼容 3,不同尺寸分辨率的兼容 ...) 由于Android碎片化严重,导致开发中一套代码在不同手机上运行起来效果不是很好,兼容性不是很好,这就需要对不同分辨率,
  • Android适配方法之dimen适配

    千次阅读 2017-01-09 10:33:48
    详细讲解了dimens适配。此种适配,虽然占用一定空间,但是非常好用!
  • 手机适配

    2017-03-30 09:36:15
    *Android开发手机适配的理解作为一名Android开发工程师,...安卓手机机型繁杂多样,像IOS开发那样维护起来简单,方便,因为机型较少,那么下面就来谈谈我对Android开发中手机适配的理解。 首先介绍以下几个概念 1
  • 屏幕适配基础(为什么要做屏幕适配?) 屏幕参数 屏幕大小 屏幕的对角线的长度,通常使用 "英寸"来度量,比如5.5英寸手机,5英寸的手机 分辨率 分辨率是指手机屏幕的像素点个数,比如1080*1920,是指宽宥1080...
  • 即 凹痕 的意思,那我们就认为是 “刘海” 就可以了。 目前,市场手机的潮流就是推出 全面屏、齐刘海 的手机,比如现在的华为、oppo 、vivo、小米等等手机厂商陆续推出了几款 齐刘海的手机。 但是,现在有个问题,...
  • 适配 Android N 需要注意什么

    千次阅读 2016-03-11 11:41:29
    这里主要分享对 Android N 的适配大家可能要注意什么。还记得 6.0 对 Apache Http 库的废除导致的应用崩溃吗?还记得 6.0 中 MAC id 始终返回为空导致的唯一 id 混合生成算法大幅失效吗?1. Android 中 Java 的实现...
  • Android 屏幕适配

    2015-10-12 11:12:53
    Android设备的屏幕尺寸...几个缩写的意思 px pixel的缩写,屏幕上的像素点。都是整数,可能出现0.5px的情况。 in inch的缩写。1 inch = 2.54cm。平时所说的手机屏幕尺寸,指的是屏幕对角线的长度。 dpi Dots Per Inc
  • 因此,屏幕的适配是Android开发者可缺少的一部分工作。 今天,记录的是今日头条的适配方案的总结,在学习适配前可阅读下面的文章了解适配: 一种极低成本的Android屏幕适配方式 Android 目前稳定高效的UI适配...
  • Android适配-版本适配

    千次阅读 2018-03-10 18:17:41
    2.这个类有个说明,意思是Notification.Builder是新增的一个内部类,用它创建通知更方便。接着往下看。 A class that represents how a persistent notification is to be presented to the user ...
  • Android 屏幕适配解决方案大全
  • 平板适配方案

    千次阅读 2020-02-10 23:17:39
    平板适配方案 非原创,作为记录使用。由于是新项目开发,最终使用的是今日头条适配方案,侵入低,效果好。 by talon 常用的适配方案 一、宽高限定符适配 含义 在res文件夹中,创建很多values-的文件夹,计算出对应...
  • 前端适配

    千次阅读 2016-12-08 20:09:43
    移动端开发中,关于适配问题的一点总结(一) 转自:http://www.jianshu.com/p/3a5063028706?nomobile=yes 我们第一次接触移动web的时候,直观印象样应该是:屏幕比pc小很多,所以对pc端设计的界面,一定...
  • 安卓框架搭建(九)UI适配适配方案

    千次阅读 2018-08-17 11:31:24
    UI适配在安卓开发中一直是一个很头疼的问题,由于安卓手机品牌型号的众多,目前又新出了一个刘海屏,就导致适配问题很难完全兼顾 方案: 目前来说适配方案有代码适配 , 布局适配 1.dp 直接适配 dp适配虽然可以兼顾...
  • 百度移动页是一条华丽的曲线,很多新站长加入百度站长平台之后发现了移动适配知道该如何操作,这才是自己GAnk自己啊,在提交移动适配之前,我们先来了解一下百度移动搜索官方的说明: 1. 为提升搜索用户在百度...
  • IOS 9 适配

    千次阅读 2016-09-18 15:35:08
    WHAT(什么是SSL/TLS?跟HTTP和HTTPS有什么关系) WHY(以前的HTTP不是也能用吗?为什么要用SSL/TLS?Apple是不是又在反人类?) HOW(如何适配?---弱弱地问下:加班要多久?) 第1种情况:HTTPS Only (只有HTTPS...
  • 机型适配: 作用是使应用程序能够在广泛的软件系统和硬件平台上都可以正常的稳定的运行 操作系统的版本的适配。API android 上面的手表,平板电脑, 所有做客户端的必须要做机型适配 机型适配的要求: 匹配,合适,...
  • Android屏幕适配

    千次阅读 2016-10-26 16:19:48
    (一)背景知识为什么需要屏幕适配 Android是一个开放的系统,全球各种用户、手机企业、OEM厂商都可以对Android系统进行定制,这就导致了Android系统的碎片化问题。其中对于开发者来讲工作中最常碰到的就是屏幕碎片...
  • vue实现PC端分辨率适配

    万次阅读 多人点赞 2019-07-25 16:12:23
    我们只需在 cssLoader 后再加上一个 px2remLoader 即可,px2rem-loader 的 remUnit 选项意思是 1rem=多少像素,结合 lib-flexible 的方案,我们将 px2remLoader 的 options.remUnit 设置成设计稿宽度的 1/10,这里...
  • 移动适配服务, 全站基于html5+css3+jquery特效手写 ,5年以上经验工程师操刀,移动适配基于css3 多媒体查询技术 ,效果永久,依赖第三方 (相对于百度适配和某适配来说) ,价格实惠,PSD设计稿中多处的像素bug ...
  • 什么是 smallestWidth smallestWidth 翻译为中文的意思就是 最小宽度,那这个 最小宽度 是什么意思呢? 系统会根据当前设备屏幕的 最小宽度 来匹配 values-swdp,为什么不是根据 宽度 来匹配,而要加上 最小 这两...
  • Android 屏幕适配总结

    千次阅读 2020-04-07 23:02:55
    现在官方推荐使用ConstraintLayout用作屏幕的适配,如果对ConstraintLayout还了解可以先看 与 Android 适配相关的文章有很多了,我阐述一下自己总结后的理解与解决方式,本文从为什么需要适配为起点,到官方推荐...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 32,185
精华内容 12,874
关键字:

不适配是什么意思