概念
自定义组合View是指android给我们提供的View本身功能不够用,但是可以把几个View粘合起来形成一个独立的类,对外部提供统一的职能,内部View之间的逻辑实现可以隐藏,使之整体看起来就像是一个新的View。另外,还可以通过自定义属性功能,使得我们的组合View直接在XML布局文件中方便的使用
实现
定义一个基类,之后的组合View都继承自它
public abstract class BaseCustomView extends RelativeLayout {
/**
* 自定义view属性命名空间
*/
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);
}
/**
* 当没有设置图片资源时隐藏之
*
* @param 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);
}
/**
* 当没有设置文字时隐藏之
*
* @param text
*/
public void setEndText(String text) {
if (!TextUtils.isEmpty(text)) {
tv_end.setVisibility(VISIBLE);
tv_end.setText(text);
}
}
}
- 新建一个属性文件attrs.xml
添加以下自定义属性(一些通用的可以抽取出来供其它使用):
<!--common-->
<attr name="textLeft" format="string"/>
<attr name="textEnd" format="string"/>
<attr name="imageLeft" format="reference"/>
<attr name="imageEnd" format="reference"/>
<!--SettingItemView-->
<declare-styleable name="SettingItemView">
<attr name="textLeft"/>
<attr name="textEnd"/>
<attr name="imageLeft"/>
<attr name="imageEnd"/>
<attr name="colorLeft" format="color"/>
</declare-styleable>
关于styleable属性类型可以搜索一下有很多资料,就不展开说了
布局文件如下:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
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">
<View
android:id="@+id/line"
android:layout_width="match_parent"
android:layout_height="0.1dp"
android:background="#ffd2d2d2"
android:layout_alignParentBottom="true"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="@dimen/item_height"
android:orientation="horizontal"
android:layout_above="@id/line">
<ImageView
android:id="@+id/iv_left"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:scaleType="centerInside"
android:visibility="gone"/>
<TextView
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"/>
<ImageView
android:id="@+id/iv_end"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:scaleType="centerInside"
android:visibility="gone"/>
<TextView
android:id="@+id/tv_end"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:visibility="gone"/>
</LinearLayout>
</RelativeLayout>
- 应用
在布局中应用刚才写的组合View就像普通View一样就好了,别忘了在跟布局中添加一行
xmlns:item="http://schemas.android.com/apk/res-auto"
这样新属性就可以以item的命名空间调用了
<所在包名.SettingItemView
android:id="@+id/siv_test"
android:layout_width="match_parent"
android:layout_height="wrap_content"
item:imageLeft="@drawable/xxx"
item:textLeft="test"/>
迁移自CSDN
2015年12月12日 11:02:33
http://blog.csdn.net/u013262051/article/details/50273451