关于自定义组合控件,我相信大家在百度、谷歌的时候,会出来一大把,可是,我们百度出来的自定义组合控件,能讲出其中原理的,少之又少,在看这篇文章的你是否想到了我要说什么呢?对,你想的没错,我就是要讲讲自定义组合控件的原理.
自定义组合控件的第一步当然就是要去继承了,并且实现他们的构造方法:
public class SettingView extends RelativeLayout {
private TextView tv_content,tv_title;
public SettingView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
System.out.println("3个参数");
}
public SettingView(Context context, AttributeSet attrs) {
super(context, attrs);
initView( context);
System.out.println("2个参数");
}
public SettingView(Context context) {
super(context);
System.out.println("1个参数");
}
}
其次,你需要去组合一些控件了,在布局里面放置一些控件,比如:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="80dip" >
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="我是设置文本1"
android:textSize="25dip" />
<TextView
android:id="@+id/tv_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/tv_title"
android:padding="5dip"
android:textColor="#88000000"
android:text="我是描述文本1"
android:textSize="15dip" />
<View
android:layout_width="match_parent"
android:layout_height="1dip"
android:layout_alignParentBottom="true"
android:background="@drawable/qb_tenpay_list_line" />
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true" />
</RelativeLayout>
这样,一个自定义的组合控件就好了,下面呢,我们要讲解一下给自定义的组合控件加上属性,就跟那个TextView控件一样,比如说,当我们给TextView添加文本属性的时候,你会看到,你给两个相同的控件添加不同的文字的时候,他们的文字是不一样的,但是到这步之前,我们的自定义组合控件的是没法给其添加属性的,因为,它压根就没有这个能力,所以就不能做这个事情,那怎么办呢?不过我们也可以办到,如果在、不能这样的话,我们自定义什么组合控件啊,,好了,我们接下来去给我们自定义的组件增加我们想要的属性呗,好,回到我们刚才布局的XML文件中,我们看看布局页面的声明,在这张图片中你可以看到我自己声明了一个命名空间,可是我们自己所写的属性资源在那里呢?其实,我们自己声明的,就是在我们当前的应用,我们可以用我们的包名来声明资源的所在地,OK
但是我们为什么要这样做呢?这么做是有原因的,我们看到系统自带的控件,如TextView控件,我们为什么可以给他增加属性呢?这是因为,他们把属性全部定义在android.jar包下,不信的话,你可以在你们放置的SDK目录下找到一个叫attrs的xml文件,这是我的SDK路径:E:\android-sdk-windows\platforms\android-18\data\res\values,在这个values文件夹下可以看到一个叫attrs.xml文件,这里定义了TextView、EditText等等这些控件的属性声明,好了,看了这些,你是不是有些感触呢?这样我们就可以依葫芦画瓢的方式,来给我们自己定义的组合控件生成属性了.当我们完成这些自定义的属性之后,我们再去看看R.java文件,我们可以看到生成了一个attr的内部类和一个styleable的内部类,在后者这个内部类里面我们可以看到有个数组,这个数组的名字就是你刚才定义的属性时,给他起的一个名字,这样说可能很抽象,放心,待会我会提供一个图片让大家看看.
通过以上步骤,我们已经完成了自定义组合控件的三分之二了,为什么说是只完成了其中的三分之二呢?因为我们还有事情没有做,那就是我们所定义的这些属性,还没有正式生效,要让他生效,我们必须通过code来实现,这就是我们刚才为什么说只完成了其三分之二,好了。下面看看怎么通过代码实现:
public class SettingView extends RelativeLayout {
private TextView tv_content,tv_title;
public SettingView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initView( context);
System.out.println("3个参数");
}
public SettingView(Context context, AttributeSet attrs) {
super(context, attrs);
initView( context);
System.out.println("2个参数");
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.SettingView);//让属性集与自定义的属性的数组建立一个对应关系
String content = ta.getString(R.styleable.SettingView_content);
String title = ta.getString(R.styleable.SettingView_title);
tv_content.setText(content);
tv_title.setText(title);
ta.recycle();//这个必须调用
}
public SettingView(Context context) {
super(context);
initView( context);
System.out.println("1个参数");
}
private void initView(Context context) {
View view = View.inflate(context, R.layout.ui_settingview, null);
this.addView(view);
tv_content = (TextView) view.findViewById(R.id.tv_content);
tv_title = (TextView) view.findViewById(R.id.tv_title);
}
}
那么刚才我们继承所实现的三个构造方法,他们执行那个呢?其实只要你们定一些log信息,然后去执行,你们就知道了,它们默认之行的是带两个参数的构造方法,那么其他的两构造函数什么时候执行呢?有三个参数的是当你该控件添加了一个样式的时候,他才会去执行的,一个参数的则是在你new的时候会调用,好了,这下你清楚了么?
如果还有不清楚的,在这里我把自定义组合控件的步骤图给大家,让大家参考参考一下:
下面贴上全部的代码:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="80dip" >
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="我是设置文本1"
android:textSize="25dip" />
<TextView
android:id="@+id/tv_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/tv_title"
android:padding="5dip"
android:textColor="#88000000"
android:text="我是描述文本1"
android:textSize="15dip" />
<View
android:layout_width="match_parent"
android:layout_height="1dip"
android:layout_alignParentBottom="true"
android:background="@drawable/qb_tenpay_list_line" />
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true" />
</RelativeLayout>
attrs文件:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="SettingView">
<attr name="content" format="string" />
<attr name="title" format="string" />
</declare-styleable>
</resources>
放置自定义的组合布局文件:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:haibo="http://schemas.android.com/apk/res/com.haibo.example"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity" >
<com.haibo.example.SettingView
android:id="@+id/sv1"
android:layout_width="fill_parent"
android:layout_height="80dip"
android:background="#D73366FF"
haibo:content="哈哈"
haibo:title="嘻嘻" >
</com.haibo.example.SettingView>
<com.haibo.example.SettingView
android:id="@+id/sv2"
android:layout_width="fill_parent"
android:layout_height="80dip"
haibo:content="哈哈"
haibo:title="嘻嘻" >
</com.haibo.example.SettingView>
<com.haibo.example.SettingView
android:id="@+id/sv3"
android:layout_width="fill_parent"
android:layout_height="80dip"
haibo:content="哈哈"
haibo:title="嘻嘻" >
</com.haibo.example.SettingView>
<com.haibo.example.SettingView
android:id="@+id/sv4"
android:layout_width="fill_parent"
android:layout_height="80dip"
haibo:content="哈哈"
haibo:title="嘻嘻" >
</com.haibo.example.SettingView>
<com.haibo.example.SettingView
android:id="@+id/sv5"
android:layout_width="fill_parent"
android:layout_height="80dip"
haibo:content="哈哈"
haibo:title="嘻嘻" >
</com.haibo.example.SettingView>
</LinearLayout>
代码:
public class SettingView extends RelativeLayout {
private TextView tv_content,tv_title;
public SettingView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initView( context);
System.out.println("3个参数");
}
public SettingView(Context context, AttributeSet attrs) {
super(context, attrs);
initView( context);
System.out.println("2个参数");
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.SettingView);//让属性集与自定义的属性的数组建立一个对应关系
String content = ta.getString(R.styleable.SettingView_content);
String title = ta.getString(R.styleable.SettingView_title);
tv_content.setText(content);
tv_title.setText(title);
ta.recycle();
}
public SettingView(Context context) {
super(context);
initView( context);
System.out.println("1个参数");
}
private void initView(Context context) {
View view = View.inflate(context, R.layout.ui_settingview, null);
this.addView(view);
tv_content = (TextView) view.findViewById(R.id.tv_content);
tv_title = (TextView) view.findViewById(R.id.tv_title);
}
}
开启的activity:
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
效果图: