Android 屏幕适配全攻略(中)-从九宫格到矢量图,揭秘Android多屏幕适配的正确打开方式


在移动互联网时代,无论是小小的手机屏幕,还是大大的平板显示器,Android 应用都必须做到完美适配,给用户以极佳的体验。本文将剖析 Android 多屏幕适配背后的种种技术细节,为您揭开最佳实践的正确打开方式,让您的应用在任何设备上都能呈现出最专业、最优雅的一面。


一、Android 布局适配


布局适配主要包括以下几个方面:

  1. 使用合理的布局方式
    • 选择合适的布局容器,如 LinearLayoutRelativeLayoutConstraintLayout 等。
    • 合理地使用 wrap_contentmatch_parent 等属性来根据内容自适应布局大小。
    • 适当使用 weight 属性来实现动态布局。
  2. 使用多尺寸资源
    • res/layout-* 目录下提供不同屏幕尺寸的布局文件。
    • res/values-* 目录下提供不同屏幕尺寸的尺寸资源。
    • res/drawable-* 目录下提供不同屏幕尺寸的图片资源。
  3. 动态适配布局
    • 在代码中动态获取屏幕尺寸和密度信息。
    • 根据获取的信息动态调整 UI 元素的大小和位置。
  4. 适配不同屏幕方向
    • res/layout-land 目录下提供横屏布局文件。
    • 在代码中监听屏幕方向变化,动态切换布局。

下面示例,演示如何在 Java 代码中动态适配布局:

public class MainActivity extends AppCompatActivity {

    private TextView textView;
    private FrameLayout.LayoutParams layoutParams;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        textView = findViewById(R.id.text_view);
        layoutParams = (FrameLayout.LayoutParams) textView.getLayoutParams();

        // 获取屏幕尺寸和密度信息
        DisplayMetrics displayMetrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
        int screenWidth = displayMetrics.widthPixels;
        int screenHeight = displayMetrics.heightPixels;
        float density = displayMetrics.density;

        // 根据屏幕尺寸和密度动态调整 TextView 的大小和位置
        int textViewWidth = (int) (200 * density);
        int textViewHeight = (int) (100 * density);
        layoutParams.width = textViewWidth;
        layoutParams.height = textViewHeight;
        layoutParams.gravity = Gravity.CENTER;
        textView.setLayoutParams(layoutParams);
    }
}

在这个示例中,我们首先获取了当前设备的屏幕尺寸和密度信息。然后,根据这些信息动态地调整了 TextView 的大小和位置,确保它在不同设备上显示的效果一致。


二、使用限定符资源,轻松匹配不同屏幕尺寸


1、什么是限定符资源?

  • 限定符资源是 Android 用于支持多种设备屏幕尺寸和密度的一种机制。

  • 开发者可以在应用的资源目录下创建多个不同的资源文件夹,每个文件夹都包含了针对特定设备特征的资源文件。

  • 当应用运行在某台设备上时,Android 系统会根据该设备的特征,自动选择最匹配的资源文件夹,并加载相应的资源。


2、常见的限定符

  • 屏幕尺寸: small, normal, large, xlarge

  • 屏幕密度: ldpi, mdpi, hdpi, xhdpi, xxhdpi, xxxhdpi

  • 屏幕方向: port (portrait), land (landscape)

  • 语言和地区: en, fr, zh-rCN, zh-rTW 等

  • Android 版本: v21, v23, v26 等


3、如何使用限定符资源


在这里插入图片描述

(1)、在应用的res目录下,创建不同的资源文件夹,并在文件夹名称中添加相应的限定符:

  • res/layout/:默认布局文件

  • res/layout-large/:针对大屏幕设备的布局文件

  • res/layout-land/:针对横屏设备的布局文件

  • res/drawable-hdpi/:针对高密度设备的图片资源

  • res/values-zh-rCN/:针对中国大陆地区的字符串资源


(2)、在代码中,直接引用这些资源文件即可

Android 系统会根据设备特征自动选择合适的资源文件。

  • 假设我们有以下几个资源文件:

    • res/layout/activity_main.xml
    • res/layout-large/activity_main.xml
    • res/layout-land/activity_main.xml
    • res/drawable-hdpi/my_image.png

  • 在 Java 代码中,我们可以这样使用这些资源:

    // 加载布局文件
    setContentView(R.layout.activity_main);
    
    // 获取图片资源
    ImageView imageView = findViewById(R.id.my_image);
    imageView.setImageResource(R.drawable.my_image);
    
    // 获取字符串资源
    String myString = getString(R.string.my_string);
    

  • 当应用运行在不同的设备上时,Android 系统会自动选择最合适的资源文件进行加载。例如:

    • 在小屏幕设备上,使用 res/layout/activity_main.xml
    • 在大屏幕设备上,使用 res/layout-large/activity_main.xml
    • 在横屏设备上,使用 res/layout-land/activity_main.xml
    • 在高密度设备上,使用 res/drawable-hdpi/my_image.png

