Android屏幕自适应

Android屏幕自适应

  • Android屏幕适配出现的原因
    • 为什么Android需要进行屏幕适配?
  • 屏幕基本概念
    • 屏幕尺寸
    • 屏幕分辨率和像素
    • sp
    • px
    • dp 密度无关像素
    • dpi
    • Density
  • 屏幕方向
    • 横屏竖屏自动切换
    • 禁用自动切换屏幕方向
  • Android屏幕自适应
    • 1. dp原生方案
    • 2. 线形布局权重
      • 示例代码
    • 3. Java代码中设置宽高
      • 示例代码
    • 4. smallestWidth
    • 5. 多layout适配
    • 6. 今日头条适配方案
      • 示例代码
    • 7. AndroidAutoSize 框架(原鸿神 AndroidAutoLayout 框架改进版)
      • 简书地址
      • GitHub地址

Android屏幕适配出现的原因

为什么Android需要进行屏幕适配?

由于Android系统的开放性,任何用户、开发者、OEM厂商、运营商都可以对Android进行定制,修改成他们想要的样子,但是这种“碎片化”到底到达什么程度呢?


统计数据表明:
2012年,支持Android的设备共有3997种;
2013年,支持Android的设备共有11868种;
2014年,支持Android的设备共有18796种;
2015年,支持Android的设备共有24093种;

试想一下这么一个场景:
为5.5寸屏幕准备的UI设计图,运行在6.6寸的屏幕上,很可能在右侧和下侧存在大量的空白;
而6.6寸的UI设计图运行到5.5寸的设备上,很可能显示不下。


屏幕种类这么多,那么就需要一套完美的方案去解决适配问题,介绍屏幕适配方案之前,下面先简单介绍下Android屏幕中用到的一些相关概念

屏幕基本概念

屏幕尺寸

屏幕尺寸即手机屏幕对角线的物理尺寸,以英寸为单位,1英寸=2.54厘米;
现常见的屏幕尺寸:5.5、6.0、6.1、6.5、6.6、6.67、6.7英寸等等
在这里插入图片描述

屏幕分辨率和像素

屏幕分辨率就是手机屏幕的像素点数,指屏幕横竖各有多少个像素,一般描述成屏幕的“高×宽”,如下方所示屏幕分辨率就是所谓的 1080x2400 ;


屏幕像素即 1080x2400=2592000,分辨率为 1080x2400 的手机约有260w个像素;
现Android手机比较常见的分辨率为:1080x1920、1080x2400、1440x3200;


adb命令查看手机屏幕分辨率:adb shell wm size
在这里插入图片描述

sp

sp:根据文字大小首选项进行放缩,主要用于字体显示;谷歌开发指导中推荐使用12sp以上的字体,否则用户将无法看清。设置字体大小时不要使用奇数或小数,可能会造成精度丢失;

px

px:像素点,构成图像的最小单位

dp 密度无关像素

dp:安卓中的相对大小,dp就是为了使得开发者设置的长度能够根据不同屏幕的分辨率获得不同的像素(px)数量;
换算公式是 1dp=(dpi/160)x 1px;(例:在密度为160dpi的屏幕上,1px就是1dp。依次类推,在320dpi的屏幕上,1dp就是2px。屏幕密度越大,1个dp对应的px也就越大);

dpi

dpi:指每英寸的像素点数,用于描述屏幕的显示特性,dpi越大,屏幕的精细度越高,屏幕看起来就越清晰;
在这里插入图片描述


adb命令查看手机屏幕密度:adb shell wm density
在这里插入图片描述

密度类型分辨率dpidp换算
低密度(ldpi)240x3201201dp=0.75px
中密度(mdpi)320x4801601dp=1px
高密度(hdpi)480x8002401dp=1.5px
超高密度(xhdpi)720x12803201dp=2px
超超高密度(xxhdpi)1080x19204801dp= 3px

Density

Density:表示设备屏幕密度的值,它表示每英寸在屏幕上显示的像素数量,density和dpi的关系为 density = dpi/160;

屏幕方向

横屏竖屏自动切换

在res目录下建立 layout 和 layout-land 两个目录,里面分别放置竖屏和横屏两种布局文件,以适应对横屏竖屏自动切换;

