Android中的屏幕适配

一、屏幕适配的个人理解

                跌跌撞撞也好,摸爬滚打也罢。在Android编程圈子中也徘徊一年有余。对于较多基础概念并不十分清楚,现在是时候回到更贴近底层的地方去的时候了。

            Android系统的硬件覆盖电子产品的方方面面,这也是硬件屏幕多样化,形成Android碎片化重要原因。碎片化是一个难题,但并不表示,Android程序开发就不必做兼容考虑。所以,屏幕适配成为其中很重要的环节。

           在市面上依旧没有一劳永逸,一次适配所有的绝佳方案。但是,我们可以应用现有的技术手段能够将我们App适用对象优化到更好,逐渐靠近百分百。通过不断地创新与优化,找到最后的解决途径。以下,将来聊聊实际中的适配处理。

1,适配中的核心关键词

           dpi:像素密度比,是指在固定的物理长度下的像素数量。【dot per inch】

           dp[dip]:屏幕无关像素,不是物理长度,也不是像素点。只有在具体的像素密度比下,可以转换为像素。dp*dpi = px;一款手机已经定制成功,像素密度比确定,dp也确定。

           屏幕分辨率:屏幕高和宽的像素数。分辨率类型大致有:1920*1080(xxh);1280*720(xh);960*540,800*400,854*480(h);480*320(m);240*320(l);

          low:medium:high:extra-high:extra-extra-high=3:4:6:8:12,即是:ldpi:mdpi:hdpi:xhdpi:xxhdpi=3:4:6:8:12。

不同像素密度下合理展示图标大小:


2,适配的理解

         适配的理解就是在程序运行的时候,程序在不同硬件上能够展示如设计那样的效果。

        不适配的情形有:带文字的控件宽度不够,文字展示不全;图标,Bar,按钮过小或者过大。

个人理解,需要做好Android系统硬件的适配,需要分为两个方面:

        (1)同一分辨率下,不同屏幕大小【手机 -- IPad -- 电视】;

        (2)同一屏幕尺寸下,不同屏幕分辨率。

         对于第一种情形,处理的更多方式是直接另起一个APP,其内置展示页面以及业务逻辑,因为屏幕之间巨大的差异,已经发生了质的变化,甚至可以说是不同的APP。

         手机本身也存在多种尺寸,但因为其相差不是很大,屏幕长宽的比例依旧保持相差不大。也归纳到同一屏幕尺寸下,不同分辨率的适配。

         当然,在同一APP中,也能够实现屏幕尺寸发生巨大差异的处理。其维护及实现复杂度相比于再开启一个APP的代价似乎更大。有这个方面的兴趣,可以更多研究。Android屏幕适配经验谈 值得你拥有。&_& &_& &_& 当然,这个Android屏幕适配全攻略 也匹配的上更多的深研。

         以下,将实现以“同一”硬件尺寸下的Android系统硬件适配。

二、屏幕适配的方法

1,布局方面

          多使用LinearLayout,RelativeLayout,不使用绝对布局(现在已经过时);

2,控件属性

          多使用match_parent/wrap_content;可使用dp/sp,不使用px(Android Studio中已经有提醒);

3,权重

          在长度/宽度为0dp时,使用layout_weight,垂直/水平根据权重分割父控件的对应高度/宽度。

<?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"
    android:orientation="vertical">
    <TextView
        android:id="@+id/desc_1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="布局适配"
        android:textSize="26sp" />
    <!--布局适配-->
    <EditText
        android:id="@+id/body_et"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/desc_1" />

    <Button
        android:id="@+id/body_ensure"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_below="@+id/body_et"
        android:text="确认"
        android:textSize="26sp" />

    <Button
        android:id="@+id/body_search"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/body_et"
        android:layout_toLeftOf="@+id/body_ensure"
        android:text="搜索"
        android:textSize="26sp" />


    <View
        android:id="@+id/divider"
        android:layout_width="match_parent"
        android:layout_height="2dp"
        android:layout_below="@+id/body_search"
        android:background="@color/red" />


    <!--单位适配-->
    <TextView
        android:id="@+id/desc_2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/divider"
        android:text="单位适配"
        android:textSize="26sp" />

    <Button
        android:id="@+id/bt1"
        android:layout_width="150dp"
        android:layout_height="wrap_content"
        android:layout_below="@+id/desc_2"
        android:text="dp"
        android:textSize="26sp" />

    <Button
        android:layout_width="200px"
        android:layout_height="wrap_content"
        android:layout_below="@+id/desc_2"
        android:layout_toRightOf="@+id/bt1"
        android:text="px"
        android:textSize="26sp" />

    <!--权重适配-->
    <View
        android:id="@+id/divider2"
        android:layout_width="match_parent"
        android:layout_height="2dp"
        android:layout_below="@+id/bt1"
        android:background="@color/red" />

    <TextView
        android:id="@+id/desc_3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/divider2"
        android:text="权重适配"
        android:textSize="26sp" />

    <LinearLayout
        android:id="@+id/ll_1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/desc_3"
        android:orientation="horizontal">

        <Button
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="横向权重: 1 "
            android:textSize="26sp" />

        <Button
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="横向权重: 1"
            android:textSize="26sp" />
    </LinearLayout>
    <!--权重适配-->
    <View
        android:id="@+id/divider3"
        android:layout_width="match_parent"
        android:layout_height="2dp"
        android:layout_below="@+id/ll_1"
        android:background="@color/red" />

    <LinearLayout
        android:id="@+id/ll_2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/divider3"
        android:orientation="vertical">

        <Button
            android:layout_width="wrap_content"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:text="纵向权重: 1"
            android:textSize="26sp" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:text="纵向权重: 1"
            android:textSize="26sp" />
    </LinearLayout>

    <View
        android:id="@+id/divider4"
        android:layout_width="match_parent"
        android:layout_height="2dp"
        android:layout_below="@+id/ll_2"
        android:background="@color/red" />