二、九宫格图片适配


除了布局适配,图片资源的适配同样很关键。我们可以为不同分辨率提供对应分辨率的图片:

res/drawable-mdpi/image.png
res/drawable-hdpi/image.png 
...

不过这种做法会使 APK 体积变大。从 Android 4.0 开始,就可以使用九宫格图片 (.9.png) 来渲染可拉伸的资源。


1、什么是九宫格图片资源?

九宫格图片资源(Nine-Patch Images)是一种特殊的图片格式,它可以根据图片的内容自动拉伸或缩放,而不会造成图片失真或模糊。它通常用于实现可伸缩的 UI 元素,如按钮、对话框等。


九宫格图片由以下9个区域组成:

  • 四个角落区域(不可拉伸)

  • 上下中间区域(只能水平拉伸)

  • 左右中间区域(只能垂直拉伸)

  • 中间区域(可以水平和垂直拉伸)


在这里插入图片描述


2、如何使用九宫格图片资源?


(1)、创建九宫格图片

  • 在 Android Studio 的 drawable 文件夹中创建一个以 .9.png 结尾的文件,表示这是一个九宫格图片。
  • 使用图像编辑工具(如 GIMP、Photoshop 等)绘制图像,并在图像的左侧和上侧添加黑色像素边框。这些额外的边框将定义图像的可拉伸区域。

(2)、在布局中使用九宫格图片

  • 在 XML 布局文件中,将九宫格图片资源设置为 View 的背景:

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/my_nine_patch" />
    

(3)、在代码中使用九宫格图片

  • 可以使用NinePatchDrawable类动态创建和应用九宫格图片:

    // 从资源文件中获取九宫格图片
    NinePatchDrawable drawable = (NinePatchDrawable) ContextCompat.getDrawable(context, R.drawable.my_nine_patch);
    
    // 设置九宫格图片为 View 的背景
    view.setBackground(drawable);
    

下面示例,演示如何使用九宫格图片资源:

import android.content.Context;
import android.graphics.drawable.NinePatchDrawable;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;

public class NinePatchExampleActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_nine_patch_example);

        // 获取 LinearLayout
        LinearLayout container = findViewById(R.id.container);

        // 创建 3 个 Button
        for (int i = 0; i < 3; i++) {
            Button button = createButton(this);
            container.addView(button);
        }
    }

    private Button createButton(Context context) {
        // 创建 Button
        Button button = new Button(context);
        button.setText("Nine-Patch Button");

        // 获取九宫格图片资源
        NinePatchDrawable drawable = (NinePatchDrawable) ContextCompat.getDrawable(context, R.drawable.my_nine_patch);

        // 设置九宫格图片为 Button 的背景
        button.setBackground(drawable);

        // 设置 Button 的宽度和高度
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
                LinearLayout.LayoutParams.WRAP_CONTENT,
                LinearLayout.LayoutParams.WRAP_CONTENT
        );
        button.setLayoutParams(params);

        return button;
    }
}

在这个示例中,我们创建了一个 NinePatchExampleActivity。在 onCreate() 方法中,我们获取 LinearLayout 容器,并动态创建了 3 个 Button


createButton() 方法中,我们首先创建一个 Button 对象,并设置它的文本为"Nine-Patch Button"。然后,我们使用 ContextCompat.getDrawable() 获取九宫格图片资源,并使用 NinePatchDrawable 类将其设置为 Button 的背景。最后,我们设置 Button 的宽度和高度,并返回 Button 对象。


当你运行这个程序时,你会看到 3 个使用九宫格图片资源作为背景的 Button。无论 Button 的大小如何变化,它们的外观都不会失真。

通过这个示例,相信你已经掌握了如何在 Android 开发中使用九宫格图片资源进行适配的基本方法。这种技术可以帮助你创建出更加美观、适配性强的 UI 元素。


随后 Android 5.0 又推出了矢量图形式,可自动缩放且不失真,这成为图片适配的最佳选择。


四、矢量图形式适配


1、为什么要使用矢量图?


