Android自定义UI控件(高级版)
上一篇已经简单的说了一下这种方法的优先,就是操作十分灵活,适合用来做模板。
我们知道,系统的控件是通过继承groupView对象来构建的,通过编写attrs.xml文件来设置控件需要的属性
我们可以模仿系统构建控件的做法,来自定义控件。
这样做出来的控件就可以像系统自带的控件一样,可以在布局文件中设置需要的属性,例如android:text=“lwj”
所以第一步,我们得编写一个attrs.xml文件来定义你要自定义控件的属性:
在res.values文件夹下新建一个xml文件,我这里的名字叫atts
自定义属性需要在<declare-styleabel></declare-styleabel>里面编写,格式为<attr name= "属性名" format="属性的变量类型"/>
1 <?xml version="1.0" encoding="utf-8"?>
2 <resources>
3 <declare-styleable name ="Topbar">
4 <attr name="title" format="string"/>
5 <attr name="titleTextSize" format="dimension"/>
6 <attr name="titleTextColor" format="color"/>
7 <attr name="LeftTextColor" format="color"/>
8 <attr name="LeftBackground" format="reference|color"/>
9 <attr name="LeftText" format="string"/>
10 <attr name="RightTextColor" format="color"/>
11 <attr name="RightBackground" format="reference|color"/>
12 <attr name="RightText" format="string"/>
13 </declare-styleable>
14 </resources>
定义完后,我们像上一个方法一样,创建一个Topbar类继承布局对象
atts文件里面的资源可以通过R.styleabe获取
1 public class Topbar extends RelativeLayout{
2 private Button leftBt,rightBt;
3 private TextView text;
4
5 private String leftText;
6 private int leftColor;
7 private Drawable leftBackground;
8
9 private String rightText;
10 private int rightColor;
11 private Drawable rightBackground;
12
13 private int titleTextColor;
14 private String titleText;
15 /*
16 * 模仿按钮的点击回调事件来实现二次回调。
17 */
18 private topbarOnClickListener listener;//自定义按钮会调接口对象
19 //按钮回调接口
20 public interface topbarOnClickListener{
21 public void leftClick(); //左按钮的点击事件
22 public void rightClick();//右按钮的点击事件
23 }
24 public void setOnTopbarClickListener(topbarOnClickListener listener){
25 this.listener = listener;
26 }
27
28 /*
29 * 通过TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.Topbar);
30 * 把在布局文件中R.styleable.Topbar控件中定义的属性按照自定义atts.xml文件中的属性格式保存在ta中
31 * 然后把ta冲的属性取出,设置给实例化后自定义控件中的各个子控件。
32 * 然后子控件通过LayoutParams和RelativeLayout.addRile得到自己在自定义控件中的大小和位置
33 * 将各个控件用addView方法把子控件添加到Topbar控件中。
34 * 这样做可以省去再去创建一个xml文件然后码布局文件的过程
35 * 而且属性是用自定义的,调用这个控件会很方便。
36 */
37 private LayoutParams leftParms,rightParms,titleParms;//子控件的布局属性
38 public Topbar(final Context context, AttributeSet attrs){
39 super(context,attrs);
40 //用来获取保存自定义XML文件中的属性值的一个数组
41 TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.Topbar);
42 //从ta中取出属性数据
43 leftText = ta.getString(R.styleable.Topbar_LeftText);
44 leftColor = ta.getColor(R.styleable.Topbar_LeftTextColor, 0);
45 leftBackground = ta.getDrawable(R.styleable.Topbar_LeftBackground);
46
47 rightText = ta.getString(R.styleable.Topbar_RightText);
48 rightColor = ta.getColor(R.styleable.Topbar_RightTextColor, 0);
49 rightBackground = ta.getDrawable(R.styleable.Topbar_RightBackground);
50
51 titleTextColor = ta.getColor(R.styleable.Topbar_titleTextColor, 0);
52 titleText = ta.getString(R.styleable.Topbar_title);
53 //ta回收,避免浪费资源
54 ta.recycle();
55 //实例化控件
56 leftBt = new Button(context);
57 rightBt = new Button(context);
58 text = new TextView(context);
59 //设置控件属性
60 leftBt.setTextColor(leftColor);
61 leftBt.setBackground(leftBackground);
62 leftBt.setText(leftText);
63
64 rightBt.setTextColor(rightColor);
65 rightBt.setBackground(rightBackground);
66 rightBt.setText(rightText);
67
68 text.setTextColor(titleTextColor);
69 text.setText(titleText);
70 text.setGravity(Gravity.CENTER);
71 setBackgroundColor(Color.BLACK);
72 /*
73 * 实例化布局LayoutParams(宽属性,高属性);
74 * 用RelativeLayout.addRile方法设置控件的位置
75 * 将各个控件用addView方法把子控件添加到Topbar控件中。。
76 */
77 leftParms = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT);
78 leftParms.addRule(RelativeLayout.ALIGN_PARENT_LEFT,TRUE); //居左对齐
79 addView(leftBt,leftParms);
80 rightParms = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT);
81 rightParms.addRule(RelativeLayout.ALIGN_PARENT_RIGHT,TRUE); //居右对齐
82 addView(rightBt,rightParms);
83 titleParms = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.MATCH_PARENT);
84 titleParms.addRule(RelativeLayout.CENTER_IN_PARENT,TRUE); //居中
85 addView(text,titleParms);
86 /*
87 * 设置点击事件
88 * 通过自定义的回调方法,把按钮被点击事情的事情传到另一个对象中
89 * 具体的响应事件由外部设定,从而把Topbar封装起来
90 */
91 leftBt.setOnClickListener(new OnClickListener(){
92 @Override
93 public void onClick(View arg0) {
94 listener.leftClick();
95 }
96 });
97 rightBt.setOnClickListener(new OnClickListener(){
98 @Override
99 public void onClick(View arg0) {
100 listener.rightClick();
101 }
102 });
103 }
104 }
然后我们就可以在我们需要调用该控件的布局文件中用了
就像平常的控件一样用
但是得注意控件名要由完整的包名,
还有一个地方要注意的这里的属性是topbar:调用的,那是因为我是这样定义的xmlns:topbar="http://schemas.android.com/apk/res/com.example.z_diy"
这也是模仿系统定义控件实现的,我们平常用的android:也是因为xmlns:android="http://schemas.android.com/apk/res/android"中有系统控件的属性
1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
2 xmlns:tools="http://schemas.android.com/tools"
3 xmlns:topbar="http://schemas.android.com/apk/res/com.example.z_diy"
4 android:layout_width="match_parent"
5 android:layout_height="match_parent"
6 tools:context="${relativePackage}.${activityClass}" >
7
8 <com.example.z_diy.Topbar
9 android:id="@+id/topbar"
10 android:layout_width="match_parent"
11 android:layout_height="50dp"
12 topbar:title ="这是一个标题"
13 topbar:titleTextColor ="#fff"
14 topbar:LeftTextColor ="#fff"
15 topbar:LeftBackground ="#000"
16 topbar:LeftText ="退出"
17 topbar:RightTextColor ="#fff"
18 topbar:RightBackground ="#000"
19 topbar:RightText ="菜单"
20 />
21
22 </RelativeLayout>
然后我们其实还没完成,别忘了,我们的响应事件
我们在Topbar中定义的响应事件也是模仿系统的,不需要管具体的实现,只需要知道他被响应的,告诉要实现该响应的对象执行就可以了
1 public class MainActivity extends Activity {
2
3 @Override
4 protected void onCreate(Bundle savedInstanceState) {
5 super.onCreate(savedInstanceState);
6 requestWindowFeature(Window.FEATURE_NO_TITLE);
7 setContentView(R.layout.activity_main);
8 //实例化Topbar
9 Topbar topbar = (Topbar)findViewById(R.id.topbar);
10 topbar.setOnTopbarClickListener(new Topbar.topbarOnClickListener() {
11 @Override
12 public void rightClick() {
13 Toast toast = Toast.makeText(MainActivity.this, "菜单", Toast.LENGTH_SHORT);
14 toast.show();
15 }
16 @Override
17 public void leftClick() {
18 Toast toast = Toast.makeText(MainActivity.this, "退出", Toast.LENGTH_SHORT);
19 toast.show();
20 }
21 });
22 }
23 }
示例结果: