自定义复合控件并进行封装

来源:互联网 发布:mac打不开文件夹 编辑:程序博客网 时间:2024/05/22 09:50

首先这个控件的布局很简单(中间为标题文字,左右各有一个按钮)




但是这个类似的布局很常用,所以就想把它封装起来,通过这个封装来学习以下三点

1.创建了一个常用的复合控件,标题栏

2.为该控件添加自定义的属性值

3.为该控件添加自定义的接口


首先我们要先想好该控件的自定义属性

在res/values下创建  attrs.xml文件 写入以下代码

<?xml version="1.0" encoding="utf-8"?><resources>    <declare-styleable name="TopBar">        <attr name="titleText" format="string"/>        <attr name="titleTextSize" format="dimension"/>        <attr name="titleTextColor" format="color"/>        <attr name="leftTextColor" format="color"/>        <attr name="leftBackground" format="reference|color"/>        <attr name="leftText" format="string"/>        <attr name="rightTextColor" format="color"/>        <attr name="rightBackground" format="reference|color"/>        <attr name="rightText" format="string"/>    </declare-styleable></resources>
我们在<declare-styleable name="自定义控件名">中声明是哪个控件的自定义属性,这里我命名为TopBar

<attr  name="属性名" format="属性格式">

format可以有以下属性

1.reference: 某一资源的id

2.color : 颜色值

3.boolean: 布尔值

4.dimension: 尺寸值

5.float: 浮点值

6.integer:整形值

7.sting: 字符串

8.fraction: 百分数

9.enum:枚举值

10.flag:位或运算


至于我定义的属性用途,从名字就可以直接的看出来,不再赘述


然后就是关键的TopBar这个类的代码了,我们用TopBar继承RelativeLayout

