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

news2024/11/20 4:23:38

在移动互联网时代,无论是小小的手机屏幕,还是大大的平板显示器,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.coloradmin.cn/o/1661754.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ModuleSim 仿真找不到模块 module is not defined

提示如下&#xff1a; # vsim -t 1ps -L altera_ver -L lpm_ver -L sgate_ver -L altera_mf_ver -L altera_lnsim_ver -L cycloneive_ver -L rtl_work -L work -voptargs""acc"" pulse_generator_tb # Start time: 14:26:25 on May 10,2024 # ** Note: (…

基于小波交叉谱分析的地震波走时变化测量(MATLAB)

地震波在地球介质中传播&#xff0c;带来了丰富的地下介质物性的信息&#xff0c;为了解地球内部结构及运动变化提供了可能。地球内部地震波速度的差异是人们确定地球圈层结构和横向不均匀性的重要物理参数&#xff0c;地下介质应力的变化和积累是地震的孕育和发生的原因&#…

Day7 字符串和常用数据结构

文章目录 字符串和常用数据结构使用字符串使用列表生成式和生成器使用元组使用集合使用字典练习练习1&#xff1a;在屏幕上显示跑马灯文字。练习2&#xff1a;设计一个函数产生指定长度的验证码&#xff0c;验证码由大小写字母和数字构成。练习3&#xff1a;设计一个函数返回给…

速卖通ip地址会相互影响吗?如何防止账号关联?

在跨境电商行业&#xff0c;大部分平台都是不允许一个卖家操作多个店铺的&#xff0c;如果被平台检测出账户关联&#xff0c;可能会被封店。在速卖通平台&#xff0c;会通过IP地址来判断是否经营多个账号吗?IP地址会使店铺相互影响吗? 一、速卖通IP地址会关联吗? 首先各位卖…

内容安全(DPI和DFI解析)

内容安全前言&#xff1a; 防火墙的本质其实就是包过滤&#xff0c;我们通常所说的安全设备&#xff08;如&#xff1a;IPS、IDS、AV、WAF&#xff09;的检测重心是应用层。下一代防火墙基于传统防火墙的拓展能力&#xff0c;就是可以将以上的安全设备模块集成在一起&#xff0…

LeetCode-1486. 数组异或操作【位运算 数学】

LeetCode-1486. 数组异或操作【位运算 数学】 题目描述&#xff1a;解题思路一&#xff1a;暴力很简单。解题思路二&#xff1a;优化&#xff01;时间复杂度&#xff1a;O(1)。注释丰富&#xff0c;明了。解题思路三&#xff1a;精简版&#xff01; 题目描述&#xff1a; 给你…

通俗的理解网关的概念的用途(三):你的数据包是如何到达下一层的

其实&#xff0c;这一章我写不好&#xff0c;因为这其中会涉及到一些计算和一些广播等概念&#xff0c;本人不善于此项。在此略述&#xff0c;可以参考。 每台设备的不同连接在获得有效的IP地址后&#xff0c;会根据IP地址的规则和掩码的规则&#xff0c;在操作系统和交换机&a…

【吃透Java手写】3-SpringBoot-简易版-源码解析

【吃透Java手写】SpringBoot-简易版-源码解析 1 SpringbootDemo2 准备工作2.1 Springboot-my2.1.1 依赖2.1.2 SpringBootApplication2.1.3 SJBSpringApplication2.1.3.1 run方法 2.2 Springboot-user2.2.1 依赖2.2.2 UserController2.2.3 UserApplication 2.3 分析run方法的逻辑…

Codeforces Round 217 (Div. 2) A. Rook, Bishop and King(BFS)

Rook, Bishop and King 题面翻译 【题目描述】 佩蒂亚正在学习国际象棋。他已经学会如何移动王、车和象。让我们提示你如何移动国象棋子。棋盘有 64 64 64个棋格&#xff0c;呈 8 8 8\times8 88正方形。一个格子可以用 ( r , c ) (r,c) (r,c)来表示—— r r r指行&#xff…

乡村振兴的文化旅游融合:整合乡村文化资源与旅游资源,发展文化旅游产业,提升美丽乡村的文化内涵和旅游吸引力

一、引言 随着城市化进程的加速和人们精神文化需求的日益增长&#xff0c;乡村旅游逐渐成为旅游市场的新热点。乡村振兴战略的提出&#xff0c;为乡村旅游的发展提供了新的契机。在这一背景下&#xff0c;如何整合乡村文化资源与旅游资源&#xff0c;发展文化旅游产业&#xf…

postman常用功能超全使用教程

Postman 使用 一、Postman 简介 Postman是一个接口测试工具,在做接口测试的时候,Postman相当于一个客户端,它可以模拟用户发起的各类HTTP请求(如:get/post/delete/put…等等),将请求数据发送至服务端,获取对应的响应结果。 二、Postman 功能简介 三、Postman 下载安装 Post…

crontab开启定时任务

linux上面可以使用crontab -e配置定时任务,但是一般需求进行一些配置才能使用,默认如下: crontab开启定时任务&#xff1a; 1.输入select-editor 2.选择 2. /usr/bin/vim.basic 有时候不需要第一步直接输入2就可以了,如下图所示 此时就可以在里面配置我们想要执行的定时任务…

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

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

ETL免费工具kettle(PDI),安装和配置

起源&#xff1a; Kettle最早是一个开源的ETL工具&#xff0c;全称为KDE Extraction, Transportation, Transformation and Loading Environment。在2006年&#xff0c;Pentaho公司收购了Kettle项目&#xff0c;原Kettle项目发起人Matt Casters加入了Pentaho团队&#xff0c;成…

如何使用visual vm和jstat进行远程监控

如何使用visual vm和jstat进行监控 安装visual vm 好像从jdk某个版本开始&#xff0c;jdk的bin目录下就不自带jvisualvm了&#xff0c;需要从官网下载一个visual vm。 打开visual vm Local是你本地的&#xff0c;无需多言。 先准备下必备的插件 如何通过visual vm观测远程…

Windows程序设计课程作业-2(音乐文件播放功能)

目录 1、作业内容 要求1&#xff1a; 提示&#xff1a; 要求2&#xff1a; 提示&#xff1a; 作业提交方式: 2、主要思路 1&#xff09;准备工作 2&#xff09;提取音乐文件功能 3&#xff09;选择音乐进行播放 4&#xff09;异常信息进行处理 5&#xff09;停止播…

Apinto下载安装以及集群部署总结

下载 下载官方提供的安装包安装&#xff08;推荐&#xff09; wget https://github.com/eolinker/apinto/releases/download/v0.13.3/apinto_v0.13.3_linux_amd64.tar.gz && tar -zxvf apinto_v0.13.3_linux_amd64.tar.gz && cd apinto 安装 先确保已经入解…

Debian mariadb 10.11 XXXX message from server: “Too many connections“

问题表现 报错信息&#xff1a;Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Data source rejected establishment of connection, message from server: "Too many connections" 处理步骤 1、尝试能不能通过终端登录&…

[报错解决]Communications link failure

报错 主机IDEA项目连接虚拟机的数据库报错。 主要报错信息有&#xff1a; com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received a…

MySQL数据库——基础事务操作-BEGIN-COMMIT-ROLLBACK

DDL CREATE TABLE student (id int(11) NOT NULL AUTO_INCREMENT COMMENT 学号,createDate datetime DEFAULT NULL,userName varchar(20) DEFAULT NULL,pwd varchar(36) DEFAULT NULL,phone varchar(11) DEFAULT NULL,age tinyint(3) unsigned DEFAULT NULL,sex char(2) DEFAU…