从动态缩放自定义View,聊聊为什么不要把问题复杂化

前言

我的项目中,关于动态修改View的大小的技术方案进阶之路,在之前的文章中其实有讲到,强烈建议有兴趣的小伙伴可以去看看《产品需求驱动下的技术演进:动态缩放View的不同方案》,因为这是我们团队历经2-3年的技术迭代过程。

今天其实想聊聊在我们上线的方案之后,其实还有更简单也更有效的方案,在我们走过的那些路中有很多问题其实我们把问题想的太复杂了,用的方法也太复杂了,如果"跳出三界之外",再回过头看看,或许有更简单有效的做法。

回顾一下之前的方案

在之前的方案中,我们经历了从生成ImageView到手动处理所有的子view,以及遇到的性能问题、边界值计算问题、清晰度问题、视觉和真实大小不一致带来的问题等等各种问题,有相同想法的可以去看看。

把问题简单化

缩放的本质其实就是修改原本定义在layout中的数值,我们所做的操作其实也就是围绕着这一块做的,而我们的xml中的布局,在一开始就有默认的大小,也就是系统自己会处理好所有事情,那为什么我们不能依靠系统处理好呢?

在我们的布局中,一般来说布局文件长这样

kotlin 复制代码
<LinearLayout
    android:layout_width="@dimen/container_width"
    android:layout_height="@dimen/container_height"
    android:padding="@dimen/container_padding">
    
    <TextView
        android:layout_width="@dimen/child_width"
        android:layout_height="@dimen/child_height"
        android:margin="@dimen/child_margin"/>
</LinearLayout>

宽度、大小、字体都用dimens管理,那如果我们直接修改dimens的值或者直接替换成套的dimens,是不是就可以最简单的解决问题?

在res/values、res/values-swxxxdp(或自定义后缀,如values-size1、values-size2)下创建多套dimens.xml,每套文件中用相同的 dimen 名称定义不同的尺寸值,对应 10 种缩放比例。

例如:

kotlin 复制代码
values-size1/dimens.xml(最小尺寸):  
<<dimen name="container_width">100dp</</dimen>  
<<dimen name="child_width">80dp</</dimen>

values-size2/dimens.xml(次小尺寸):  
<<dimen name="container_width">120dp</</dimen>  
<<dimen name="child_width">96dp</</dimen>

...(依此类推定义 10 套)

然后在使用的时候切换即可

kotlin 复制代码
val config = Configuration(resources.configuration)

// 这里需要自定义 "qualifier"(但非标准 swNNNdp/语言/方向等很难生效)

val newContext = createConfigurationContext(config)

val view = LayoutInflater.from(newContext).inflate(R.layout.my_layout, null)

需要注意的是,采用这个方案切换后需要重新执行infalte的一套流程,单纯靠requestLayout是没有办法刷新触发新的dimens的

这个方案自然也有弊端,所有的"可能性"都需要提前预设,例如原本的缩放比例是1-100%自由缩放,如果采用在这个方案下就可能需要提前预设100套方案,那是不是应该修改相关的产品测的策略,将进度变成以每10%为一个可调整区间,这样只需要预设10套dimens即可

进阶的方案

动态切换dimens的思路是完全正确的,但是如果我们直接修改dimens可能会带来一些意想不到的问题:

只能按系统 qualifier(sw600dp、values-xxhdpi)自动匹配,很难在运行时手动切换。

并且切换时需要 模拟系统配置变更,可能导致 Activity 重建甚至全局刷新。

那既然知道问题,咱们就解决问题,首先在dimens的方案上,继续定义多套dimens,然后在主题中定义不同的style

xml 复制代码
<!-- 默认尺寸 -->

<style name="AppTheme.Size1" parent="Theme.AppCompat.Light">

    <item name="containerWidth">@dimen/size1_container_width</item>

    <item name="textSize">@dimen/size1_text_size</item>

</style>

 

<!-- 第二套尺寸 -->

<style name="AppTheme.Size2" parent="Theme.AppCompat.Light">

    <item name="containerWidth">@dimen/size2_container_width</item>

    <item name="textSize">@dimen/size2_text_size</item>

</style>

然后在布局中不直接写 @dimen/...,而是写 ?attr/textSize,这样才会跟随 theme 切换

xml 复制代码
<TextView

    android:layout_width="wrap_content"

    android:layout_height="wrap_content"

    android:textSize="?attr/textSize"/>

在自定义view中这样切换

kotlin 复制代码
context.setTheme(R.style.AppTheme_Size2)
LayoutInflater.from(context).inflate(R.layout.my_custom_view, this, true)

切换后重新 inflate,布局里的所有 ?attr 会自动应用新 theme 对应的尺寸。

让AI参与进来

到这里,想硬扯一句AI,因为在处理这个方案的时候就在想,这个方案需要大量的预设,这是"笨办法",那现在我们有了AI,其实可以通过AI代替我们做这些繁琐复杂的事情,比如说直接通过Trae让他帮我们生成100套预设,而我们也就有更多的精力去用在更值得我们去思考的地方。

想想

技术成长的过程,其实就是不断折腾,不断试错。很多时候我们追求"优雅"和"通用",但过度设计往往带来新的复杂性。

由繁至简的过程,其实是一种不一样的体验,"笨办法"或许有时候才是真正聪明的做法,真正的经验往往不是"多高明的技巧",而是什么时候该停下折腾,选择最合适的平衡点。

公众号:柿蒂

相关推荐
alexhilton15 分钟前
Compose Unstyled:Compose UI中失传的设计系统层
android·kotlin·android jetpack
大熊猫侯佩38 分钟前
斯塔克工业技术日志:用基础模型打造 “战甲级” 结构化 AI 功能
ai编程·swift·apple
刘龙超2 小时前
如何应对 Android 面试官 -> 玩转 RxJava (基础使用)
android·rxjava
lecepin2 小时前
AI Coding 资讯 2025.8.27
前端·ai编程
kerli3 小时前
kotlin协程系列:callbackFlow
android·kotlin
不想取名564 小时前
VSCode MCP体验
ai编程
没有了遇见5 小时前
Android 原生定位实现(替代融合定位收费,获取经纬度方案)
android·kotlin
量子位5 小时前
小扎高薪挖来的人又跳回OpenAI了!首席科学家赵晟佳也要回去
openai·ai编程
量子位5 小时前
马斯克星舰试验再创历史!3次爆炸3次推迟终成功,顺利完成太空载荷部署
ai编程