package com.example.topbar;import android.content.Context;import android.content.res.TypedArray;import android.graphics.drawable.Drawable;import android.text.Layout;import android.util.AttributeSet;import android.util.Log;import android.view.Gravity;import android.view.LayoutInflater;import android.view.View;import android.widget.Button;import android.widget.RelativeLayout;import android.widget.TextView;import android.widget.RelativeLayout.LayoutParams;import android.view.View.OnClickListener;public class TopBar extends RelativeLayout implements OnClickListener{//定义与attrs.xml中的自定义属性对应的属性private int mLeftTextColor;private Drawable mLeftBackground;private String mLeftText;private int mRightTextColor;private Drawable mRightBackground;private String mRightText;private String mTitleText;private int mTitleTextColor;private float mTitleTextSize;/* * 定义我们要显示的布局 * 一个显示标题的TextView 两个分居两侧的标题 */private Button mLeftButton;private Button mRightButton;private TextView mTitleView;//用于控制控件的布局属性private LayoutParams mLeftParams;private LayoutParams mRightParams;private LayoutParams mTitleParams;//我们给button赋予一个id,便于在事件监听时候对应到相应buttonprivate final int mLeftButtonId = 1;private final int mRightButtonId = 2;//下面我们在这个类中定义的一个公共接口private OnTopBarClickListener onTopBarClickListener;//构造函数,attrs就是布局文件传过来的对应的属性public TopBar(Context context, AttributeSet attrs) {super(context, attrs);initAttrs(context,attrs);initView(context);}//将attrs.xml中定义的属性值存入typedArray中private void initAttrs(Context context, AttributeSet attrs){TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.TopBar);mLeftTextColor = ta.getColor(R.styleable.TopBar_leftTextColor,0);mLeftBackground = ta.getDrawable(R.styleable.TopBar_leftBackground);mLeftText = ta.getString(R.styleable.TopBar_leftText);mRightTextColor = ta.getColor(R.styleable.TopBar_rightTextColor,0);mRightBackground = ta.getDrawable(R.styleable.TopBar_rightBackground);mRightText = ta.getString(R.styleable.TopBar_rightText);mTitleTextSize = ta.getDimension(R.styleable.TopBar_titleTextSize, 10);mTitleTextColor =ta.getColor(R.styleable.TopBar_titleTextColor, 0);mTitleText = ta.getString(R.styleable.TopBar_titleText);ta.recycle();}//初始化布局中的控件,并将属性分配给他们,以及给他们注册监听事件private void initView(Context context){mLeftButton = new Button(context);mRightButton = new Button(context);mTitleView = new TextView(context);mLeftButton.setTextColor(mLeftTextColor);mLeftButton.setBackground(mLeftBackground);mLeftButton.setText(mLeftText);mRightButton.setTextColor(mRightTextColor);mRightButton.setBackground(mRightBackground);mRightButton.setText(mRightText);mTitleView.setText(mTitleText);mTitleView.setTextColor(mTitleTextColor);mTitleView.setTextSize(mTitleTextSize);mTitleView.setGravity(Gravity.CENTER);mLeftButton.setId(mLeftButtonId);mLeftParams = new LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);mLeftParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT,TRUE);mLeftParams.addRule(RelativeLayout.CENTER_VERTICAL);addView(mLeftButton,mLeftParams);mRightButton.setId(mRightButtonId);mRightParams = new  LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);mRightParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT,TRUE);mRightParams.addRule(RelativeLayout.CENTER_VERTICAL,TRUE);addView(mRightButton,mRightParams);mTitleParams = new LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);mTitleParams.addRule(RelativeLayout.CENTER_IN_PARENT,TRUE);addView(mTitleView,mTitleParams);mLeftButton.setOnClickListener(this);mRightButton.setOnClickListener(this);}/** *  * @param id  id=0标识leftButton  else 标识着rightButton * @param flag flag = 0 意味着不显示该id控件 * button默认为显示 */public void setButtonVisable(int id, boolean flag){if(flag){if(id == 0){mLeftButton.setVisibility(View.VISIBLE);}else{mRightButton.setVisibility(View.VISIBLE);}}else{if(id == 0){mLeftButton.setVisibility(View.GONE);}else{mRightButton.setVisibility(View.GONE);}}}//重写借口的onclick方法,去调用自定义的接口的方法@Overridepublic void onClick(View v) {switch(v.getId()){case mLeftButtonId:onTopBarClickListener.leftClick();break;case mRightButtonId:onTopBarClickListener.rightClick();break;}}//为外部增加一个方法去添加接口的监听事件public void setOnTopBarClickListener(OnTopBarClickListener onTopBarClickListener){this.onTopBarClickListener = onTopBarClickListener;}//自定义一个接口,供使用者为两个button添加事件public interface OnTopBarClickListener{void leftClick();void rightClick();}}

然后就是我们定义一个布局,去引用这个自定义控件

activity_topbar_test.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    tools:context="com.example.topbar.TopBarTest"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical"    >    <com.example.topbar.TopBar    xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:custom="http://schemas.android.com/apk/res-auto"    android:id="@+id/topBar"    android:layout_width="match_parent"    android:layout_height="80dp"    android:background="#ffccff"    custom:leftText="Back"    custom:leftTextColor="#000000"    custom:leftBackground="#ff0000"    custom:rightText="More"    custom:rightTextColor="#000000"    custom:rightBackground="#ff0000"    custom:titleText="自定义标题"    custom:titleTextColor="#123412"    custom:titleTextSize="12sp"    /></LinearLayout>

这个地方我们要注意一下,

xmlns:android="http://schemas.android.com/apk/res/android"

是声明android的命名空间,这样我们就可以通过android:来引用其中的属性了

xmlns:custom="http://schemas.android.com/apk/res-auto"

是我们为自定义的属性声明的命名空间,名字为custom

自定义属性的位置是 http://schemas.android.com/apk/res-auto 

我们也可以写为 http://schema.android.com/apk/res/包路径

包路径指的是你在Manifest中定义的项目的包路径,而不是说TopBar这个类的包路径

总之就是为了找到我们这个项目,然后正确的识别values 的 attrs.xml


最后就是写一个activity去引用这个布局,然后测试我们是否成功啦

TopBarTestActivity.java

package com.example.topbar;import custom.TopBar;import custom.TopBar.OnTopBarClickListener;import android.support.v7.app.ActionBarActivity;import android.os.Bundle;import android.view.Menu;import android.view.MenuItem;import android.view.Window;import android.widget.Toast;public class TopBarTestActivity extends ActionBarActivity {TopBar topBar;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        //去掉系统标题栏        this.requestWindowFeature(Window.FEATURE_NO_TITLE);        setContentView(R.layout.activity_topbar_test);                topBar = (TopBar)findViewById(R.id.topBar);        //为topBar中的按钮注册监听事件        topBar.setOnTopBarClickListener(new OnTopBarClickListener(){@Overridepublic void leftClick() {Toast.makeText(TopBarTestActivity.this, "点击了leftButton", Toast.LENGTH_SHORT).show();}@Overridepublic void rightClick() {Toast.makeText(TopBarTestActivity.this, "点击了rightButton", Toast.LENGTH_SHORT).show();}                });        /*         * 可以用setButtonVisable(id,flag)来控制是否显示相应按钮         * 添加以下代码,两个按钮都被隐藏了         * topBar.setButtonVisable(0, false);         * topBar.setButtonVisable(1, false);         */            }}

好啦,运行可以看到我开始时候放的图片了!

注释都很详尽,我就不再解释了,有问题可以留言讨论~


这只是一个简单的复合控件,但是我们可以通过这个学习到如何自定义一个复合控件,与为他定制属性和一些接口,方法。

由简单到复杂,下一次,我们可以自定义一个SlidingMenu 然后把自定义属性也定制到里面~


github地址 Wizwizard/TopBar




2 0
原创粉丝点击