Android 自适应

一开始项目使用的是第三方框架

GitHub - JessYanCoding/AndroidAutoSize: 🔥 A low-cost Android screen adaptation solution (今日头条屏幕适配方案终极版,一个极低成本的 Android 屏幕适配方案).

但是会偶现,断电重启第一次,自适应失败的情况。

复现手顺:

当前为A分辨率,杀死进程 =》设置B分辨率=》断电重启,自适应失败。

以下内容基于单位dp。

一 失败原因

第一种

设置DisplayMetrics还未生效,layout已经开始绘制,导致失败。

第二种

DisplayMetrics是全局可用,被其他应用【三方应用或者系统应用\View等】重写了甚至是恢复默认,导致失败。

二 原理

DisplayMetrics是公用的,谁都有权利进行修改,DisplayMetrics.density一旦进行修改,所有的页面、view、第三方库都会被修改到。

能够达到低成本和低侵入性。

同时如果,其他应用,或者系统进行DisplayMetrics.density的修改,也会影响到我们自身的应用。

除非我们的页面已经创建,没有重建,创建好的页面后,再设置density是不会成功的。

三 解决方案

工具类

public class DisplayUtils {private String TAG = DisplayUtils.class.getSimpleName();//设计宽度private static final float DEFAULT_DISPLAY_WIDTH = 1280;private static DisplayUtils instance = null;public synchronized static DisplayUtils getInstance() {if (instance == null) {instance = new DisplayUtils();}return instance;}//设计高度,本项目以高度为准,横向滑动private float DEFAULT_DISPLAY_HEIGHT = 720;public void setDisplayDensity(Context context){if (context == null) {Log.d(TAG, "context is null");return;}DisplayMetrics displayMetrics = getRealDisplayMetrics(context);//布局缩放倍数float targetDensity = ((float) displayMetrics.heightPixels) / DEFAULT_DISPLAY_HEIGHT;//todo 宽度为基准
//        float targetDensity = ((float) displayMetrics.widthPixels) / DEFAULT_DISPLAY_WIDTH;//字体缩放倍数float targetScaledDensity = targetDensity * (displayMetrics.scaledDensity / displayMetrics.density);int targetDensityDpi = (int) (targetDensity * 160);Log.d(TAG, "setDisplayDensity: heightPixels = " + displayMetrics.heightPixels +", targetDensity = "+ targetDensity + ", density = " + displayMetrics.density + ", scaledDensity = " + displayMetrics.scaledDensity+ ", targetScaledDensity = " + targetScaledDensity + ", targetDensityDpi = " + targetDensityDpi);DisplayMetrics activityDisplayMetrics = context.getResources().getDisplayMetrics();activityDisplayMetrics.density = targetDensity;activityDisplayMetrics.densityDpi = targetDensityDpi;activityDisplayMetrics.scaledDensity = targetScaledDensity;}public static DisplayMetrics getRealDisplayMetrics(Context context){DisplayMetrics displayMetrics = new DisplayMetrics();WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);Display display = windowManager.getDefaultDisplay();display.getRealMetrics(displayMetrics);return displayMetrics;}/*** 每个子fragment创建之前重置density,保证是正确的,因为onConfigurationChanged回调分辨率切换时设置后,* 在Fragment创建前density又被系统修改,导致分辨率显示异常(偶现)*/public void setDisplayDensityForFragments(AppCompatActivity context){context.getSupportFragmentManager().registerFragmentLifecycleCallbacks(new FragmentManager.FragmentLifecycleCallbacks() {@Overridepublic void onFragmentCreated(@NonNull FragmentManager fm, @NonNull Fragment f, @Nullable Bundle savedInstanceState) {super.onFragmentCreated(fm, f, savedInstanceState);Log.d(TAG, "onFragmentCreated: " + f);setDisplayDensity(context);}}, true);}
}

使用方式

Activity

以下为主Activity调用,必须在setContentView之前。在view绘制之前需要设置好DisplayMetrics.density。

要注意onConfigurationChanged里,分辨率差距过小,页面可能不会进行重建,这个时候需要我们手动重建。

