Android多分辨率适配框架(2)— 原理剖析

简介: 探索Android软键盘的疑难杂症 深入探讨Android异步精髓Handler 详解Android主流框架不可或缺的基石 站在源码的肩膀上全解Scroller工作机制Android多...

探索Android软键盘的疑难杂症
深入探讨Android异步精髓Handler
详解Android主流框架不可或缺的基石
站在源码的肩膀上全解Scroller工作机制


Android多分辨率适配框架(1)— 核心基础
Android多分辨率适配框架(2)— 原理剖析
Android多分辨率适配框架(3)— 使用指南


自定义View系列教程00–推翻自己和过往,重学自定义View
自定义View系列教程01–常用工具介绍
自定义View系列教程02–onMeasure源码详尽分析
自定义View系列教程03–onLayout源码详尽分析
自定义View系列教程04–Draw源码分析及其实践
自定义View系列教程05–示例分析
自定义View系列教程06–详解View的Touch事件处理
自定义View系列教程07–详解ViewGroup分发Touch事件
自定义View系列教程08–滑动冲突的产生及其处理


PS:Android多分辨率适配框架视频教程同步更新啦


前言

在上一篇文章中我们先讨论了Andoid中常见的与度量有关的知识和技术;然后对于drawable的加载原理也做了一个完整分析。

在完成这些准备之后,就要直面我们的目标:一套UI图实现多分辨率的适配


思路

国庆的时候出去玩了一圈,回来之后我洗了一张女友的照片放到相框里面

这里写图片描述

昨天,我又买了一个同款的小号的相框,它的宽和高只有原来的一半。
我现在把原来的照片等比例缩小二分之一是不是就可以将其放入新的相框了呢?

嗯哼,与此类似:为了实现多分辨率的适配,我们需要将UI进行等比例的缩放。
比如:可以把一个在高分辨率(例如1920*1080)手机上的布局等比例缩小后展示在其他分辨率(例如800*480)的手机上。

在知晓了总体思路后,我们再来拆解Android多分辨率适配框架的具体实现。


UI切图

在多数情况下UI设计师会切几套对应的图,我们再将其放入drawable-ldpi、drawable-mdpi、drawable-hdpi、drawable-xhdpi、drawable-xxhdpi、drawable-xxxhdpi文件夹即可。但是,现在,我们只需要一套图,那么到底采用哪一套切图呢?目前,Android手机中主流的分辨率是xxhdpi,所以我们可以采用drawable-xxhdpi这套UI切图,在xxhdpi的手机上调好布局后,当其他较低dpi手机加载该UI时再将其等比例缩小即可。

切图是有了,但是该把它放到res下哪个文件夹中呢?
有人说:这不是明摆着的么,当然放到drawable-xxhdpi中呗。
真的是这样么?
嗯哼,结合我们上一篇的讲解可知:如果把切图放到了drawable-xxhdpi中,那么当这些切图显示在hdpi的手机上时图片会被缩小并且可能导致失真。同理,如果这些切图显示在xxxhpi的手机上时图片会被放大并且可能导致失真。图片的放大和缩小,这个好理解,但是为什么会导致图片失真呢?或者说为什么不是等比例的放大或者缩小呢?现在通过一个实例来分析原因。
在此,准备两部测试手机:
华为P7,分辨率为1920*1080,dpi为480
HTC T392,分辨率为800*480,dpi为240
现在有一套专门为dpi等于480的手机准备的切图放在drawable-xxhdi中。当P7加载该套切图时图片显示正常,当T392加载该套图片时图片被缩小,且缩小比为240/480=0.5。但是请注意两部手机分辨率的比值。其中,宽的比:480/1080=0.44;高的比800/1920=0.42;也就是说两个屏幕的分辨率的比大概是0.4,但是图片的缩放比是0.5,所以这两者的不一致导致了图片缩放后的失真。如果要使图片在HTC T392上不失真,那么需要按照0.4缩放图片,而非0.5.

为了摆脱这个桎梏,避免图片的缩放导致图片失真:

  1. 将切图放入drawable-nodpi中。
    该文件夹中的图片不会被缩放,在不同分辨率的手机上都只显示原图的大小。如此以来,摒弃了系统对于图片的缩放,为我们以后自己处理图片的缩放做好了铺垫。
  2. 计算出缩放比。
    依据不同的分辨率计算出缩放比。

