精华内容
下载资源
问答
  • Android 屏幕适配

    2015-05-17 16:55:14
    这篇文章转自stormzhang大神的个人博客,对于android屏幕适配这一块写的非常好! 众所周知,Android机型尺寸各种各样,于是屏幕适配就成了Android开发中很重要的一环。Android屏幕适配可能一些开发者都会遇到...

    这篇文章转自stormzhang大神的个人博客,对于android屏幕适配这一块写的非常好!

    众所周知,Android机型尺寸各种各样,于是屏幕适配就成了Android开发中很重要的一环。Android屏幕适配可能一些开发者都会遇到这样的问题,今天就来分享下屏幕适配,你会发现其实Android屏幕适配也可以很简单。

    基本概念

    Android屏幕适配必须要理解的一些概念,这部分可能比较枯燥,但是俗话说的好“工欲善其事,必先利器”,翻译过来就是“有什么样的枪,决定你打什么样的鸟”,一旦这些概念你理解掌握了,屏幕适配你自然而然就觉得简单多了。

    • px

    是英文单词pixel的缩写,意为像素,屏幕上的点。我们通常所说的分辨率如480X800就是指的像素。

    在设计领域中,像素是用来计算数码影像的最小单位。计算机中显示的图像并非连续的线条组成,而是由许多肉眼看不见的小点组成。如果把影像放大数倍,会发现这些连续色调其实是由许多色彩相近的小点所组成,这些小点就是构成影像的最小单位“像素”。由于是最小的独立显示单位,px均为整数,不会出现0.5px的情况。如:

    看这个色彩鲜艳的LED灯(原图大小)

    你能想象这才是他的本来面目吗?(放大之后)

    • in

    表示英寸,是屏幕的物理尺寸。每英寸等于2.54厘米。例如我们经常说的手机屏幕大小有,5(英)寸、4(英)寸就是指这个单位。这些尺寸是屏幕的对角线长度。如果手机的屏幕是4英寸,表示手机的屏幕(可视区域)对角线长度是4 X 2.54 = 10.16厘米。

    • dpi

    dpi是Dots Per Inch的缩写, 每英寸点数,即每英寸包含像素个数。比如320X480分辨率的手机,宽2英寸,高3英寸, 每英寸包含的像素点的数量为320/2=160dpi(横向)或480/3=160dpi(纵向),160就是这部手机的dpi,横向和纵向的这个值都是相同的,原因是大部分手机屏幕使用正方形的像素点。

    • density

    屏幕密度,density和dpi的关系为 density = dpi/160

    • dp

    也即dip,设备独立像素,device independent pixels的缩写,Android特有的单位,在屏幕密度dpi = 160屏幕上,1dp = 1px。

    • sp

    和dp很类似,一般用来设置字体大小,和dp的区别是它可以根据用户的字体大小偏好来缩放。

    Android Drawable

    我们新建一个Android项目后应该可以看到很多drawable文件夹,分别对应不同的dpi

    • drawable-ldpi (dpi=120, density=0.75)

    • drawable-mdpi (dpi=160, density=1)

    • drawable-hdpi (dpi=240, density=1.5)

    • drawable-xhdpi (dpi=320, density=2)

    • drawable-xxhdpi (dpi=480, density=3)

    市面上的一些Android教程大多都是教的是为每种dpi都出一套图片资源,这个固然是一种解决办法,但同时也是一种非常笨的方法,为美工或者设计增加了不少的工作量不说,同时也会让你的apk包变的很大。那么有没有什么好的方法既能保证屏幕适配,又可以最小占用设计资源,同时最好又只使用一套dpi的图片资源呢?下面就来讲解下项目中总结出来的这个方法。

    首先必须清楚一个自动渲染的概念,Android SDK会自动屏幕尺寸选择对应的资源文件进行渲染,如SDK检测到你手机dpi是160的话会优先到drawable-mdpi文件夹下找对应的图片资源,注意只是优先,假设你手机dpi是160,但是你只在xhpdi文件夹下有对应的图片资源文件,程序一样可以正常运行。所以理论上来说只需要提供一种规格的图片资源就ok了,如果只提供ldpi规格的图片,对于大分辨率的手机如果把图片放大就会不清晰,所以需要提供一套你需要支持的最大dpi的图片,这样即使用户的手机分辨率很小,这样图片缩小依然很清晰。

    xhdpi成为首选

    上面说了只需要提供一套大的dpi的图片就ok了,现在市面手机分辨率最大可达到1080X1920的分辨率,如Nexus5,dpi属于xxhdpi,但是毕竟还没普及,目前市面上最普遍的高端机的分辨率还多集中在720X1080范围,也就是多集中在xhdpi,所以目前来看xhpdi规格的图片成为了首选。当然随着技术规格的提高以后发展,以后可能市场上xxdpi的手机会越来越普遍,但这是后话。

    设计资源紧张怎么办?

    在现在的App开发中,基本都会有iOS和Android版本,有些公司为了保持App不同版本的体验交互一致,还有些公司的设计资源可能比较紧张,这些情况下iOS和Android版本基本是一个设计师主导,而大多数情况下设计师可能更会以iPhone手机为基础进行设计,包括后期的切图之类的。这个时候身为Android开发人员你是否还要求设计师单独为Android端切一套图片资源呢?这会让你们的设计师崩溃的,下面就来告诉一个项目中总结的更棒的方法。

    相信设计师们一般都会用最新的iPhone5(5s和5的尺寸以及分辨率都一样)来做原型设计,而iPhone5的屏幕分辨率为640X1164, 屏幕尺寸为4英寸,根据勾股定理(a^2 + b^2 = c^2)640^2+1164^2=1764496, 然后再对其开根号可求出屏幕对角线的分辨率为:1328,除以4可得出iphone5的dpi:1328/4≈332 可以看出iPhone5的屏幕的dpi约等于320, 刚好属于xhdpi,所以你可以很自豪的像你们的设计师说不用专门为Android端切图,直接把iPhone的那一套切好的图片资源放入drawable-xhdpi文件夹里就ok了。

    wrap_content VS dp

    wrap_content和dp都是在Android开发中应该经常用到的,然后它们冥冥中是有关系的。

    假设你看了这篇文章后都是统一有xhdpi的资源,那么你用wrap_content完全没有问题,Android会自动为其他规格的dpi屏幕适配,比如你在xhdpi放了一张120X120px大小的图片,那么在在hdpi屏幕上显示的就只有120/2*1.5=90px大小,但是如果你不小心同样把这张图片也放入了mdpi了,这个时候用wrap_content显示就会有问题,具体看下面的例子:

    例如假设你只在drawable_xhdpi文件夹下放了test图片,xhdpi的设备会去xhdpi文件夹下找到test图片并直接显示,而mdpi的设备优先会去mdpi文件夹里查找test图片,但是没找到,最后在xhdpi文件夹下找到,然后会自动根据density计算并缩放显示出来,实际显示出来的大小是120/2=60px, 所以整体的显示比例才会看起来比较正常

    • mdpi

    • xhdpi

    但是如果你在mdpi文件夹里也放入了同样的图片,那么mdpi的设备会直接去mdpi文件夹里寻找到test图片,并直接显示,而这时候显示不会缩放,实际显示大小就是120X120,在mdpi的屏幕上看起来就会比较大,如图:

    通过上面整个过程,大家应该理解了Android加载资源的整个过程, wrap_content同样可以用dp来代替,就拿上面这个例子,在xhdpi文件夹内放入了一张120X120像素的test图片,宽高直接除density就得出dp的数值,即这种情况下以下代码是等同的.

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/test" />
    <ImageView
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:src="@drawable/test" />

    总结

    相信通过以上的讲解,对Android UI中的一些基本概念有个很好的理解,实际开发工作中也有一些高效的方法可以参考,应该可以应对大部分的屏幕适配工作。但是项目中仍然有一些比较特殊的适配需求满足不了,以后会针对一些特殊的需求进行示例讲解。


    原文地址:

    http://www.stormzhang.com/android/2014/05/16/android-screen-adaptation/

    展开全文
  • Android屏幕适配

    千次阅读 2015-12-18 16:05:47
    Android屏幕适配 Android屏幕适配的文章已经很多很多了,想看“大道理”的可以去搜搜,这里只介绍怎么用。 工具类 生成适配所有Android手机屏幕分辨率的适配文件 import java.io.File; import java.io....

    Android屏幕适配

    Android屏幕适配的文章已经很多很多了,想看“大道理”的可以去搜搜,这里只介绍怎么用。

    工具类

    生成适配所有Android手机屏幕分辨率的适配文件

    import java.io.File;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.PrintWriter;
    
    /**
     * Created by kongqw on 2015/11/21.
     */
    public class MakeXml {
        // 生成地址 C盘layoutroot目录下
        private final static String rootPath = "C:\\layoutroot\\values-{0}x{1}\\";
    
        /**
         * 设置基准分辨率
         * 一般标注按照多大的图标,这里我们就设置多大尺寸
         */
        private final static float dw = 720f;
        private final static float dh = 1280f;
    
        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 < dw; i++) {
                sb.append(WTemplate.replace("{0}", i + "").replace("{1}", change(cellw * i) + ""));
            }
            sb.append(WTemplate.replace("{0}", "720").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 < dh; i++) {
                sb2.append(HTemplate.replace("{0}", i + "").replace("{1}", change(cellh * i) + ""));
            }
            sb2.append(HTemplate.replace("{0}", "1280").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;
        }
    
    }

    生成适配文件

    上述工具类(MakeXml.java)放置在任意目录下,按住Shift+鼠标右键,点击在此处打开命令窗口
    或者
    Windows键 + R,输入cmd,打开命令行窗口以后,再进入到MakeXml.java所在目录

    我是把MakeXml.java放在了桌面

    P1

    输入编译指令,会生成.class文件

    javac MakeXml.java

    P4

    在编译过程中,可能会出现如下错误

    P2

    右键使用文本编辑器,另存为,改下编码就行了

    P3

    最后一步,输入指令,生成xml文件

    java MakeXml

    如下

    P5

    到此,xml已经生成了,到C盘下看一下

    P6

    适配文件的使用

    使用比较简单,直接将这些文件拷贝到工程目录下就可以了

    P7

    使用

    android:layout_width="@dimen/x24"
    android:layout_height="@dimen/y24"

    在使用的时候,你可能会发现没有提示,找一个分辨率的适配文件,copy到默认的values目录下就可以了,一般标注按照什么尺寸的标注,就把那个尺寸的适配文件放过去就行了。

    P8

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

    万次阅读 多人点赞 2015-05-04 13:08:47
    1、概述大家在Android开发时,肯定会觉得屏幕适配是个尤其痛苦的事,各种屏幕尺寸适配起来蛋疼无比。如果我们换个角度我们看下这个问题,不知道大家有没有了解过web前端开发,或者说大家对于网页都不陌生吧,其实...

    转载请标明出处:
    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、引入

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

    如下图:

    20150503174449732

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

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

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

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

    20150503180400049

    可以看到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%;
    那么效果图:

    20150503180542414

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

    • 对于设计图

    假设现在的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包,默认情况下,双击即可生成,使用说明:

    20150503173911632

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

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

    20150503173719049

    按照

    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
    (欢迎关注,第一时间推送博文信息)
    1422600516_2905.jpg

    参考链接

    Android多屏幕适配学习笔记

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

    展开全文
  • android 屏幕适配

    千次阅读 2014-06-09 13:58:51
    android屏幕适配一直是开发者头疼的问题,因为android的设备大小不一,而且屏幕显示效果也不相同,如何对android进行屏幕适配是一个很大的挑战,为了应对不同的情况,需要仔细研究android对不同屏幕的定义。...

    android的屏幕适配一直是开发者头疼的问题,因为android的设备大小不一,而且屏幕显示效果也不相同,如何对android进行屏幕适配是一个很大的挑战,为了应对不同的情况,需要仔细研究android对不同屏幕的定义。看过学渣的这篇博客,希望大家对屏幕适配有一个基本的了解。

    1 android的屏幕大小

    android的屏幕有大有小,为了对不同大小屏幕的设备提供最好的体验,需要对不同大小的设备进行不同的设计,首先遇到的问题就是android对屏幕大小的区分。

    android的屏幕问题在官网有详细说明,,作为一名学渣,需要细细研读,首先android把屏幕分为四种大小:small,normal,large,xlarge,这四种屏幕首先是直观的区分,即对设备的对角线用尺子量一下,用英寸做单位进行区分,比如学渣用的红米就是4.7英寸,属于normal,具体分类如图1所示:


    图1 android屏幕大小区分

    如果你的程序获知android设备屏幕后,根据大小不同可以采用不同的布局方案,但是我们写程序时,进行布局时,不可能用英寸进行布局,先假设我们使用像素(px)进行布局,但是这里会遇到一个问题,这里需要介绍新的term,请看2。。。。。

    2 屏幕的分辨率和密度

     这里遇到的问题需要看几个术语,android官网上去后有几个术语介绍,学渣先为大家介绍分辨率和密度

            分辨率(Resolution):The total number of physical pixels on a screen. 即一个设备的物理像素,如1280*720,大家可以自己计算。

        密度(Screen density):The quantity of pixels within a physical area of the screen; usually referred to as dpi (dots per inch).一般我们的密度的单位是像素数目/平方英寸,但是这里推荐了一个新的密度表示方法,就是每英寸的像素数目(dpi)。我们以后用到的密度就是这个dpi

         android里用分辨率和密度这两个域来记录设备的真实尺寸,采用密度的主要原因(学渣猜的)应该是“去英寸化”,即在程序中不要出现英寸这个单位,因此用密度和分辨率这两个值可以保存设备的真实尺寸。

        对于一个程序而言,它可以获取到屏幕的分辨率和尺寸,进而密度=分辨率/尺寸,可以算出尺寸,在android里,获取密度尺寸可以参考这里我们这里用一个小程序来求两个设备的分辨率和密度。学渣定义了两台avd,尺寸都是4.7英寸,设备1的分辨率为800*1280,设备2的分辨率为480*800,测试代码如下:

    package com.example.testscreen;
    
    import android.os.Bundle;
    import android.app.Activity;
    import android.util.DisplayMetrics;
    import android.view.Menu;
    
    public class MainActivity extends Activity {
    	@Override
    	protected void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.activity_main);
    		
    		 DisplayMetrics metrics = new DisplayMetrics();
    		 getWindowManager().getDefaultDisplay().getMetrics(metrics);
    		 
    		 //得到设备的分辨率,即宽和高的像素数目
    		 int height = metrics.heightPixels;
    		 int width = metrics.widthPixels;
    		 
    		 System.out.println("the height is "+height +" the width is" + width);
    		 
    		 //得到设备的密度
    		 int density = metrics.densityDpi;
    		 System.out.println("the density is " + density);
    		
    	}
    }
    

    设备1的输出是:

    06-09 00:10:17.188: I/System.out(2041): the height is 1184 the width is768
    06-09 00:10:17.188: I/System.out(2041): the density is 320

    设备2的输出是:

    06-09 00:45:35.085: I/System.out(2088): the height is 736 the width is480
    06-09 00:45:35.085: I/System.out(2088): the density is 213

        从两个设备的输出可以知道,其实学渣是定义了两个4.7英寸的avd,但是有着不同的分辨率,(android里有底部栏,看起来有点不一样),这两个例子说明了一个问题:相同大小的手机,可以有不同的分辨率,进而就有不同的密度喽,(因为密度=分辨率/大小)。

    3 程序判断屏幕大小

          每个程序都需要判定屏幕的大小,进而选择合适的布局(后面会说),如何判定大小(设备的真实尺寸,可以理解为设备对角线的英寸数)呢,就根据2所提到的两个参数来判断,一个是分辨率,一个是密度,用设备1而言,知道height是1184像素(px),其密度为320dpi(像素/英寸),则高度的具体值就是1280/320=4(英寸),宽度为800/320=2.5 ,用勾股定理算出对角线的长度,(学渣这里没有细算)再和图1匹配,得到这个设备的屏幕大小尺寸。

          屏幕大小判定之后,首先需要在mainfest声明支持的屏幕大小,如:

    <supports-screens android:largeScreens="true" />

                 要想要好的用户体验,程序可以根据不同的大小选择不同的布局,android官方文档里也提到了,可以对不同的大小,设置不同的layout,如res/layout-large就是large屏幕时所采用的布局。

        官方文档里有这么几句话要注意:Beginning with Android 3.2 (API level 13), the above size groups are deprecated and you should instead use the sw<N>dp configuration qualifier to define the smallest available width required by your layout resources. For example, if your multi-pane tablet layout requires at least 600dp of screen width, you should place it inlayout-sw600dp/.即对于3.2以上的,直接采用dp(dp相当于一种程序中的英寸大小)进行判断屏幕的宽度,进而选择不同的布局,如/res/layout-sw600dp,就是宽度要求是600dp以上的我们就选择这个布局。不过意思和small,large等一样,只不过把大小换成了具体的数字。

    3 去英寸化 

       上面我们提到了去英寸化,如何让一个程序能够很好的显示大小呢,似乎可以采用像素?但是这是完全不可以的。先举一个简单的例子说明像素的缺陷,还是采用上述的设备1和设备2进行测试,我们在设备1和设备2都定义一个button,宽度和高度都为200px(像素),效果如图2所示:


    图2 相同大小的手机,相同的像素大小的button

          其实这个结果一点也不意外,这是因为两个button的像素大小虽然一样,但是密度不同,而最后的真实大小是按照英寸来画的,因为密度=像素/英寸,则 真实大小(英寸数)=像素/密度。那么这个问题怎么破,因为我们的程序一定是在相同大小的屏幕上有相同的大小,如果两个空间的大小一样,则是其英寸数相等,而英寸数又不能直接写在程序里,于是乎出现一个逆天的术语,dp。其实在2里我们看到过这个dp,那么什么是dp呢?

           dp在官网里叫Density-independent pixel (dp),即密度无关的像素,即可以摆脱密度的缠绕,就是前面我所提到的一种具有“去英寸化”功能的新的单位,我们先不提dp的具体计算(后面会说),我们就先假设这个dp就是一个全新的度量单位,让相等的dp在不同密度的屏幕里有相等的长度,比如1dp无论你是在设备1还是设备2,大小都是相等。这就是解决了“去英寸化”的问题。

    4 dp的应用与图片问题

       通过3的描述,我们应该可以知道,在layout里任何的控件都采用dp就可以保证显示一致的问题了。这也是google所推荐的。

        但是对于图片这种外来户,我们可以规定它在layout中的大小,假如我们规定了图片的宽度1英寸(可以转为dp,后面会将),对于一张图片,其真实的宽度为15像素,在密度为3dpi的屏幕中,可以显示3个像素,这时需要丢掉12个像素,图片一定极为不清晰;在密度为15dpi的屏幕里可以显示15个像素,显示完全。这就有了分辨率的问题,在宽度都为1英寸的情况下,肯定是能够显示全部15个像素的图片清晰,怎么能让不同密度的屏幕显示的照片都比较清晰呢,我们可以对不同密度的屏幕选择不同的图片,即高密度选择高清图片。对于任何一张图片,我们都可以做三张,一张低分辨率,一张高分辨率,一张中间值,对于高密度的屏幕,比如密度为15,我们选择一张分辨率较高的图片(就是大的图片),如15英寸的,对于密度为3的,我们让它显示一张分辨率为3的,则保证了不会丢失信息,从而保证图片清晰。

        对于不同密度的屏幕,可以通过/res/drawable-hdpi等进行选择图片。这个官网也有。

    5 dp的计算  

        其实我们没必要对dp进行计算,但是为了便于理解,我还是把dp的计算说一下, px = dp * (dpi / 160).这是官网的计算公式。对于一个密度为160dpi的屏幕而言,一个px就等于一个dp。。。。

       另外:android里字体的大小采用sp,具体的还没有研究,不过作用估计和dp差不多。

    这篇博客花了学渣一个中午的时间,对于android的学习,学渣认为应该以官网为主要参考,如果本文内容有误,欢迎指出,谢谢!

    展开全文
  • android屏幕适配

    千次阅读 2016-07-22 00:38:20
    设备机型不同导致屏幕大小和分辨率(Resolution)不同(碎片化),但是无论分辨率有多大,屏幕有多大,我们手指触控范围的百分比应该一样,适配一般就是要达到目标控件在所有机器里面屏占比一样大(当然,我认为这...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 43,016
精华内容 17,206
关键字:

android屏幕适配