lib库实现UI定制化

来源:互联网 发布:淘宝店铺分类导航 编辑:程序博客网 时间:2024/06/13 05:32

背景

随着公司项目越来越多,会使用到公共的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内,较集中,方便管理。因此,一般来说,控件模块化使用第一种方式,功能模块化使用第三种方式。

原创粉丝点击