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 屏幕适配也变得越发重要和复杂。相信通过本文的详尽指导,您已经掌握了多屏幕适配的方方面面。不过在实际应用中屏幕适配永无止境, 还可能会遇到哪些其他问题和挑战呢?就让我们拭目以待,继续在这方面的实战中去探索和总结吧!


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/611769.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

教你解决PUBG绝地求生打完一把游戏无法返回大厅的问题

《绝地求生》&#xff08;PUBG&#xff09;作为风靡全球的战术竞技大作&#xff0c;凭借其高度还原的战场氛围和扣人心弦的生存挑战吸引了大量游戏玩家。不过&#xff0c;部分玩家在经历了一场紧张激烈的比赛后&#xff0c;遭遇了一个小困扰&#xff1a;游戏未能顺畅过渡到结算…

人大金仓报The connection attempt failed.Reason:Connection reset解决办法

在连接人大京仓数据库 的时候报下面的错误 解决办法&#xff1a; 更换这里的IP地址就行&#xff0c;不要用127.0.0.1&#xff0c;然后就可以了

keil5软件安装教程(MDKv5.39)

keil5软件安装分为三部分&#xff1a; 目录 1.安装mdk 2.激活mdk 3.安装STM32芯片包 1.安装mdk 安装包链接&#xff1a;https://pan.baidu.com/s/1StkkTQ5lmOz_99Qop4l8Gw?pwdrlmc 提取码&#xff1a;rlmc 1、下载keil5的压缩包并解压&#xff0c;鼠标右击【Setup】选…

利用函数视图实现精细化管控:DolphinDB 非标权限管理指南

1. 前言 DolphinDB 提供的用户权限管理功能管控的最小粒度是表级别&#xff0c;无法设置小于表粒度的数据访问权限管控&#xff0c;如限制用户仅能访问表中某些行或某些列的数据。为了满足客户更精细的权限管控需求&#xff0c;我们编写了本教程。 2. 概述 函数视图是封装了…

安卓通信方式简介

目录 一、Binder二、Socket三、Binder与Socket四、Handler 一、Binder Binder作为Android系统提供的一种IPC机制&#xff0c;无论从系统开发还是应用开发&#xff0c;都是Android系统中最重要的组成。 二、Socket Socket通信方式也是C/S架构&#xff0c;比Binder简单很多。在…

数据库开启远程连接

服务器端添加一个允许远程连接的root用户: mysql -u root -p create user root192.168.10.20 identified by admin; //创建一个192.168.10.20地址远程连接的root用户 grant all privileges on *.* to root192.168.10.20; //赋予远程root用户所有的权…

Linux文本处理工具【tr、cut、sort、uniq】

1. tr 命令——替换、压缩、删除 tr (Text Replacer) 命令常用来对来自标准输入的字符进行替换、压缩和删除。 命令格式 &#xff1a;tr [选项]... SET1 [SET2] &#xff08;SET 是一组字符串&#xff0c;一般都可按照字面含义理解&#xff09; 选项&#xff1a; -d 删除 -s 压…

01面向类的讲解

指针指向类成员使用 代码&#xff1a; #include<iostream> using namespace std;class Test { public:void func() { cout << "call Test::func" << endl; }static void static_func();int ma;static int mb; //不依赖对象 }; void Test::static…

DDS Blockset Shapes Demo

此示例演示DDS模块集Blockset形状演示应用程序。Shapes Demo是一个常见的数据分发服务&#xff08;DDS&#xff09;应用程序&#xff0c;用于介绍DDS概念&#xff0c;你可以使用它发布和订阅以简单形状&#xff08;圆形、方形和三角形&#xff09;表示的主题&#xff0c;并观察…

如何设计测试用例

一、介绍 测试用例就是一个文档&#xff0c;描述输入、动作、或者时间和一个期望的结果&#xff0c;其目的是确定应用程序的某个特性是否正常的工作。 二、基本格式 用例的基本要素包括测试用例编号、测试标题、重要级别、测试输入、操作步骤、预期结果等。 用例编号&#…

适合年轻人的恋爱交友脱单软件有哪些?中国十大社交软件排行榜分享

