Android屏幕自适应2

简介: Android屏幕自适应

Android屏幕自适应1:https://developer.aliyun.com/article/1473627

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 框架改进版)

简书地址

目录
相关文章
|
Docker 容器 Ubuntu
docker container 设置编码为utf8
以Ubuntu 14.04 为例创建编码为utf8的container
6070 0
|
Android开发
Android TV开发中所有的遥控器按键监听及注意事项,新增home键监听
原文:Android TV开发中所有的遥控器按键监听及注意事项,新增home键监听 简单记录下android 盒子开发遥控器的监听 ,希望能帮到新入门的朋友们 不多说,直接贴代码 public...
8055 0
|
芯片 SoC 内存技术
全志H713红外IR遥控配置方法
这篇文章详细介绍了全志H713芯片平台配置红外遥控器的方法,包括获取遥控器规格、NEC协议的配置步骤、其他IR协议配置以及解决头码配置问题的方法。
698 5
全志H713红外IR遥控配置方法
|
缓存 Java 调度
优雅的自定义 ThreadPoolExecutor 线程池
优雅的自定义 ThreadPoolExecutor 线程池
|
网络安全
升级openssh版本
有网络情况下 1 下载包,编译 tar zxvf openssh-7.1p1.tar.gz cd openssh-7.1 ./configure --prefix=/usr --sysconfdir=/etc/ssh make make install 2 解决如下环境报错:    configure: error: *** zlib.
1660 0
|
安全
【Lua篇】静态代码扫描分析(一)
静态代码分析是一种通过检查代码而不是执行程序来发现源代码中错误的手段。通常可以帮助我们发现常见的编码错误,例如: 语法错误 违反制定的标准编码 未定义的变量 安全性问题 静态代码分析可以通过评估编写的代码来提高代码质量;可以稳定的运行且可以轻松自动化;增加了在源代码中发现漏洞的可能性,从而提高应用安全;由于是针对源码扫描可以在离线的开发环境中完成。但是静态代码分析并不能完全保证编写的代码没有Bug,它也有一些缺点,
1173 0
【Lua篇】静态代码扫描分析(一)
|
安全 Java 编译器
Kotlin | 深入理解协程
协程由程序自己创建和调度,不需要操作系统调度,所以协程比线程更加轻量。相比于线程的切换,协程切换开销更小,速度更快
561 0
CMake中使用vcpkg
vcpkg是一个微软开源的C++包管理器。 在以前的开发中,如果在项目中需要使用某个开源库,例如qt,我们需要取官网下载qt的源码,然后构建得到对应的库,然后在项目中链接这个库。对于自己熟悉的库还好说,若是不熟悉的库,如何拉取源码?如何构建?如何在项目中引用?等等这些问题通常会困扰我们,然而,大多数情况下,我们只是使用这个开源库,并不需要关心这个库的构建和编译等问题。如此,在以前的开发过程中,往往会花费不少的时间在引入开源库上。 vcpkg是在背景下开发出来的,通过vcpkg,我们可以在项目中很方便的引入开源库,不用再关心拉取代码、构建开源库的这些事情。 CMake构建的项目中引入开源库
405 0
|
自然语言处理 Cloud Native Java
SpringNative:把Spring项目编译成原生程序
Spring 发布了 Spring Native 的 beta 版本,该功能已经在 start.spring.io 上可用了。 Spring Native 是什么 Spring Native 可以通过 GraalVM 将 Spring 应用程序编译成原生镜像,提供了一种新的方式来部署 Spring 应用。Spring Native 支持 Java 和 Kotlin。 这个项目的目标是寻找 Spring JVM 的替代方案,提供一个能将应用程序打包,并运行在轻量级容器的方案。期望能够在 Spring Native 中支持所有的 Spring 应用程序(几乎不用修改代码)。