lib库实现UI定制化

背景

随着公司项目越来越多,会使用到公共的UI组件,那么将组件抽离出来独立成一个lib库是有必要的。但是,不同的项目存在一定的差异化是不可避免的,这时候,如何在提高公共组件可复用性又可实现UI差异?那么UI定制化就是本文的重点。

组件模块化

组件模块化根据粒度大小,将其分为:控件模块化和功能模块化。

控件模块化,就是将某个控件抽离出来,它仅仅用来显示效果,不包括业务逻辑;

相对的,功能模块化,就是包含了业务逻辑,一个较完整的功能模块。

控件模块化

控件模块化中的UI定制,和Android中自定义View一样,在res/attr.xml文件下声明一个declare-styleable

<declare-styleable name="YLCalendar">
    <attr name="todayBorderColor" format="color"/>
    <attr name="todayShape">
        <enum name="circle" value="0"/>
        <enum name="rectangle" value="1"/>
    </attr>
    <attr name="todayFill" format="boolean"/>
    <attr name="todayTextColor" format="color"/>
    <attr name="todayTextSize" format="dimension"/>
    <!--公历字体颜色-->
    <attr name="solarTextColor" format="color" />
    <!--农历字体颜色-->
    <attr name="lunarTextColor" format="color" />
    <!--不在当月日期的颜色-->
    <attr name="hintColor" format="color" />
</declare-styleable>

然后在自定义view中去获取属性值

public abstract class CalendarViewPager extends ViewPager{
    public CalendarViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        initAttr(context,attrs);
    }

    private void initAttr(Context context, AttributeSet attrs){
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.YLCalendar);
        ...
        ta.recycle();
    }
}

最后在引用自定义view时,给它配置属性值

<com.yealink.calendar.calendar.MWCalendar
    android:id="@+id/mWCalendar"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    style="@style/YLCalendarStyle">

</com.yealink.calendar.calendar.MWCalendar>

其中YLCalendarStyle包含了R.styleable.YLCalendar的属性项

<style name="YLCalendarStyle">
    <!--今天绘制形状:圆形、矩形-->
    <item name="todayShape">circle</item>
    <!--今天形状是否实心-->
    <item name="todayFill">true</item>
    <!--今天字体颜色-->
    <item name="todayTextColor">@android:color/white</item>
    <!--今天字体大小-->
    <item name="todayTextSize">@dimen/solarTextSize</item>
</style>

这是将控件进行封装,将一些属性暴露出来,然后使用的时候通过xml进行动态设置。

功能模块化

功能模块与控件模块UI定制的不同之处在于,功能模块已经将控件进行组合显示,并包含了一些业务逻辑操作,因此它无法像控件那样通过xml进行引用,外界只能通过接口调起该功能模块,因此它的UI定制将通过另外一种方式。

第一种方式:通过theme主题
在attr.xml文件下声明属性

<resources>
    <!--标题栏背景色-->
    <attr name="titleBarBackground" format="color"/>
    <!--状态栏高度-->
    <attr name="statusBarHeight" format="dimension"/>
</resources>

和之前的styleable属性不同,它不在declare-styleable节点,而是在根节点直接声明。接着使用的时候,如下:

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <View
        android:id="@+id/status_bar"
        android:layout_width="match_parent"
        android:layout_height="?attr/statusBarHeight"
        android:background="?attr/titleBarBackground"/>
</LinearLayout>

可以看到,通过?attr进行引用,它标示预定义样式,属性值会随着主题而改变。
最后定制UI的时候,可以在应用的主题theme进行赋值,如下:

<style name="AppBaseTheme" parent="Theme.AppCompat.Light.NoActionBar">
    ...
    <item name="statusBarHeight">0dp</item>
    <item name="titleBarBackground">@color/app_primary_white</item>
</style>

第二种方式:通过style样式

这种方式和控件模块有点相似,只是它不是通过xml配置。在res/attr.xml文件下声明一个declare-styleable

<declare-styleable name="YlAlbum">
    <!--状态栏和标题栏颜色-->
    <attr name="statusBarColor" format="color"/>
    <!--是否显示标题栏左边按钮文字“返回”-->
    <attr name="showTitleBarLeftText" format="boolean"/>
    <!--要显示的图片格式-->
    <attr name="imageFormat">
        <flag name="jpg" value="1"/>
        <flag name="jpeg" value="2"/>
        <flag name="png" value="4"/>
        <flag name="bmp" value="8"/>
        <flag name="gif" value="16"/>
        <flag name="all" value="31"/>
    </attr>
    <attr name="sendButtonText" format="string"/>
</declare-styleable>

接着在style.xml定义一个style,配置属性值

<style name="YlAlbumStyle">
    <!--状态栏和标题栏颜色-->
    <item name="statusBarColor">@color/album_lib_status_bar_color</item>
    <!--是否显示标题栏左边按钮文字“返回”-->
    <item name="showTitleBarLeftText">false</item>
    <!--要显示的图片格式-->
    <item name="imageFormat">gif|jpg|jpeg|bmp|png</item>
    <!--发送按钮显示的文字内容-->
    <item name="sendButtonText">@string/album_lib_send</item>
</style>

style中的属性项都是来于declare-styleable(上面的YlAlbum)

最后在代码中读取属性值,并使用。

private void initAttributes(){
    int styleID = getIntent().getIntExtra("styleID",R.style.YlAlbumStyle);
    TypedArray typedArray = obtainStyledAttributes(styleID,R.styleable.YlAlbum);
    Attrs.statusBarColor = typedArray.getColor(R.styleable.YlAlbum_statusBarColor,getResources().getColor(R.color.album_lib_status_bar_color));
    Attrs.showTitleBarLeftText = typedArray.getBoolean(R.styleable.YlAlbum_showTitleBarLeftText,true);
    Attrs.imageFormat = typedArray.getInt(R.styleable.YlAlbum_imageFormat,Attrs.ImageFormat.ALL.getFlag());
    Attrs.sendButtonText = typedArray.getText(R.styleable.YlAlbum_sendButtonText);
    typedArray.recycle();
}

主要是通过getTheme().obtainStyledAttributes方法读取styleable的属性值,代码中使用这些属性值。

总结

UI定制有三种形式:
1. 自定义view通过xml配置
2. 通过在xml预定义?/attr,配置theme主题
3. 通过自定义style,代码中读取style属性值

第一种相对较灵活,在xml引用自定义view时即可配置属性值;第二种,由于是跟随主题,而一个activity或者application只配置一次主题,导致项目中只能使用一套UI;第三种,可以动态的使用不同的style,定制不同的UI,且属性项是在一个declare-styleable内,较集中,方便管理。因此,一般来说,控件模块化使用第一种方式,功能模块化使用第三种方式。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值