禁用自动切换屏幕方向

// 限制此页面横屏显示
Android:screenOrientation="landscape"

// 限制此页面竖屏显示
Android:screenOrientation="portrait"

Android屏幕自适应

1. dp原生方案

Android尺寸的基本单位,Android自带的原始的适配方案, 在不同的分辨率手机里面表现出相应大小的像素点。 在不同的分辨率的手机里面1dp对应着不同的px, 这样就实现了dp定义一个控件大小的时候,在不同分辨率手机里表现出相应大小的像素值;

2. 线形布局权重

(layout_weight:属性值越小 对应的优先级越高)
在 values 文件夹下的 styles 文件中新建一个 style 属性标签;
布局文件中有需要引用即可(省去标签中的 android:layout_height=“0px” 属性);

示例代码

styles.xml 文件

<!--styles.xml-->
<?xml version="1.0" encoding="utf-8"?>
<resources>  
 
<!-- 全屏幕拉伸-->
  <style name="layout_full">  
    <item name="android:layout_width">match_parent</item>  
    <item name="android:layout_height">match_parent</item>  
  </style>
   
<!-- 固定自身大小-->
  <style name="layout_wrap">  
    <item name="android:layout_width">wrap_content</item>  
    <item name="android:layout_height">wrap_content</item>  
  </style>
 
<!-- 横向分布-->
  <style name="layout_horizontal" parent="layout_full">  
    <item name="android:layout_width">0px</item>  
  </style> 
    
<!-- 纵向分布-->
  <style name="layout_vertical" parent="layout_full">  
    <item name="android:layout_height">0px</item>  
  </style> 
  
</resources>  

activity_main.xml 文件

<!--activity_main.xml-->
<LinearLayout 
  style="@style/layout_vertical"
  android:layout_weight="2"
  android:orientation="vertical">
  
  <View
    style="@style/layout_vertical"
    android:background="#ffffff"
    android:layout_weight="2"/>    
  
  <View
    style="@style/layout_vertical"
    android:background="#000000"
    android:layout_weight="6"/>
  
  <View
    style="@style/layout_vertical"
    android:background="#ff0000"
    android:layout_weight="9"/>
  
  <View
    style="@style/layout_vertical"
    android:background="#00ffff"
    android:layout_weight="1"/>
 
</LinearLayout>

3. Java代码中设置宽高

示例代码

activity_main.xml 文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
  <Button  
    android:id="@+id/btn1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="#000000"
    android:text="按钮1"/>
  <Button  
    android:id="@+id/btn2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="#ffffff"
    android:text="btn2"/>
  <Button  
    android:id="@+id/btn3"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="#ff0000"
    android:text="btn3"/>
  <Button  
    android:id="@+id/btn4"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="#ff00ff"
    android:text="btn4"/>   
</LinearLayout>

MainActivity.java 文件

// app启动时先获取当前屏幕的宽高
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
phoneWidth = displayMetrics.widthPixels;
phoneHeight = displayMetrics.heightPixels;

// 设置控件大小
// 第一个按钮,宽度100%,高度10%
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
    LayoutParams.MATCH_PARENT,(int) (phoneHeight * 0.1f + 0.5f));
btn1.setLayoutParams(params);

// 第二个按钮,宽度100%,高度30%
LinearLayout.LayoutParams params2 = new LinearLayout.LayoutParams(
    LayoutParams.MATCH_PARENT,(int) (phoneHeight * 0.3f + 0.5f));
btn2.setLayoutParams(params2);

// 第三个按钮,宽度50%,高度20%
LinearLayout.LayoutParams params3 = new LinearLayout.LayoutParams(
    (int) (phoneWidth * 0.5f + 0.5f),(int) (phoneHeight * 0.2f + 0.5f));
btn3.setLayoutParams(params3);

// 第三个按钮,宽度70%,高度填满剩下的空间
LinearLayout.LayoutParams params4 = new LinearLayout.LayoutParams(
    (int) (phoneWidth * 0.7f + 0.5f),LayoutParams.MATCH_PARENT);
btn4.setLayoutParams(params4);

4. smallestWidth

sw限定符适配(需要安装 SmallestWidth Dimens 插件),依据最小宽度限定符,指的是 Android 会识别屏幕宽度最小尺寸的 dp 值(其实就是手机的宽度值),然后根据识别到的结果去资源文件中寻找对应限定符的文件夹下的资源文件。


