概念
自定義組合View是指android給我們提供的View本身功能不夠用,但是可以把幾個View粘合起來形成一個獨立的類,對外部提供統一的職能,内部View之間的邏輯實作可以隐藏,使之整體看起來就像是一個新的View。另外,還可以通過自定義屬性功能,使得我們的組合View直接在XML布局檔案中友善的使用
實作
定義一個基類,之後的組合View都繼承自它
public abstract class BaseCustomView extends RelativeLayout {
private static final String NAMESPACE = "http://schemas.android.com/apk/res-auto";
//重載構造函數 通過new建構對象時會調用此處
//View.java中原文:Simple constructor to use when creating a view from code
public BaseCustomView(Context context) {
super(context);
initView();
}
//在XML中建構時會調用此處,也是我們自定義屬性的構造函數,style預設用app的主題
//View.java中原文:Constructor that is called when inflating a view from XML
//...This version uses a default style of 0, so the only attribute values
//applie are those in the Context's Theme and the given AttributeSet
public BaseCustomView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs, getStyleable());
initAttributes(a);
initView();
a.recycle();
}
public BaseCustomView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView();
}
private void initView() {
View view = View.inflate(getContext(), getLayout(), this);
ButterKnife.bind(this, view);
initData(view);
}
//傳回 R.styleable.xxx styleable是自定義的一組declare-styleable
protected abstract int[] getStyleable();
//根據擷取到的屬性數組在代碼中初始化屬性值
protected abstract void initAttributes(TypedArray a);
//擷取自定義組合View的布局 R.layout.xxx
protected abstract int getLayout();
//初始化一些預設資料
protected abstract
一個簡單的例子
一般我們在應用中會有很多類似的View,比如設定界面的View都可以抽取出來獨立成章,簡化代碼友善維護下邊是一個簡單的例子,實作了一個比較通用的設定條目,XML中沒有設定相關資源的時候就隐藏相應内部View,否之顯示出來。一個空的效果顯示如下:
示例
public class SettingItemView extends BaseCustomView {
private String mLeftString;
private String mEndString;
private Drawable mLeftImage;
private Drawable mEndImage;
private int mLeftColor;
public SettingItemView(Context context) {
super(context);
}
public SettingItemView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SettingItemView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected int[] getStyleable() {
return R.styleable.SettingItemView;
}
@Override
protected void initAttributes(TypedArray a) {
mLeftString = a.getString(R.styleable.SettingItemView_textLeft);
mEndString = a.getString(R.styleable.SettingItemView_textEnd);
mLeftImage = a.getDrawable(R.styleable.SettingItemView_imageLeft);
mEndImage = a.getDrawable(R.styleable.SettingItemView_imageEnd);
mLeftColor = a.getColor(R.styleable.SettingItemView_colorLeft, getResources().getColor(R
.color.text_color));
}
@Override
protected int getLayout() {
return R.layout.ui_setting_item;
}
@Override
protected void initData(View view) {
setLeftText(mLeftString);
setEndText(mEndString);
setLeftImage(mLeftImage);
setEndImage(mEndImage);
tv_left.setTextColor(mLeftColor);
}
public void setLeftImage(Drawable image) {
iv_left.setImageDrawable(image);
}
public void setEndImage(Drawable image) {
if (image != null) {
iv_end.setVisibility(VISIBLE);
iv_end.setImageDrawable(image);
}
}
public void setLeftText(String text) {
tv_left.setText(text);
}
public void setEndText(String text) {
if (!TextUtils.isEmpty(text)) {
tv_end.setVisibility(VISIBLE);
tv_end.setText(text);
}
}
}
建立一個屬性檔案attrs.xml
添加以下自定義屬性(一些通用的可以抽取出來供其它使用):
關于styleable屬性類型可以搜尋一下有很多資料,就不展開說了
布局檔案如下:
android:id="@+id/rl_root"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="@dimen/item_height">
android:id="@+id/line"
android:layout_width="match_parent"
android:layout_height="0.1dp"
android:background="#ffd2d2d2"
android:layout_alignParentBottom="true"/>
android:layout_width="match_parent"
android:layout_height="@dimen/item_height"
android:orientation="horizontal"
android:layout_above="@id/line">
android:id="@+id/iv_left"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:scaleType="centerInside"
android:visibility="gone"/>
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center_vertical"
android:layout_weight="1"
android:visibility="gone"/>
android:id="@+id/iv_end"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:scaleType="centerInside"
android:visibility="gone"/>
android:id="@+id/tv_end"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:visibility="gone"/>
應用
在布局中應用剛才寫的組合View就像普通View一樣就好了,别忘了在跟布局中添加一行
xmlns:item="http://schemas.android.com/apk/res-auto"
這樣新屬性就可以以item的命名空間調用了
android:id="@+id/siv_test"
android:layout_width="match_parent"
android:layout_height="wrap_content"
item:imageLeft="@drawable/xxx"
item:textLeft="test"/>