Android 的适配

Android 适配的重要概念

  • 什么是屏幕尺寸、屏幕分辨率、屏幕像素密度?
  • 什么是dp、dip、dpi、sp、px?他们之间的关系是什么?
  • 什么是mdpi、hdpi、xdpi、xxdpi?如何计算和区分?

屏幕尺寸

  • 屏幕尺寸指的是屏幕的对角线的长度,单位是英寸,1英寸=2.54厘米
  • 比如常见的屏幕尺寸5.0英寸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值。

名称 像素密度范围
mdpi 120dpi~160dpi
hdpi 160dpi~240dpi
xhdpi 240dpi~320dpi
xxhdpi 320dpi~480dpi
xxxhdpi 480dpi~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),依此类推。

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

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

解决方案

支持各种屏幕尺寸

  • 使用wrap_content、match_parent、weight
  • 使用相对布局,禁用绝对布局

因为分辨率不一样,所以不能用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;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android适配是指将应用程序在不同的Android设备上进行优化和调整,以确保应用能够在各种屏幕尺寸、分辨率和设备类型上正常运行。适配涉及到以下几个方面: 1. 布局适配:根据不同屏幕尺寸和分辨率调整布局,保证界面元素的合理排列和显示效果。可以使用ConstraintLayout、LinearLayout等布局管理器来实现自适应布局。 2. 图片适配:提供不同分辨率的图片资源,并根据设备的屏幕密度加载合适的图片。可以通过资源文件夹的命名方式(如drawable-hdpi、drawable-xhdpi等)来管理不同分辨率的图片。 3. 字体适配:根据设备的屏幕密度和用户设置的字体大小,调整应用中的文字大小和样式。可以使用sp(可缩放像素)作为字体大小的单位,以支持用户自定义字体大小。 4. 功能适配:根据设备的硬件特性和系统版本,判断是否支持某些功能或API,并进行相应的处理。可以使用特定的API或兼容性库来实现功能适配。 5. 版本适配:针对不同的Android版本,处理其特有的行为和API差异。可以使用条件判断、动态加载类等方式来处理不同版本的兼容性问题。 6. 设备适配:根据设备的硬件特性和屏幕尺寸,调整应用的功能和界面。可以使用资源限定符、特定的API等来实现设备适配。 以上是Android适配的一些常见方面,具体的适配策略和方法,可以根据应用的需求和目标设备的特点进行选择和实施。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值