在 Android 开发中,我们通常会使用位图图像(如 PNG、JPEG 等)来作为应用程序的图标和UI元素。但是,这种方式存在一些问题:


  • 图像质量下降

    当位图图像在不同分辨率的设备上显示时,可能会出现图像质量下降的问题。这是因为位图图像是由固定大小的像素组成的,在进行缩放时会导致失真。


  • 文件体积增大

    为了适配不同分辨率的设备,开发者通常需要准备多套不同尺寸的图像资源,这会大大增加应用程序的安装包体积。


为了解决这些问题,Android 提供了矢量图形式(Vector Drawable)作为一种新的图像资源格式。矢量图使用可缩放的数学公式来描述图形,能够在任何分辨率下保持优质的图像质量,同时文件体积也相对较小。


2、如何使用矢量图进行屏幕适配?


(1)、创建矢量图资源

  • 您可以使用 Android Studio 自带的 Vector Asset Studio 工具来创建矢量图资源。

  • 也可以使用其他矢量图编辑工具(如 Adobe Illustrator、Sketch 等)来创建 SVG 格式的矢量图,然后导入到 Android Studio 项目中。


(2)、在布局中使用矢量图

  • 在 XML 布局文件中,使用 <vector> 标签来引用矢量图资源:

    <ImageView
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:src="@drawable/my_vector_icon" />
    

(3)、在代码中使用矢量图

  • 在 Java 代码中,可以使用 VectorDrawableCompat 类来加载和使用矢量图资源:

    Drawable vectorDrawable = VectorDrawableCompat.create(getResources(), R.drawable.my_vector_icon, null);
    imageView.setImageDrawable(vectorDrawable);
    

(4)、适配不同屏幕密度

  • 矢量图本身是可缩放的,因此不需要为不同屏幕密度准备多套图像资源。

  • 但是,仍然需要为不同的屏幕密度提供合适的图标尺寸,以确保在各种设备上都能够正常显示。

  • 可以使用 VectorDrawableCompat.create 方法,并传入 DisplayMetrics 对象来动态调整图标大小

    DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
    float density = displayMetrics.density;
    Drawable vectorDrawable = VectorDrawableCompat.create(getResources(), R.drawable.my_vector_icon, null);
    vectorDrawable.setBounds(0, 0, (int)(48 * density), (int)(48 * density));
    imageView.setImageDrawable(vectorDrawable);
    

(5)、使用矢量图进行屏幕适配完整案例

下面是一个完整的 Java 代码示例,演示如何在 Android 中使用矢量图进行屏幕适配:

import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.widget.ImageView;

import androidx.appcompat.app.AppCompatActivity;
import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;

public class VectorDrawableActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_vector_drawable);

        ImageView imageView = findViewById(R.id.image_view);
        loadVectorDrawable(this, imageView, R.drawable.my_vector_icon, 48);
    }

    private void loadVectorDrawable(Context context, ImageView imageView, int vectorDrawableId, int desiredSizeDp) {
        DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
        float density = displayMetrics.density;
        int desiredSizePx = (int) (desiredSizeDp * density);

        Drawable vectorDrawable = VectorDrawableCompat.create(context.getResources(), vectorDrawableId, null);
        vectorDrawable.setBounds(0, 0, desiredSizePx, desiredSizePx);
        imageView.setImageDrawable(vectorDrawable);
    }
}

在这个示例中,我们首先在 onCreate() 方法中加载了一个矢量图资源并将其设置到 ImageView 上。

然后,我们定义了一个 loadVectorDrawable() 方法,它接受四个参数:

  • context: 上下文对象

  • imageView: 要设置矢量图的 `ImageView``

  • ``vectorDrawableId`: 矢量图资源的 ID

  • desiredSizeDp: 期望的图标尺寸(以 dp 为单位)


在方法内部,我们首先获取设备的屏幕密度,并根据期望的尺寸计算出实际的像素尺寸。然后,我们使用 VectorDrawableCompat.create() 方法加载矢量图资源,并设置其大小,最后将其设置到 ImageView 上。


通过这种方式,我们可以在不同的屏幕密度下都能正确、清晰地显示矢量图,同时也大大减少了应用程序的安装包体积。

结语:

总之,随着各种全面屏、异形屏和可折叠屏的出现,Android 屏幕适配也变得越发重要和复杂。相信通过本文的详尽指导,您已经掌握了多屏幕适配的方方面面。不过在实际应用中屏幕适配永无止境, 还可能会遇到哪些其他问题和挑战呢?就让我们拭目以待,继续在这方面的实战中去探索和总结吧!


  • 22
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

w风雨无阻w

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

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

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

打赏作者

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

抵扣说明:

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

余额充值