</RelativeLayout>
          适配效果:

布局适配:


整体适配效果:


单位适配:


4,使用硬件单位化

         将手机屏幕虚拟的的划分成为固定的份数,以320*480为例,生成对应分辨率资源文件。

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(768, 1280);//nexus 4
        makeString(800, 1280);
        makeString(1080, 1812);
        makeString(1080, 1920);
        makeString(1440, 2560);
        makeString(1536, 2048);//nexus 9
        makeString(2560, 1600);//nexus 10
    }

    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;
    }
              java生成文件放置在res/目录下。


使用:

    <Button
        android:layout_width="@dimen/x160"
        android:layout_height="@dimen/x240" />
效果:


弊端:当没生成对应分辨率的文件时,展示效果为空白,如Nexus 7所示。并且生成文件一直在APP中,相对较耗存储空间。

5,图片适配

            依据不同分辨率,切出对应分辨率的图片,可实现背景、按钮、图片、TabBar、Icon等的屏幕适配。

切图比例如图所示:


为了缩小App的体积,且多套图是不太建议的。可以采用切大图及市场占有率最高的两套来适配所有。

图片适配遍历的流程:


           图片适配还可以采用.9图片来实现。在.9图片的制作中,请注意每边都留上2px,即是不让边框线完全没有。同时也注意缩放范围。保持最核心图标的合理变形,整体符合视觉效果的合理缩放。

           Android SDK中提供了编辑9-Patch图片的工具,在tools目录下draw9patch.bat,能够立刻看到编辑后的拉伸效果。


6,百分比屏幕适配

            浏览器中,Web程序展示的屏幕变化并不会少于手机样式,但是很少出现适配问题。是多采用比例布局的缘故。在Android5.0中,新增百分比布局。

<?xml version="1.0" encoding="utf-8"?>
<android.support.percent.PercentRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.percent.PercentRelativeLayout
        android:id="@+id/rl1"
        android:layout_width="match_parent"
        android:layout_height="50dp">

        <Button
            android:id="@+id/bt1"
            android:layout_width="200dp"
            android:layout_height="match_parent"
            android:text="百分布局的固定宽度"
            android:textSize="18sp" />

        <Button
            android:id="@+id/bt2"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_toRightOf="@+id/bt1"
            android:background="@color/blue"
            android:text="比例:50%"
            android:textSize="20sp"
            app:layout_widthPercent="50%" />

        <Button
            android:id="@+id/bt3"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_toRightOf="@+id/bt2"
            android:background="@color/red"
            android:text="比例:50%"
            android:textSize="20sp"
            app:layout_widthPercent="50%" />

    </android.support.percent.PercentRelativeLayout>

    <android.support.percent.PercentRelativeLayout
        android:id="@+id/rl2"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:layout_below="@+id/rl1">

        <Button
            android:id="@+id/bt4"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:background="@color/green"
            android:text="比例:30%"
            android:textSize="20sp"
            app:layout_widthPercent="30%" />

        <Button
            android:id="@+id/bt5"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_toRightOf="@+id/bt4"
            android:background="@color/purple"
            android:text="比例:40%"
            android:textSize="20sp"
            app:layout_widthPercent="40%" />

        <Button
            android:id="@+id/bt6"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_toRightOf="@+id/bt5"
            android:background="@color/gold"
            android:text="比例:30%"
            android:textSize="20sp"
            app:layout_widthPercent="30%" />

    </android.support.percent.PercentRelativeLayout>

    <Button
        android:id="@+id/bt7"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_below="@+id/rl2"
        android:text="纵向百分布局:20%"
        app:layout_heightPercent="20%" />

    <Button
        android:id="@+id/bt8"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_below="@+id/bt7"
        android:background="@color/navy"
        android:text="纵向百分布局:20%"
        app:layout_heightPercent="20%" />

</android.support.percent.PercentRelativeLayout>
布局展示效果:


百分布局中,控件是相对与父控件的对应属性。所以,在指定过某些控件的固定长度后,依旧不能完全适配。如视图第一行所示。在完全分割父控件对应属性100%的情形下,百分布局的适配性很好。


三、个人感慨

             编程路上因为有很多兴趣相似、相同的人共同前行而变得更有意义。若你看到这篇文章,有什么建议、优化记得分享一下哦~_~

             一个普通男孩,充实着自己的脑袋,也把这个作为一个标注。愿大家前行更美好~~

戳这里,有源码~_~


专注下来!!!!【  让一件事的发生成为必然   】

                                                                                                每篇一句鼓励,愿你我前行更美好~~
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

壹叁零壹

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值