屏幕适配

因为安卓设备的开放性,有很多的厂家都可以对安卓系统进行定制,市场上就出现了碎片化,也出现了各种各样的设备,不同的设备就有不同的需求,如果把所有的设备都使用的是一套方案肯定是不行的

下面我就结合着对慕课网视频的学习来写如何进行屏幕适配,慕课网视频地址

然后这个视频的主讲老师也写了一篇博客整理的非常清楚

http://blog.csdn.net/zhaokaiqiang1992/article/details/45419023

最后我通过我的理解整理了下面的内容

这次博客的适配内容主要包括以下几个部分
- 相关概念
-解决方案
- 实施自适应用户界面流程

相关概念

  • 屏幕尺寸
  • 分辨率
  • 屏幕像素密度
  • 单位介绍
屏幕尺寸

概念:屏幕尺寸就是对角线的长度
单位是英寸,1英寸=2.54cm,比如说 4.7,5.0,5.5一些尺寸

我以前误解以为屏幕的适配主要和屏幕的尺寸有关,其实和下面的分辨率也有很大的关系,这个作为一个了解

分辨率

概念:横纵方向上的像素点数
一般一个屏幕的分辨率越高,屏幕显示的就会越清晰
单位是px 1px=1个像素点

1920 x 1080 就是指 纵向像素*横向像素

像素密度

概念:每英寸上的像素点数

单位是dpi

屏幕像素密度与屏幕尺寸和屏幕分辨率有关

计算公式举例:(√(1920²+1080²))/4.9

这个就是对角线上的像素点数/屏幕尺寸

单位介绍

1.dp,dip

密度无关像素,以160dpi为基准,1dip=1px

如果密度是320dpi,则1dip=2px,以此类推

2.px

这个是像素的单位

为什么我们常用dp很少用px作为长度单位

假如同样都是画一条320px的线,在480x800分辨率手机上显示为2/3屏幕宽度,在320x480的手机上则占满了全屏,如果使用dp为单位,在这两种分辨率下,160dp都显示为屏幕一半的长度。

3.sp

sp设置文字的大小,最好不用奇数,一般会造成精度的丢失

4.mdip,dip,xdip,xxdip,不同的像素密度区分

这里写图片描述

所以我们可以计算出手机的像素密度,就知道该手机会调用哪个包下的图片了

解决方案

  • 支持各种屏幕尺寸
    • weight的使用
    • 限定符
    • 图片的自动拉伸
  • 支持各种屏幕密度
  • 实施自适应用户界面流程
支持屏幕尺寸

注意事项
- 使用wrap_content,math_parent,weight
- 使用相对布局,禁用绝对布局
- 使用限定符 large,sw600dp,小案例
- 使用自动拉伸图

1.weight方法的使用

只能在LinearLayout使用,对于想要改变的那边使用0dp

那么weight的宽度是如何给出的

设:

一个Button1 宽=match_parent , weight= 2

一个Button2 宽match_parent, weight= 1

这时候可能会认为第一个weight设置的大,所以会占据2/3的空间,但其实不是这样的

这里写图片描述          这里写图片描述

为什么第一个的weight大但是占据的宽度却小呢

显示的宽度=父控件的宽度+剩余空间所占百分比的宽度

首先设父控件的宽度是L,两个btn的宽度都为match_parent,所以两个空间的宽度和为2L,剩余的为L

显示宽度=L+(L-2L)*1/3=2/3L

由此可知如果设置成宽度为0dp则就是正常的比例了

2.使用限定符
有的时候我们的设备是平板,平板的宽度是比普通的手机要宽的,所以在设计的时候常常把它分成两栏,如图
这里写图片描述
左边一栏可以看做一个导航,右边显示的是正文内容

首先我们要为不同的设备创建好不同的布局

单面板布局:res/layout/main.xml

多面板布局:res/layout-large/main.xml 3.2之前的版本

多面板布局:res/layout-sw600dp/main.xml 3.2之后的版本

或者最后两个可以整合为:res/layout/main_twopanes.xml

内容的话普通手机和平板也会不一样

手机中的布局,只有一个显示内容的区域,就是一个Fragment

<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:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/headlines"
        android:name="show.xbl.com.shipeidemo.HeadlinesFragment"
        />

</LinearLayout>

平板的布局,一边是导航栏一边是显示内容的区域,所以有两个Fragment

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal" android:layout_width="match_parent"
    android:layout_height="match_parent">
    <!--多面板,宽屏-->
    <fragment
        android:layout_width="400dp"
        android:layout_height="match_parent"
        android:id="@+id/headlines"
        android:name="show.xbl.com.shipeidemo.HeadlinesFragment"/>
    <fragment
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:name="show.xbl.com.shipeidemo.ArticleFragment"
        android:id="@+id/article"/>

</LinearLayout>

有这么多的资源文件而且名字不同,怎样才能归结到一起,整成相同的名字

—那么就要使用资源文件来调布局的文件,这样直接调用大家相同的名字让手机系统自动适配下面的布局

res/values/layout.xml

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

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>

同样还有屏幕方向限定符
横向:res/values-sw600dp-land/layouts.xml

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

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

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

最后调用,让系统自动匹配就好啦

setContentView(R.layout.main);

比如:
适配的屏幕要求如下

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

3. 图片的拉伸
①eclipse所带的图片拉伸软件

位置在:安装包下SDK文件→tools→draw9patch.bat

②AndroidStudio自带的图片拉伸软件
双击点击点击想要拉伸的.9图片就可以自动拉伸了

注意事项

再使用.9图片进行拉伸的时候,点点的位置不要经过图片的内容区域,否则内容区域也会被拉伸

将图片想要拉伸的上边框,左边框描黑边,为可拉伸的部分

图片的四个顶点不要拉伸

如果是黑边在左边,则左边向右边相同长度的整个区域都可以被上下拉伸

支持各种屏幕密度
  • 使用非密度制约像素 —使用dp和sp
  • 提供备用的位图

1.因为分辨率不一样,所以不能用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高清设计图给你之后,你就可以根据设计图上的尺寸,以某一个分辨率的机型为基础,找到对应像素数的单位,然后设置给控件即可。

这里写图片描述
这里写图片描述

2.提供备用的位图

如果一个ImageView调用当前手机分辨率下的drawable分辨率下的图片,这个时候占用的内存是最小的

如果在当前分辨率下没有所对应的drawable文件夹,ImageView调用与分辨率不符的图片的时候会对图片进行压缩处理,导致占用内存

实施自适应用户界面流程

  • 确定当前布局—判断当前是单面板还是双面板,并且每一块的布局是怎样的
  • 根据当前布局做出响应—单面板的话首先要点击不同的item跳转到不同的界面,双面板左边是导航右边直接是界面
  • 重复使用其他活动中的片段—fragment的使用,集中处理界面
  • 处理屏幕适配变化—屏幕宽的时候顶部的导航可以全部显示出来,手机屏幕的时候可以将顶部的导航做成一个popupWindow
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值