@Overridepublic void onCreate(@Nullable Bundle savedInstanceState) {DisplayUtils.getInstance().setDisplayDensity(this);DisplayUtils.getInstance().setDisplayDensityForFragments(this);super.onCreate(savedInstanceState);setContentView(R.layout.xxxx);}@Overridepublic void onConfigurationChanged(@NonNull Configuration newConfig) {super.onConfigurationChanged(newConfig);Log.e(TAG, "onConfigurationChanged screenInfo Width:" + ScreenUtils.getScreenWidth() + " height:" + ScreenUtils.getScreenHeight() + " dpi:" + ScreenUtils.getScreenDensityDpi());DisplayUtils.getInstance().setDisplayDensity(this);//偶现分辨率不会重绘,手动重绘this.recreate();}

Fragment

在主Activity添加“ DisplayUtils.getInstance().setDisplayDensityForFragments(this);”这句代码后,本身Fragment是不需要单独设置的。

因为我们项目是只有一个activity,剩下的都是Fragment,时序问题导致,偶现首个添加的Fragment自适应失败,所以才需要单独添加代码。

同样也需要在设置view之前,但是不能在onCrate,请参考第二种情况的原因。

为了保证自适应一定成功,要在页面显示到屏幕之前,毫秒级别的差距,设置成你想要的DisplayMetrics.density。否则就有可能会失败。

@Nullable@Overridepublic View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {DisplayUtils.getInstance().setDisplayDensity(getMainActivity());binding = DataBindingUtil.inflate(inflater, R.layout.xxxx, container, false);return binding.getRoot();}

动态添加View的时候,最好也设置一下。

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

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

相关文章

Flutter-发现局域网中的设备

前言 现在有一个需求:要能够获取到局域网中的遮阳帘设备。通过搜索发现flutter_mdns_plugin可以满足这个需求 Pub:flutter_mdns_plugin | Flutter package GitHub:https://github.com/terrabythia/flutter_mdns_plugin MDNS服务类型 要根据…

Vue3嵌套导航相对路径问题

有如下的页面设计,页面上方第一次导航,两个菜单,首页和新闻 点击新闻,内容里面嵌套一个左侧和右侧,左侧有4条新闻,点击某一条新闻,右侧显示详情 代码如下: ​ File Path: d:\hello\…

自感式压力传感器结构设计

自感式压力传感器的结构如图2-35 和图 2-36所示,分为变隙式、变面积式和螺管式三种,每种均由线网、铁心和衔铁三部分组成。 图2-35 自感式压力传感器的结构 1-线圈 2-铁心 3-衔铁 图2-36 螺管式 1-线图 2-铁心 3一衔铁 自感式压力传感器按磁路变化可…

QT的核心机制 对话框资源

案例 1、键盘按下w,s,a,d键分别为标签向上,下,左,右移动 鼠标按下获取本地坐标,全局坐标 鼠标双击获取本地坐标,全局坐标 鼠标移动获取本地坐标,全局坐标 让鼠标跟踪…

Midjourney零基础学习

Midjourney学习笔记TOP04 Midjourney的各种参数设置 Midjourney的用户操作界面没有醒目的工具栏、属性栏,所有的操作都是通过调用各种指令和参数进行的。 【MJ Version】 Midjourney在2023年3月份就已经更新到了V5版本,V5版本除了画质有所提升外&#…

interwirelessac9560感叹号,电脑无法连接wifi,无法搜索到wifi

interwirelessac9560感叹号 电脑无法连接wifi,无法搜索到wifi 原因 这可能是wifl模块出现了问题。 解决方案 1、winx 打开,选择【设备管理器】 2、选择网络适配器 右键打开wireless-AC,选择【卸载设备】。 3、关机2分钟后&#xff0c…

SpringBoot智慧外贸平台

专业团队,咨询就送开题报告,欢迎大家私信留言,联系方式在文章底部 摘 要 网络的广泛应用给生活带来了十分的便利。所以把智慧外贸管理与现在网络相结合,利用java技术建设智慧外贸平台,实现智慧外贸的信息化。则对于进…

数据结构-5.9.树的存储结构

一.树的逻辑结构: 二.双亲表示法(顺序存储): 1.树中除了根结点外每一颗树中的任意一个结点都只有一个父结点(双亲结点); 2.结点包括结点数据和指针; 3.上述图片中右边的顺序存储解析:比如A结点左边的0,就…

ASML业绩暴雷,股价一度跌超16%

KlipC报道:当地时间10月15日,阿斯麦(ASML)原定于周三公布的三季度业绩报告由于技术原因被短暂地提前公布,业绩报告显示,阿斯麦第三季度总净销售额75亿欧元,毛利率50.8%,净利润21亿欧…

社招高频面试题

1.单例模式 面试突击50:单例模式有几种写法? 2.Mybatis缓存机制 MyBatis的一、二级缓存查询关系 一级缓存是SqlSession级别,不能跨SqlSession共享,默认开启。 二级缓存是基于mapper namespace级别的,可以跨SqlSessi…

PetaLinux工程的常用命令——petalinux-create

petalinux-create&#xff1a;此命令创建新的PetaLinux项目或组件。 注&#xff1a;有些命令我没用过&#xff0c;瞎翻译有可能会翻译错了&#xff0c;像是和fpgamanager相关的部分。 用法: petalinux-create [options] <-t|--type <TYPE> <-n|--name <COMPONEN…

LeetCode:3039.进行操作使字符串为空(模拟 Java)

目录 3039.进行操作使字符串为空 题目描述&#xff1a; 实现代码与解析&#xff1a; 模拟 原理思路&#xff1a; 3039.进行操作使字符串为空 题目描述&#xff1a; 给你一个字符串 s 。 请你进行以下操作直到 s 为 空 &#xff1a; 每次操作 依次 遍历 a 到 z&#xff…

Mongodb 获取集合(collection)的统计信息

在MongoDB中&#xff0c;获取指定集合&#xff08;collection&#xff09;的统计信息可以通过执行collStats命令来实现。这个命令提供了关于集合的详细信息&#xff0c;包括&#xff1a; 集合的大小索引的大小和数量文档的数量存储空间的使用情况各种统计数据&#xff0c;如平…

[linux 驱动]gpio子系统详解与实战

目录 1 描述 1.1 文件节点操作 gpio 引脚 1.2 gpio 引脚计算 2 结构体 2.1 gpio_desc 2.2 gpio_device 2.3 gpio_chip 3 相关函数 3.1 goio 申请释放 3.1.1 gpio_request 3.1.2 gpio_free 3.2 gpio 输入输出设置 3.2.1 gpio_direction_input 3.2.2 gpio_direction…

filecoin filspark 检索

安装 boost 1、安装 YugabyteDB2、boostd-data 运行3、初始化 boostd4、运行 boostd5、运行 booster-http6、需要公网映射端口6.1 Libp2p 公网映射本地端口24001 发布矿工6.2 Graphql 公网映射本地端口8080 web界面6.3 IndexProvider.HttpPublisher 公网映射本地端口6700 http发…

微信小程序路由跳转的区别及其常见的使用场景

在微信小程序中&#xff0c;页面路由跳转的实现有几种常用方式&#xff0c;不同的跳转方式适用于不同的使用场景。下面是几种跳转方法的区别及其在实际项目中的应用场景。 1. wx.navigateTo 简介&#xff1a;保留当前页面并跳转到指定页面&#xff0c;最多保留10个页面的历史记…

Scala入门基础(10)高级函数

一.什么是高阶函数 二.map函数 三.foreach函数 四.filter函数 五.flatten函数 正文&#xff1a; 一.什么是高阶函数 高阶函数&#xff1a;是一个特殊的函数&#xff0c;特殊之处在于&#xff1a;它指使用其他函数作为参数或返回值 &#xff08;演示&#xff09; 二.map函…

Linux -- 初识动静态库

目录 为什么要有库&#xff1f; 静态库 什么是静态库&#xff1f; 特点 优点 缺点 动态库 什么是动态库&#xff1f; 优点 缺点 编译器会选择哪个库&#xff1f; 为什么要有库&#xff1f; 库的存在是为了提高软件开发的效率、促进代码复用以及简化维护工作。通过使用…

SpringSecurity(一)——认证实现

一、初步理解 SpringSecurity的原理其实就是一个过滤器链&#xff0c;内部包含了提供各种功能的过滤器。 当前系统中SpringSecurity过滤器链中有哪些过滤器及它们的顺序。 核心过滤器&#xff1a; &#xff08;认证&#xff09;UsernamePasswordAuthenticationFilter:负责处理…

js获取硬件设备

在Javascript中通过MediaDevices 的方法enumerateDevices() 请求一个可用的媒体输入和输出设备的列表&#xff0c;例如麦克风&#xff0c;摄像机&#xff0c;耳机设备等。返回的 Promise 完成时&#xff0c;会带有一个描述设备的 MediaDeviceInfo 的数组。通常你可以使用 navig…