总之,我们不再采用系统提供的对于图片的适配和缩放,而是自己确定一个准确的缩放比例将高分辨率的UI按照该比例缩放从而实现多分辨率的适配


布局的细节

嗯哼,在知道了怎么做之后,我们就首先要在一个高分辨率(如:1920*1080)手机上完成布局。
在布局的过程中,请注意一个问题:不再使用dp、sp作为大小单位,而是统一使用px。

为什么要这么做呢?

  1. 缩放比例的确定是基于屏幕的分辨率而确定的。
    屏幕的分辨率均是采用px作为单位的,所以在布局时亦采用px从而保证缩放比例的一致和准确
  2. dp和sp均与设备的dpi有关。
    不同设备的dpi值不一样,所以在不同的设备上同一个dp和sp所对应的px值是不尽相同的。如果采用dp和sp作为尺寸的单位,那么在缩放时会产生较大的偏差

代码实现

好了,现在图片有了,布局也写好了,现在就要开始对UI缩放了。

第一步:

计算缩放比

int widthPixels = displayMetrics.widthPixels;
scale = (float)widthPixels / BASE_SCREEN_WIDTH_FLOAT;

通过设备的宽与BASE_SCREEN_WIDTH_FLOAT的比值计算出缩放比。
此处的BASE_SCREEN_WIDTH_FLOAT就是一个缩放的基准,比如高分辨率手机(如:1920*1080)中的1080。

第二步:

等比例缩放UI

 /**
  * 原创作者:
  * 谷哥的小弟
  *
  * 博客地址:
  * http://blog.csdn.net/lfdfhl
  */
public static void scaleViewSize(View view) {
    if (null != view) {
        int paddingLeft = getScaleValue(view.getPaddingLeft());
        int paddingTop = getScaleValue(view.getPaddingTop());
        int paddingRight = getScaleValue(view.getPaddingRight());
        int paddingBottom = getScaleValue(view.getPaddingBottom());
        view.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);

        LayoutParams layoutParams = view.getLayoutParams();

        if (null != layoutParams) {

            if (layoutParams.width > 0) {
                layoutParams.width = getScaleValue(layoutParams.width);
            }

            if (layoutParams.height > 0) {
                layoutParams.height = getScaleValue(layoutParams.height);
            }

            if (layoutParams instanceof MarginLayoutParams) {
                MarginLayoutParams marginLayoutParams = (MarginLayoutParams) layoutParams;
                int topMargin = getScaleValue(marginLayoutParams.topMargin);
                int leftMargin = getScaleValue(marginLayoutParams.leftMargin);
                int bottomMargin = getScaleValue(marginLayoutParams.bottomMargin);
                int rightMargin = getScaleValue(marginLayoutParams.rightMargin);
                marginLayoutParams.topMargin = topMargin;
                marginLayoutParams.leftMargin = leftMargin;
                marginLayoutParams.bottomMargin = bottomMargin;
                marginLayoutParams.rightMargin = rightMargin;
            }
        }
        view.setLayoutParams(layoutParams);
    }
}

利用该方法对布局中的每个View进行缩放操作。
在该方法中对每个View的宽高,padding,margin值都按比例缩放,并且在缩放后重新设置其布局参数。

第三步:

关于TextView的特殊处理。

对于TextView,不但要缩放其尺寸,还需要对其字体进行缩放:

 /**
  * 原创作者:
  * 谷哥的小弟
  *
  * 博客地址:
  * http://blog.csdn.net/lfdfhl
  */
   Object isScale = textView.getTag(R.id.is_scale_font_tag);
    if (!(isScale instanceof Boolean) || !((Boolean) isScale).booleanValue()) {
        float size = textView.getTextSize();
        size *= scale;
        textView.setTextSize(0, size);
      }

除此以外,还要考虑到对TextView的CompoundDrawable进行缩放

 /**
  * 原创作者:
  * 谷哥的小弟
  *
  * 博客地址:
  * http://blog.csdn.net/lfdfhl
  */
public static Drawable scaleDrawableBounds(Drawable drawable) {
    int right=getScaleValue(drawable.getIntrinsicWidth());
    int bottom=getScaleValue(drawable.getIntrinsicHeight());
    drawable.setBounds(0, 0, right, bottom);
    return drawable;
}

总结

