资讯专栏INFORMATION COLUMN

一种巧妙的drawable.xml替代方案

jasperyang / 347人阅读

摘要:不过,如果两相结合,作为对第一种方案的补充倒是一个不错的方案。总结回顾本文,并没有任何复杂的代码或高深的逻辑组合,仅提出一种巧妙的替代方案,具有既具有高可读性,又能全面适配的特点。

如何维护(替换)drawable xml是android开发中一个老生常谈的话题。按照标准的Android布局开发模式,我们不得不为各种UI效果新建不同的xml文件进行描述,哪怕是简单的一个圆角。随着项目迭代,成百上千的xml连同那模棱两可的文件名,不仅让开发者复用或清理的成本难以估计,还使得项目体积急剧增大。因此,下面我们探索一种原理巧妙、适配全面的drawable替代方案。

传统方案总结

我们先概括下目前市面上已有的方案,大致分为两种实现方式。

一种是继承某个(或某几个)常用的控件,然后将drawable.xml中的常用属性作为当前控件的自定义属性,最后在控件内部动态生成drawable作为该控件的背景。这种方案的优点很明显:能直观地将drawable效果描述作为控件的属性定义在布局xml中,具有很好的可读性;但是缺点也不可忽视,这些属性并不能应用到任意控件,导致在很多时候还是不得不创建drawable.xml文件。

另一种方案则是将drawable的常用属性封装为代码API,以动态的方式在代码中生成并赋值给控件。这种方案理论上完全抛弃了drawable.xml,可以适配任意控件,但是若想完全以这种方式达到完全替换xml,个人觉得不可能,代码量大,关联性低是其最大的缺点,单看布局,无从知晓该控件的最终效果。不过,如果两相结合,作为对第一种方案的补充倒是一个不错的方案。

新方案探索

上述两种方案各有千秋,但都无法完全解决问题,我们对上述两种方案进行分析,提出以下问题:为什么不能有一种「既具有高可读性,又能全面适配」的drawable.xml替代方案呢?也就是说能同时兼顾前面提到的两种方案的优点,高可读性意味着对drawable的描述需要作为属性定义在布局文件中、全面适配意味这些属性对任意控件都有效。思来想去,答案似乎只有一个:DataBinding。说到这里,可能有些朋友已经隐隐猜到了,不过别急,容我娓娓道来。

DataBinding是Android官方推出的数据绑定库,尽管已有数年,但是我估计仍有部分开发者还没有接触甚至有些抵触,具体就不细说,但是我希望你暂且能拥抱它,继续阅读。
数据绑定让数据变化能直接反映到布局中,对于控件已有的属性,例如TextView的android:text属性,一旦通过DataBinding绑定:

在运行时内部就会调用TextView内部的setText方法。其实现原理的关键就是DataBinding通过提供的@BindingAdapter注解,该注解将任意指定的属性和任意指定的方法关联,DataBinding会在编译的时候动态生成的调用关系,而对于常用的控件,DataBinding已经预置了对应的注解方法,例如以下就是TextView的setText方法:

@BindingAdapter("android:text")
public static void setText(TextView view, CharSequence text) {
    final CharSequence oldText = view.getText();
    if (text == oldText || (text == null && oldText.length() == 0)) {
        return;
    }
    if (text instanceof Spanned) {
        if (text.equals(oldText)) {
            return; // No change in the spans, so don"t set anything.
        }
    } else if (!haveContentsChanged(text, oldText)) {
        return; // No content changes, so don"t set anything.
    }
    view.setText(text);
}

我们需要关注的就是这个@BindingAdapter注解,「任意指定的属性」这个属性并非特指我们在布局中Android提供的标准属性,也就是说,我们可以提供任意字符串作为属性,而任意方法很好理解,上面的代码片段很好的表达了这个意思,我们唯一需要关注的就是这个方法的参数:第一个参数是指定注解中的属性的作用域,后面的参数则是和注解所声明的属性一一对应,那么结合到我们本文的主题,答案也就呼之欲出了:

新方案实现

提供一个用@BindingAdapter注解的方法,作用域指定为View(即任意控件);参数约定为drawable.xml中的属性,不就达到了目的吗。是否是感觉到一丝丝巧妙?既然方案有了,下面我们来看具体实现。

限于drawable属性的丰富性,本文以常用的属性solid 和 corner为例展开。如以下片段所示:

@BindingAdapter(value = {
        "drawable_solidColor",
        "drawable_radius",
}, requireAll = false)
public static void setViewBackground(View v, int color, int radius) {
    GradientDrawable drawable = new GradientDrawable();
    drawable.setColor(color);
    drawable.setCornerRadius(radius);
    view.setBackground(drawable);
}

上面代码片段定义了两个属性:drawable_solidColor, drawable_radius,分别表示solid的color和corner的radius属性,也就是说稍后我们就就可以在布局文件中为每个View都指定该属性了;

这里可能有朋友会产生疑问,drawable的属性那么多,这里只定义了两个还好,如果把所有的drawable属性都定义,那岂不是每个控件都要把每个属性都指定一次,即使不需要。所以还需要提一下requireAll参数,它表示是否需要每个属性都必须绑定了数据才会调用setViewBackground方法,设置为false后,就可以在布局文件中只指定需要的属性即可。

以上几行代码完成了基本定义,下面我们来看看如何使用:


    

不用怀疑,就是这么简单,即使这里不贴出效果图,我想大家脑海中已经浮现出来了,是不是觉得一目了然?以此类推,其它的drawable属性也可以通过本方案逐一实现。

总结

回顾本文,并没有任何复杂的代码或高深的逻辑组合,仅提出一种巧妙的drawable.xml替代方案,具有「既具有高可读性,又能全面适配」的特点。

从成本来说,本方案应该是最低的(特别是对一些已经在使用DataBinding的项目):只需要定义一个方法即可,而效果却是最优的:理论来讲,实现该方案后,可以减少99%的drawable.xml创建。
如果非要说出本方案的缺点,那么它的实现原理所依赖的核心库DataBinding可能是有些开发者所不能接受的。

读到这里,是否觉得意犹未尽?没错,我已依据本文的方案替大家整理好了几乎所有常用的drawable属性提交到了GitHub,核心依然是只有一个方法,直接可用。

Github地址:https://github.com/whataa/noD...

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/14426.html

相关文章

  • 一种巧妙drawable.xml替代方案

    摘要:不过,如果两相结合,作为对第一种方案的补充倒是一个不错的方案。总结回顾本文,并没有任何复杂的代码或高深的逻辑组合,仅提出一种巧妙的替代方案,具有既具有高可读性,又能全面适配的特点。 如何维护(替换)drawable xml是android开发中一个老生常谈的话题。按照标准的Android布局开发模式,我们不得不为各种UI效果新建不同的xml文件进行描述,哪怕是简单的一个圆角。随着项目迭...

    zhoutao 评论0 收藏0
  • Android夜间模式实践

    摘要:现在我采用的就是这种简单粗暴的方法,用户体验比较不友好,后期需要参考知乎的实现,改进实现。参考链接夜间模式最佳实践知乎和简书的夜间模式实现套路夜间模式,你所不知道的坑 前言 由于项目需要,近段时间开发的夜间模式功能。主流的方案如下: 1、通过切换theme实现 2、通过resource id映射实现 3、通过Android Support Library的实现 方案选择 切换the...

    junfeng777 评论0 收藏0
  • Drawable 使用详解

    摘要:启用或停用位图过滤。当位图收缩或拉伸以使其外观平滑时使用过滤。在每个状态变更期间,将从上到下遍历状态列表,并使用第一个与当前状态匹配的项目此选择并非基于最佳匹配,而是选择符合状态最低条件的第一个项目。每个可绘制对象由单一元素内的元素表示。 showImg(https://segmentfault.com/img/remote/1460000019975019?w=157&h=54); ...

    JinB 评论0 收藏0
  • 设计套路:Mysql主键选取

    摘要:最近在对一些大表进行优化,发现主键和索引设计都有争议,就此从原理上分析主键设计该如何选取。主键的选取我先把结论给出来,方便喜欢直接套用的童鞋,但是对技术有追求的人来说,还是了解下原理比较有说服力。 最近在对一些大表进行优化,发现主键和索引设计都有争议,就此从原理上分析主键设计该如何选取。 Mysql的数据结构 Mysql是由B+树构成,搞清楚下面两个问题,就知道为什么用B+树了。 sh...

    JerryWangSAP 评论0 收藏0
  • 安卓(Android)开发基础知识

    摘要:文件是一种归档文件,以格式构建,以为文件扩展名。用户可以使用自带的命令创建或提取文件。也可以使用其他压缩工具,不过压缩时文件头里的条目顺序很重要,因为文件常需放在首位。文件内的文件名是文本。文件基于文件格式,它与文件的构造方式相似。.aar文件 .aar是一种压缩文件,和.jar类似,不过它可以包含资源文件,例如图片、drawable、xml资源 .jar文件 在软件领域,JAR文件(Jav...

    zhunjiee 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<