这个可以使用 Android Studio 里的 SmallestWidth Dimens 插件来完成。
需要注意的是,如果没有 values-sw360dp 文件夹,系统会向下寻找,比如离 360dp 最近的只有 values-sw340dp,那么系统就会选择 values-sw340dp 文件夹下的资源文件;
在这里插入图片描述

5. 多layout适配

多layout适配主要是针对某个分辨率,新建一个layout文件夹

6. 今日头条适配方案

适配方案的核心原理在于根据dp和px的转换公式 :px = dp * density,不管我们设定的单位是什么, 最终我们都会将这些单位长度转化为px的。
density就是他们的转化比, 所以,动态改变这个转化比也是可以达到我们适配屏幕的目的。
通过修改density值,强行把所有不同尺寸分辨率的手机的宽度dp值改成一个统一的值(在清单文件中定义),这样就解决了所有的适配问题;


Density = 当前设备屏幕总宽度(单位为像素)/ 设计图总宽度(单位为 dp) ;
例:分辨率1080x1920,dpi为480,正常情况下计算density=dpi/160=480/160=3,此时屏幕总宽度dp=px/density=1080/3=360;


一般的应用场景就是在BaseActivity的onCreate方法中调用,即可达成全局适配;

示例代码

工具类调用方法

// 在Activity中的onCreate方法中调用,必须在setContentView()之前
CustomDensityUtil.setCustomDensity(MainActivity.this, getApplication());

今日头条适配方案工具类

public class CustomDensityUtil {
   // 系统的Density
   private static float sNoncompatDensity;
   // 系统的ScaledDensity
   private static float sNoncompatScaledDensity;

   /**
    * 今日头条适配方案
    *
    * @param activity
    * @param application
    */
   public static void setCustomDensity(Activity activity, final Application application) {
       //通过资源文件getResources类获取DisplayMetrics
       DisplayMetrics appDisplayMetrics = application.getResources().getDisplayMetrics();
       if (sNoncompatDensity == 0) {
           //保存之前density值
           sNoncompatDensity = appDisplayMetrics.density;
           //保存之前scaledDensity值,scaledDensity为字体的缩放因子,正常情况下和density相等,但是调节系统字体大小后会改变这个值
           sNoncompatScaledDensity = appDisplayMetrics.scaledDensity;
           //监听设备系统字体切换
           application.registerComponentCallbacks(new ComponentCallbacks() {

               public void onConfigurationChanged(Configuration newConfig) {
                   if (newConfig != null && newConfig.fontScale > 0) {
                       //调节系统字体大小后改变的值
                       sNoncompatScaledDensity = application.getResources().getDisplayMetrics().scaledDensity;
                   }
               }

               public void onLowMemory() {

               }
           });
       }

       //获取以设计图总宽度360dp下的density值
       float targetDensity = appDisplayMetrics.widthPixels / 360;
       //通过计算之前scaledDensity和density的比获得scaledDensity值
       float targetScaleDensity = targetDensity * (sNoncompatScaledDensity / sNoncompatDensity);
       //获取以设计图总宽度360dp下的dpi值
       int targetDensityDpi = (int) (160 * targetDensity);
       //设置系统density值
       appDisplayMetrics.density = targetDensity;
       //设置系统scaledDensity值
       appDisplayMetrics.scaledDensity = targetScaleDensity;
       //设置系统densityDpi值
       appDisplayMetrics.densityDpi = targetDensityDpi;

       //获取当前activity的DisplayMetrics
       final DisplayMetrics activityDisplayMetrics = activity.getResources().getDisplayMetrics();
       //设置当前activity的density值
       activityDisplayMetrics.density = targetDensity;
       //设置当前activity的scaledDensity值
       activityDisplayMetrics.scaledDensity = targetScaleDensity;
       //设置当前activity的densityDpi值
       activityDisplayMetrics.densityDpi = targetDensityDpi;
   }
}

源码

     /**
    * @param unit 要转换的单位
    * @param value 单位对应的值
    * @param metrics 显示指标
    */
   public static float applyDimension(int unit, float value,DisplayMetrics metrics){
       switch (unit) {
       case COMPLEX_UNIT_PX://单位为px
           return value;
       case COMPLEX_UNIT_DIP://单位为dp
           return value * metrics.density;
       case COMPLEX_UNIT_SP://单位为sp
           return value * metrics.scaledDensity;
       case COMPLEX_UNIT_PT://单位为pt
           return value * metrics.xdpi * (1.0f/72);
       case COMPLEX_UNIT_IN://单位为in
           return value * metrics.xdpi;
       case COMPLEX_UNIT_MM://单位为mm
           return value * metrics.xdpi * (1.0f/25.4f);
       }
       return 0;
   }

7. AndroidAutoSize 框架(原鸿神 AndroidAutoLayout 框架改进版)

简书地址

今日头条屏幕适配方案终极版

GitHub地址

AndroidAutoSize

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

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

相关文章

阿里云短信服务业务

一、了解阿里云用户权限操作 1.注册账号、实名认证&#xff1b; 2.使用AccessKey 步骤一 点击头像&#xff0c;权限安全的AccessKey 步骤二 设置子用户AccessKey 步骤三 添加用户组和用户 步骤四 添加用户组记得绑定短信服务权限 步骤五 添加用户记得勾选openApi访问 添加…

Higgsfield AI: 对飙Sora打造个性化视频新浪潮,重塑社交媒体内容创作

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

对于个人如何选择服务器是最适合的?

选择适合的服务器对于个人来说是一个重要的决策&#xff0c;因为它会直接影响到你的网站或应用的性能、稳定性和成本。以下是一些建议&#xff0c;帮助你选择最适合的服务器&#xff1a; 京东云服务器&#xff0c;一年2G2H3M只需要50元&#xff01;&#xff01; 进入活动会场…

isc-dhcp-server DNS配置

我遇到一个有趣的问题&#xff0c;我先在一台Ubuntu服务器上使用isc-dhcp-server在其其中一个网口运行DHCP服务&#xff0c;然后我自己的笔记本电脑直连到这个网口&#xff0c;来上网。 本来直接就应该能上网&#xff0c;但是我的电脑只有在打开Clash时才能访问互联网&#xf…

【御控物联】JavaScript JSON结构转换(18):数组To对象——多层属性重组

文章目录 一、JSON结构转换是什么&#xff1f;二、案例之《JSON数组 To JSON对象》三、代码实现四、在线转换工具五、技术资料 一、JSON结构转换是什么&#xff1f; JSON结构转换指的是将一个JSON对象或JSON数组按照一定规则进行重组、筛选、映射或转换&#xff0c;生成新的JS…

猫头虎分享已解决Bug: ERROR: Could not find a version that satisfies the requirement

猫头虎分享已解决Bug: ERROR: Could not find a version that satisfies the requirement &#x1f42f;&#x1f4bb; 摘要 &#x1f4c4; 大家好&#xff0c;我是猫头虎博主&#xff0c;今天我们要聊聊后端技术领域中的一个常见Bug&#xff1a;ERROR: Could not find a vers…

Linux第3课 Linux系统安装及换源方法

文章目录 Linux第3课 Linux系统安装及换源方法一、VMware虚拟机下系统的安装及配置&#xff08;一&#xff09;创建新的虚拟机 二、换源三、初次配置四、修改分辨率五、共享文件夹的实现&#xff08;一&#xff09;创建并查看共享文件夹 Linux第3课 Linux系统安装及换源方法 用…

java生成word