嗯哼,关于Android多分辨率适配框架的原理就分析完了。再回过头看,可以发现:其实它没有我们想象的那么难。
对于该框架的理解和使用,有以下几个要点:

  • 切图存放于drawable-nodpi
  • 抛开系统的dpi并且摒弃dp和sp,统一使用px作为尺寸单位
  • 按照高分辨率(如1920*1080)切图和布局
  • 在代码中等比例缩放每个View

目前,xxhdpi分辨率的手机占了主流,所以在该框架中采用了drawable-xxhdpi的切图。倘若以后xxxhdpi分辨率的手机占了主导地位,那么就请UI设计师按照该分辨率切图,我们将其放在drawable-nohdpi中,再修改BASE_SCREEN_WIDTH_FLOAT即可。

who is the next one? ——> Demo



PS:Android多分辨率适配框架视频教程同步更新啦


相关文章
|
1月前
|
缓存 Java 数据库
Android的ANR原理
【10月更文挑战第18天】了解 ANR 的原理对于开发高质量的 Android 应用至关重要。通过合理的设计和优化,可以有效避免 ANR 的发生,提升应用的性能和用户体验。
124 56
|
1月前
|
算法 JavaScript Android开发
|
25天前
|
开发框架 Dart Android开发
安卓与iOS的跨平台开发:Flutter框架深度解析
在移动应用开发的海洋中,Flutter作为一艘灵活的帆船,正引领着开发者们驶向跨平台开发的新纪元。本文将揭开Flutter神秘的面纱,从其架构到核心特性,再到实际应用案例,我们将一同探索这个由谷歌打造的开源UI工具包如何让安卓与iOS应用开发变得更加高效而统一。你将看到,借助Flutter,打造精美、高性能的应用不再是难题,而是变成了一场创造性的旅程。
|
2月前
|
Java 程序员 API
Android|集成 slf4j + logback 作为日志框架
做个简单改造,统一 Android APP 和 Java 后端项目打印日志的体验。
128 1
|
2月前
|
XML 前端开发 Android开发
Android View的绘制流程和原理详细解说
Android View的绘制流程和原理详细解说
48 3
|
3月前
|
ARouter 测试技术 API
Android经典面试题之组件化原理、优缺点、实现方法?
本文介绍了组件化在Android开发中的应用,详细阐述了其原理、优缺点及实现方式,包括模块化、接口编程、依赖注入、路由机制等内容,并提供了具体代码示例。
51 2
|
3月前
|
前端开发 Java 数据库
💡Android开发者必看!掌握这5大框架,轻松打造爆款应用不是梦!🏆
在Android开发领域,框架犹如指路明灯,助力开发者加速应用开发并提升品质。本文将介绍五大必备框架:Retrofit简化网络请求,Room优化数据库访问,MVVM架构提高代码可维护性,Dagger 2管理依赖注入,Jetpack Compose革新UI开发。掌握这些框架,助你在竞争激烈的市场中脱颖而出,打造爆款应用。
416 3
|
3月前
|
编解码 前端开发 Android开发
Android经典实战之TextureView原理和高级用法
本文介绍了 `TextureView` 的原理和特点,包括其硬件加速渲染的优势及与其他视图叠加使用的灵活性,并提供了视频播放和自定义绘制的示例代码。通过合理管理生命周期和资源,`TextureView` 可实现高效流畅的图形和视频渲染。
291 12
|
3月前
|
编译器 Android开发 开发者
带你了解Android Jetpack库中的依赖注入框架:Hilt
本文介绍了Hilt,这是Google为Android开发的依赖注入框架,基于Dagger构建,旨在简化依赖注入过程。Hilt通过自动化的组件和注解减少了DI的样板代码,提高了应用的可测试性和可维护性。文章详细讲解了Hilt的主要概念、基本用法及原理,帮助开发者更好地理解和应用Hilt。
93 8
|
2月前
|
Java 调度 Android开发
Android面试题之Kotlin中async 和 await实现并发的原理和面试总结
本文首发于公众号“AntDream”,详细解析了Kotlin协程中`async`与`await`的原理及其非阻塞特性,并提供了相关面试题及答案。协程作为轻量级线程,由Kotlin运行时库管理,`async`用于启动协程并返回`Deferred`对象,`await`则用于等待该对象完成并获取结果。文章还探讨了协程与传统线程的区别,并展示了如何取消协程任务及正确释放资源。
39 0