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;@Overrideprotected 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 的背景:

    <Buttonandroid: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 {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_nine_patch_example);// 获取 LinearLayoutLinearLayout container = findViewById(R.id.container);// 创建 3 个 Buttonfor (int i = 0; i < 3; i++) {Button button = createButton(this);container.addView(button);}}private Button createButton(Context context) {// 创建 ButtonButton 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> 标签来引用矢量图资源:

    <ImageViewandroid: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 {@Overrideprotected 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.mzph.cn/web/9915.shtml

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

相关文章

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

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

解决mybatis的配置文件没代码提示的问题

1.将org.apache.ibatis.builder.xml包里的两个dtd文件复制出来&#xff0c;jar包里复制 2.复制dtd的url地址&#xff1a; http://mybatis.org/dtd/mybatis-3-mapper.dtd 一样的做法&#xff01; 3.关闭两个配置文件&#xff0c;重新打开&#xff0c;就可以有代码提示了&…

【智能优化算法】白鲨智能优化算法(White Shark Optimizer,WSO)

白鲨智能优化算法(White Shark Optimizer,WSO)是期刊“KNOWLEDGE-BASED SYSTEMS”&#xff08;中科院一区期刊 IF8.6&#xff09;的2022年智能优化算法 01.引言 白鲨智能优化算法(White Shark Optimizer,WSO)的核心理念和基础灵感来自大白鲨的行为&#xff0c;包括它们在导航和…

从项目开始学习Vue——02(若依框架)

往期&#xff1a; 从项目开始学习Vue——01 目录标题 一、基础插件&#xff08;一&#xff09;路由Vue Router&#xff08;二&#xff09;导航守卫&#xff08;路由拦截器&#xff09;二、Vuex&#xff08;一&#xff09;什么是VuexVuex的部分介绍内容&#xff1a; &#xff08…

QQ超大文件共享(别用,传进去后,压缩都显示不出来,LJ qq!)(共享文件)

文章目录 需要共享双方同时在线开启方法第一次会提示设置默认共享目录&#xff0c;默认是E:\QQFileShare\<qq号>\&#xff1a;然后新建共享会在其后创建共享目录&#xff0c;共享目录中只能共享文件。需要点击添加文件&#xff0c;直接把文件拷贝到目录里好像还不行&…

C语言/数据结构——(相交链表)

一.前言 今天在力扣上刷到了一道题&#xff0c;想着和大家一起分享一下这道题——相交链表https://leetcode.cn/problems/intersection-of-two-linked-lists废话不多说&#xff0c;让我们开始今天的分享吧。 二.正文 1.1题目描述 是不是感觉好长&#xff0c;我也这么觉得。哈…

网络编程套接字和传输层tcp,udp协议

认识端口号 我们知道在网络数据传输的时候&#xff0c;在IP数据包头部有两个IP地址&#xff0c;分别叫做源IP地址和目的IP地址。IP地址是帮助我们在网络中确定最终发送的主机&#xff0c;但是实际上数据应该发送到主机上指定的进程上的&#xff0c;所以我们不仅要确定主机&…

OAuth 2.0 和 OAuth 2.1

OAuth 2.0 和 OAuth 2.1比较&#xff1a; OAuth 2.0 和 OAuth 2.1 是授权框架的不同版本&#xff0c;它们用于允许应用程序安全地访问用户在另一个服务上的数据。以下是它们之间的一些主要区别&#xff1a; 安全性增强&#xff1a;OAuth 2.1 旨在提高安全性&#xff0c;它整合…

什么是云原生架构,我们该如何做好云原生安全,引领云计算时代的应用程序革新

随着云计算技术的飞速发展&#xff0c;企业面临着前所未有的机遇和挑战。在这个高度竞争的市场中&#xff0c;传统的应用程序架构因其僵化、不易扩展和维护的特点&#xff0c;已难以满足当今企业对灵活性、可伸缩性和高效性的追求。在这样的背景下&#xff0c;云原生架构应运而…

git rebase 合并当前分支的多个commit记录

git rebase 合并当前分支的多个commit记录 git rebase 相关的选项和用法step1&#xff1a;找到想要合并的 commitstep2. 使用 rebase -istep3. 编辑提交历史&#xff1a;step4.编辑合并后的提交信息step5.完成 rebase 过程&#xff1a;step6.**推送更新&#xff1a;**step6.**再…

FFmpeg常用API与示例(三)—— 音视频解码与编码

编解码层 1.解码 (1) 注册所有容器格式和 CODEC:av_register_all() (2) 打开文件:av_open_input_file() (3) 从文件中提取流信息:av_find_stream_info() (4) 穷举所有的流&#xff0c;查找其中种类为 CODEC_TYPE_VIDEO (5) 查找对应的解码器:avcodec_find_decoder() (6) …

数据结构-二叉树结尾+排序

一、二叉树结尾 1、如何判断一棵树是完全二叉树。 我们可以使用层序遍历的思路&#xff0c;利用一个队列&#xff0c;去完成层序遍历&#xff0c;但是这里会有些许的不同&#xff0c;我们需要让空也进队列。如果队列里到最后只剩下空那么这棵树就是完全二叉树。具体的实现如下…

js 数据格式转换,对象转数组,数组转对象

1.对象转数组 // 对象obj转换成数组格式 let obj { orgCode:分局编码, alertId:告警ID, name:告警名称 } let arr [] for(let key in obj) { console.log(11,key,obj[key]); // 定义一个对象&#xff0c;赋值 let o { id: key, // key是obj对象的键值 label: obj[key] …

重装前端整体流程

用户管理 --汇总 -- 明细-CSDN博客 一、node 这个看环境变量 2023最新版Node.js下载安装及环境配置教程&#xff08;非常详细&#xff09;从零基础入门到精通&#xff0c;看完这一篇就够了_nodejs安装及环境配置-CSDN博客 配置到国内镜像的时候&#xff0c;去看&#xff0c;淘…

Java方法的重载

方法重载 1. 为什么需要方法重载 public class TestMethod{public static void main (String[] args){int a 10;int b 20;int ret add(a,b);System.out.println("ret "ret);double a2 10.5;double b2 20.5;double ret2 add(a2,b2);System.out.println("…

《QT实用小工具·六十二》基于QT实现贝塞尔曲线画炫酷的波浪动画

1、概述 源码放在文章末尾 该项目实现了通过贝塞尔曲线画波浪动画&#xff0c;可控制 颜色密度速度加速度 安装与运行环境 语言&#xff1a;C 框架&#xff1a;Qt 11.3 平台&#xff1a;Windows 将屏幕水平平均分为10块&#xff0c;在一定范围内随机高度的12个点&#xff08;…

【初阶数据结构】顺序表OJ题讲解

前言 &#x1f4da;作者简介&#xff1a;爱编程的小马&#xff0c;正在学习C/C&#xff0c;Linux及MySQL。 &#x1f4da;本文收录与初阶数据结构系列&#xff0c;本专栏主要是针对时间、空间复杂度&#xff0c;顺序表和链表、栈和队列、二叉树以及各类排序算法&#xff0c;持…

基于ambari hdp的kafka用户授权读写权限

基于ambari hdp的kafka用户授权读写权限 版本Kafka 2.0.0添加自定义配置修改admin密码重启kafka授权读取授权写入有效通配符部分举例 版本Kafka 2.0.0 添加自定义配置 authorizer.class.name kafka.security.auth.SimpleAclAuthorizer super.users User:admin allow.everyo…

【LLM 论文】Step-Back Prompting:先解决更高层次的问题来提高 LLM 推理能力

论文&#xff1a;Take a Step Back: Evoking Reasoning via Abstraction in Large Language Models ⭐⭐⭐⭐ Google DeepMind, ICLR 2024, arXiv:2310.06117 论文速读 该论文受到的启发是&#xff1a;人类再解决一个包含很多细节的具体问题时&#xff0c;先站在更高的层次上解…

Android 屏幕适配全攻略(上)-掌握屏幕单位,应对千变万化的设备

本文从 Android 开发中常见的长度单位 px、dp、sp 入手&#xff0c;详细介绍了它们的特点及转换关系。 接着深入探讨了屏幕尺寸、分辨率、像素密度等重要的屏幕指标&#xff0c;帮助读者全面理解它们之间的联系。最后&#xff0c;通过实例代码演示了如何在代码中进行单位转换&…