两种方案 一、poi-tl生成word <dependency><groupId>com.deepoove</groupId><artifactId>poi-tl</artifactId><version>1.12.1</version> </dependency> public static void main(String[] args) throws Exception {String…

解决打印尺寸难题:精准打印证件复印件的软件

为什么打印复印件&#xff0c;尺寸总是不对&#xff0c;用尺子测量打印出来总是不一样。 每次打印复印件&#xff0c;不是大了就是小了&#xff0c;让人十分痛苦。收款牌和桌卡也总是尺寸不对&#xff0c;怎么办&#xff1f;打印的痛苦谁能懂&#xff1f;复印件、收款牌、桌卡…

DashOJ-8.奇偶统计

题目链接&#xff1a; 题目详情 - 奇偶统计 - DashOJ 思路&#xff1a; &#xff08;while循环加if分支语句&#xff09; 巧用死循环 while(1) 然后在里面第一句就判断输入的数字是否等于0 if(x0) &#xff0c;如果 等于0就直接break跳出循环 或者用 while(cin>>x) 代…

AI Kimi:帮助教师做好试卷命题

原文&#xff1a;https://www.toutiao.com/article/7353661304307778083/?log_fromcfd0a50014034_1712243146922 最近&#xff0c;Kimichat工具很火。这款软件不仅仅是一个聊天和阅读工具&#xff0c;还是一个强大的教学辅助工具。作为一位教师&#xff0c;尝试使用Kimichat&…

Flask-RESTful 分析

Flask-RESTful 是一个 Flask 扩展&#xff0c;它为构建 RESTful API 提供了方便的工具和资源。它简化了创建 RESTful 服务的过程&#xff0c;允许开发者专注于业务逻辑而不是 HTTP 协议的细节。 资源&#xff08;Resources&#xff09;&#xff1a; Resource 类&#xff1a;是…

【C++】模拟实现红黑树(插入)

目录 红黑树的概念 红黑树的性质 红黑树的调整情况 红黑树的模拟实现 枚举类型的定义 红黑树节点的定义 插入函数的实现 旋转函数的实现 左旋 右旋 自检函数的实现 红黑树类 红黑树的概念 红黑树&#xff0c;是一种二叉搜索树&#xff0c;但在每个结点上增加一个存储…

数据结构进阶篇 之 【并归排序】(递归与非递归实现)详细讲解

都说贪小便宜吃大亏&#xff0c;但吃亏是福&#xff0c;那不就是贪小便宜吃大福了吗 一、并归排序 MergeSort 1.基本思想 2.实现原理 3.代码实现 4.归并排序的特性总结 二、非递归并归排序实现 三、完结撒❀ –❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀…

Leetcode链表刷题总结(Java版)

链表 1、移除链表元素&#xff08;考虑全情况&#xff09; 问题需求&#xff1a;根据给定的val值&#xff0c;移除链表中值是这个val的节点 203. 移除链表元素 - 力扣&#xff08;LeetCode&#xff09; 这里有一个问题就是&#xff0c;如果需要被移除的节点不是中间的某个节点…

【蓝桥杯嵌入式】六、真题演练(二)-1研究篇:第 13 届真题-第二部分

温馨提示&#xff1a; 真题演练分为模拟篇和研究篇。本专栏的主要作用是记录我的备赛过程&#xff0c;我打算先自己做一遍&#xff0c;把遇到的问题和不同之处记录到演练篇&#xff0c;然后再返回来仔细研究一下&#xff0c;找到最佳的解题方法记录到研究篇。题目在&#xff1a…

【CSS】浮动笔记及案例

CSS浮动 1. 认识浮动 float属性可以指定一个元素沿着左侧或者是右侧放置&#xff0c;允许文本和内联元素环绕它 float属性最初只使用文字环绕图片但却是早起CSS最好用的左右布局方案 绝对定位、浮动都会让元素脱标&#xff0c;以达到灵活布局的目的可以通过float属性让元素脱…

SSM实战项目——哈哈音乐(二)后台模块开发

1、项目准备 ① 引入后台模块&#xff08;hami-console&#xff09;需要的依赖 <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.0…

【Qt】:常用控件(五:显示类控件)

常用控件 一.ProgressBar二. Calendar Widget 一.ProgressBar 使⽤ QProgressBar 表⽰⼀个进度条 代码⽰例:设置进度条按时间增⻓ 设置定时器&#xff0c;每个0.1秒&#xff0c;让进度条1 在实际开发中&#xff0c;进度条的取值&#xff0c;往往是根据当前任务的实际进度来进行…

创意绘图画画小程序:融合白板黑板功能,开启绘画新纪元

创意绘图画画小程序&#xff1a;融合白板黑板功能&#xff0c;开启绘画新纪元 在数字化时代的浪潮下&#xff0c;艺术创作正逐渐摆脱传统形式的束缚&#xff0c;以更加多元、便捷的方式走进人们的生活。其中&#xff0c;创意绘图画画小程序以其独特的白板画、黑板画功能&#…