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 }

示例结果:

    

如果有什么错误,或者我理解错误或不当的,恳请大家纠正,谢谢!嘻嘻嘻~

 

posted on 2017-03-07 17:04  艹艹哒丶  阅读(239)  评论(0编辑  收藏  举报

导航