今天学习了一下自定义组件,在android的开发中经常会有一个布局文件多次重复使用的情况,google提供了自定义组件的的功能可以让开发这根据自己的情况自己“DIY”。来是怎样实现的呢?
本文基于android studio开发,在eclipse中的自定义组件和android studio中有差异,在这里就不两个都介绍了。
定义一个自定义属性xml文件
在项目中创建一个attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MySettingItemView">
<attr name="tv_setting_title"
format="string"></attr>
<attr name="tv_setting_content"
format="string"></attr>
</declare-styleable>
</resources>
自定义命名空间
这段代码声明了两个自定义属性,tv_setting_title, ltv_setting_content, 一旦你定义自定义属性,你可以 在布局XML文件使用它们就像内置的属性。唯一的区别是你的自定义属性属于一个不同的名称空间。而不是属于http://schemas.android.com/apk/res/android名称空间,他们属于http://schemas.android.com/apk/res/(你的包名称)。举例来说如何使用属性为 MySettingItemView定义 :在eclipse中要将第二行改为 xmlns:自定义的命名空间="http://schemas.android.com/apk/res/<span style="color: rgb(37, 37, 37); font-family: 'Microsoft YaHei';font-size:18px; line-height: 19.2px;">(你的包名称)</span>"
在android studio中直接可以将项目包名改为res-auto<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:geowind="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
创建一个View类,获取自定义属性数据
本文以自定义LinearLayout为例,其实原理就是和android自带的组件一样,只是两个的命名空间不同
public MySettingItemView(Context context, AttributeSet attrs) {//attrs为自定义组件的属性
super(context, attrs);
mItem = View.inflate(context, R.layout.item_settingceneter,null);//布局中的条目布局
//获取attrs.xml中stylead中的attr
TypedArray a = context.getTheme().obtainStyledAttributes(
attrs,
R.styleable.MySettingItemView,
0, 0);
initView();
//将item加到自定义布局中
addView(mItem);
try {
<pre name="code" class="java"> //获取要title的名字
mTitle=mA.getString(R.styleable.MySettingItemView_tv_setting_title);
//获取tv_content的内容
mContent=mA.getString(R.styleable.MySettingItemView_tv_setting_content);
setTitle(mTitle);
mContents = mContent.split("-");//将checkbox的内容通过“-”分割成两部分存放在数组中
setContent(mContents[1]);
} finally { a.recycle();//回收资源 } }<pre name="code" class="html">private void initView() { mTv_title = (TextView) mItem.findViewById(R.id.tv_settingCenter_title); mTv_content = (TextView) mItem.findViewById(R.id.tv_settingCenter_content); mCb_check = (CheckBox) mItem.findViewById(R.id.cb_update); }
在自定义组件中使用自定义属性
<com.geowind.mysafegaurd.MySettingItemView
android:layout_width="match_parent"
android:layout_height="wrap_content"
geowind:tv_setting_title="更新设置"
geowind:tv_setting_content="已经开启-已经关闭"/>
<com.geowind.mysafegaurd.MySettingItemView
android:layout_width="match_parent"
android:layout_height="wrap_content"
geowind:tv_setting_title="更新设置2"
geowind:tv_setting_content="已经开启-已经关闭2"/>
<com.geowind.mysafegaurd.MySettingItemView
android:layout_width="match_parent"
android:layout_height="wrap_content"
geowind:tv_setting_title="更新设置3"
geowind:tv_setting_content="已经开启-已经关闭3"/>
<com.geowind.mysafegaurd.MySettingItemView
android:layout_width="match_parent"
android:layout_height="wrap_content"
geowind:tv_setting_title="更新设置4"
geowind:tv_setting_content="已经开启-已经关闭4"/>
如何给自定义组件设置点击事件
自定义组件的点击事件可以直接用组件父类原有的,但是这样做只能写一个监听事件,也就是说当要使用这一个自定义组件时,所用的点击事件都是一样的,这样做就将代码写死了,解决这一点就需要自定义组件的监听事件
1.将LinearLayout的clickable属性改为true,Linealayout的clickable默认是为false的
2.暴露自定义view类的属性接口,要想访问自定义组件的成员属性,必须写一个方法设置
private void setTitle(String title){
mTv_title.setText(title);
invalidate();
requestLayout();
}
private void setContent(String content){
mTv_content.setText(content);
invalidate();
requestLayout();
}<pre name="code" class="java"> //为外界提供访问cb_check的接口
public boolean isChecked(){
return mCb_check.isChecked();
}
public void setChecked(boolean ischecked){
if(ischecked){
setContent(mContents[0]);
mTv_content.setTextColor(Color.GREEN);
}else {
setContent(mContents[1]);
mTv_content.setTextColor(Color.RED);
}
mCb_check.setChecked(ischecked);
}
3.自定义点击事件
public void setItemClickListener(OnClickListener l){
mItem.setOnClickListener(l);
}
4.调用自定义组件的点击事件
到这里就可以去调用我们自己定义的点击事件了
setContentView(R.layout.settingcenter);
mMv_settingUpdate = (MySettingItemView) findViewById(R.id.mv_setting_update);
mMv_settingUpdate.setItemClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(mMv_settingUpdate.isChecked()){
SpTools.putBoolean(getApplicationContext(),MyConstant.AUTOUPDATE,false);
mMv_settingUpdate.setChecked(!mMv_settingUpdate.isChecked());
}else {
SpTools.putBoolean(getApplicationContext(), MyConstant.AUTOUPDATE,true);
mMv_settingUpdate.setChecked(!mMv_settingUpdate.isChecked());
}
}
});