Android自定义UI控件(高级版)
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 }
示例结果:
如果有什么错误,或者我理解错误或不当的,恳请大家纠正,谢谢!嘻嘻嘻~