无需自定义View,彻底解放shape,selector(二)

2,955 阅读3分钟

前言

新年快乐,大家好,我又来了。。。
这篇文章主要是介绍我之前的一个框架BackgroundLibrary预览功能的实现
相信很多人看过我之前的文章: 无需自定义View,彻底解放shape,selector吧 , 通过自定义标签去设置shape、selector的属性,省去了一大部分的shape.xml文件。
项目发布5个月,也累计了1500+的star,现在也基本稳定运行在各个项目中了。

问题

但是美中不足的是,虽然BackgroundLibrary这个库解决了繁琐的xml问题,确始终无法解决预览问题(下图所示),开发者只能直接在app中看到效果,无法在as中看到效果。这让我们开发的时候造成了一定的不便。


BackgroundLibrary原理是通过给原生控件添加自定义属性,然后在运行时期生成drawable,这样产生了shape、selector。而as是不会去编译代码的,这就导致了,在没有编译的时候编译器无法进行预览。

如何实现预览

Anko

首先我想到了一个同样类似原理的框架Anko,通过动态生成布局来提高app性能,它实现预览的方式是通过实现一个自定义预览插件,然后需要预览的时候,每次build一下项目,然后进行预览,显然这种方式和我们直接运行app没有太大的区别,而且开发插件的成本较高,不适合采用这种方法。

Android Studio编译器

那么as是如何实现view的预览的呢?
我们简单看一下TextView的源码:

TextView有三个构造函数,通常我们在通过代码生成布局的时候只会用到new TextView(context)这样的方式去生成对象,而且TextView还有两个构造函数,多了一个参数AttributeSet,而这个参数所包涵的便是我们在layout.xml中对View设置的各种属性,as编译器通过调用这个构造函数,实现了View的预览。
而这种方法对于这个框架来说是可行的,因此为了方便大家可以预览,我同样实现了对应的自定义View。

效果及使用方法

效果

使用方法

1、如果需要对View进行预览,直接把原来的View换成框架内对应的BLView即可,即可展示预览效果,如果不需要预览可以直接忽略这些用于预览的自定义View;
2、如果没有效果,make project一下即可;
3、如果BLView中没有对应的需要预览的View,可以很简单的自己实现一下,以BLTextView为例:

public class BLTextView extends AppCompatTextView {
    public BLTextView(Context context) {
        super(context);
    }

    public BLTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    public BLTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }

    private void init(Context context, AttributeSet attrs){
        BackgroundFactory.setViewBackground(context, attrs, this);
    }
}

继承所需要预览的View,然后在构造函数中添加BackgroundFactory.setViewBackground(context, attrs, this)方法即可。
注意
为了提高性能,这些View在编译的时候会自动替换为对应原生的View,所以除了再xml中,不要在代码中出现任何的BLTextView,否则会报类似如下的错误:

//错误
BLTextView button = findViewById(R.id.text);
//正确
BLTextView button = findViewById(R.id.text);


Caused by: java.lang.ClassCastException: android.support.v7.widget.AppCompatTextView cannot be cast to com.noober.background.view.BLTextView

总结

上面就是我实现思路的一个方式,只需一行代码setViewBackground去实现自定义View,来进行预览,并且在运行时替换自定义View,这样在开发的时候除了需要预览的情况,我们完全可以忽略这些自定义控件的存在,这对android sdk的升级改变都不会产生任何影响。欢迎大家提供更多的思路。