交友始祖&#xff1a;Tinder 一直很受欢迎&#xff0c;可以向上扫给 super like (每日有一次免费机会)。如果双方互相 like&#xff0c;代表配对成功&#xff0c;就可以开始聊天。另外&#xff0c;每日有 10 个 top picks 供选择&#xff0c;你可以免费选一位 主力编外&#xf…

添加一个索引要投产,需要哪些步骤?

编程一生 致力于写大家都能看懂的、有深度的 技术文章 05/2024 01 开场白 亚马逊有个bar raiser文化。就是说新招来的人一定要超过之前入职人员的平均水平&#xff0c;宁缺毋滥。越来越多的公司在推行这种文化。在这种氛围下&#xff1a;“虽然我不懂&#xff0c;但是活儿是能出…

一文了解webpack和vite中Tree-Shaking

1、什么是Tree-Shaking 1.1 摇树优化&#xff08;Tree Shaking&#xff09;是Webpack中一种用于优化JavaScript代码的技术。它的目标是通过静态分析&#xff0c;从代码中剔除未被使用的模块&#xff0c;从而减少最终打包文件的大小。 1.2 Tree-shaking 它的名字来源于通过摇晃…

纯血鸿蒙APP实战开发——数字滚动动效实现

介绍 本示例主要介绍了数字滚动动效的实现方案。 该方案多用于数字刷新&#xff0c;例如页面刷新抢票数量等场景。 效果图预览 使用说明&#xff1a; 下拉页面刷新&#xff0c;数字进行刷新。 实现思路 通过双重ForEach循环分别横向、纵向渲染数字。 Row() {ForEach(this…

基于SSM的文化遗产的保护与旅游开发系统(有报告)。Javaee项目。ssm项目。

演示视频&#xff1a; 基于SSM的文化遗产的保护与旅游开发系统&#xff08;有报告&#xff09;。Javaee项目。ssm项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;…

Java中包的概念package

Package Package:包 指明方法、类所处的包&#xff1b; 将类分配到不同的包中&#xff0c;方便管理&#xff1b; 用于指明文件中定义的类、接口等结构所在的包&#xff1b; 一个源文件只要一个包的声明语句&#xff0c;必须放到开头&#xff1b; 属于标识符&#xff0c;满足命…

Java类加载器介绍

在Java中&#xff0c;类加载器是一种动态加载类的机制&#xff0c;它负责在运行时查找、加载和链接类文件。当Java应用程序需要创建某个类的对象时&#xff0c;类加载器会在运行时查找该类对应的.class文件&#xff0c;并将其加载到Java虚拟机中。Java类加载器通常分为三层&…

《ESP8266通信指南》15-MQTT连接、订阅MQTT主题并打印消息(基于Lua|适合新手|非常简单)

往期 《ESP8266通信指南》14-连接WIFI&#xff08;基于Lua&#xff09;-CSDN博客 《ESP8266通信指南》13-Lua 简单入门&#xff08;打印数据&#xff09;-CSDN博客 《ESP8266通信指南》12-Lua 固件烧录-CSDN博客 《ESP8266通信指南》11-Lua开发环境配置-CSDN博客 《ESP826…

空间复杂度

前言 通过上一节的学习&#xff0c;我们知道了衡量一个算法是否高效的标准就是复杂度&#xff0c;我们已经学习了时间复杂度&#xff0c;那么本节我们就了解一下空间复杂度的相关知识&#xff0c;那么我们废话不多说&#xff0c;正式进入今天的学习 空间复杂度 空间复杂度也是…

Bugku Crypto 部分题目简单题解(三)

where is flag 5 下载打开附件 Gx8EAA8SCBIfHQARCxMUHwsAHRwRHh8BEQwaFBQfGwMYCBYRHx4SBRQdGR8HAQ0QFQ 看着像base64解码 尝试后发现&#xff0c;使用在线工具无法解密 编写脚本 import base64enc Gx8EAA8SCBIfHQARCxMUHwsAHRwRHh8BEQwaFBQfGwMYCBYRHx4SBRQdGR8HAQ0QFQ tex…