自定义组合控件,组合模式

转载请注明出处,谢谢:http://blog.csdn.net/wei_chong_chong/article/details/50814617

这次我们来实现自定义组合控件

把已经有的控件组合在一起形成一个新的控件


三大步

1定义属性

2.实现我们的view

3.在layout中使用我们的view

1.定义属性,为我们组合控件定义属性

在values目录下建立属性文件my_attrs

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <declare-styleable name="TopBar">
        <attr name="title" 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>

2.创建自定义定义控件TopBar继承ViewGroup,从而组合一些需要的控件。为了简单起见这里直接继承RelativeLayout

package com.example.androidmoudletest;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.widget.Button;
import android.widget.RelativeLayout;
import android.widget.TextView;

public class TopBar extends RelativeLayout{

	//声明需要用到的控件
	private Button leftButton,rightButton;
	private TextView tvTitle;

	//声明控件用到的属性,即在attrs文件中自定义的属性
	private int mleftTextColor;
	private Drawable mleftBackground;
	private String mleftText;

	private int mrightTextColor;
	private Drawable mrightBackground;
	private String mrightText;

	private float mtitleTextSize;
	private int mtitleTextColor;
	private String mtitle;

	private topbarClickListener listener;

	//定义一个接口
	public interface topbarClickListener{
		public void leftClick();
		public void rightClick();
	}
	//暴露一个方法给调用者来注册接口回调,通过接口获得回调者对接口方法的实现
	public void setOnTopbarClickListener(topbarClickListener listener){
		this.listener = listener;
	}
	private LayoutParams mleftParams,mrightParams,mtitleParams;
	@SuppressLint("NewApi") public TopBar(Context context, AttributeSet attrs) {
		super(context, attrs);
		// TODO Auto-generated constructor stub
		TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.TopBar);
		/*系统提供了TypedArray 这样的数据结构来获取自定义属性集,后面引用的styleable的
		TopBar,通过对象ta的方法获取这些定义的属性值

		 */

		//从TypedArray中获取对应的值来为要设置的属性赋值
		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);

		mtitle = ta.getString(R.styleable.TopBar_title);
		mtitleTextColor = ta.getColor(R.styleable.TopBar_titleTextColor, 0);
		mtitleTextSize = ta.getDimension(R.styleable.TopBar_titleTextSize, 10);
		//获取完TypeArray值后,一定要回收资源,避免重新创建时出错
		ta.recycle();

		leftButton = new Button(context);
		rightButton = new Button(context);
		tvTitle = new TextView(context);

		//为创建的组件元素赋值(值就来源于我们在xml中设置的属性值)
		leftButton.setBackground(mleftBackground);
		leftButton.setTextColor(mleftTextColor);
		leftButton.setText(mleftText);

		rightButton.setBackground(mrightBackground);
		rightButton.setTextColor(mrightTextColor);
		rightButton.setText(mrightText);

		tvTitle.setText(mtitle);
		tvTitle.setTextColor(mtitleTextColor);
		tvTitle.setTextSize(mtitleTextSize);

		tvTitle.setGravity(Gravity.CENTER);//使用系统定义好的属性值
		//给viewgroup设置背景颜色
		setBackgroundColor(0xfff25663);

		//把控件放到布局里面需要一个重要的属性
		mleftParams = new LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.MATCH_PARENT);
		mleftParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT, TRUE);
		addView(leftButton,mleftParams);

		mrightParams = new LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.MATCH_PARENT);
		mrightParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, TRUE);
		addView(rightButton,mrightParams);

		mtitleParams = new LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.MATCH_PARENT);
		mtitleParams.addRule(RelativeLayout.CENTER_IN_PARENT, TRUE);
		addView(tvTitle,mtitleParams);

		leftButton.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				listener.leftClick();

			}
		});

		rightButton.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				listener.rightClick();
			}
		} );

	}
	//设置左边按钮是否显示
	public void setLeftIsVisiable(boolean flag){
		if(flag){
			leftButton.setVisibility(View.VISIBLE);
		}
		else {
			leftButton.setVisibility(View.GONE);
		}
	}

}



下面来总结一下,1.我们继承RelativeLayout,重写构造方法,因为这里我们自定义属性所以2.重写带attrs参数的构造函数

然后3.获取自定义属性的值到TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.TopBar);第二个参数是我们在定义的组合控件的名,与<declare-styleable name="TopBar">这个一致,第一个参数使用的是构造方法里面的参数

4.接着通过TypeArray对象的方法获取这些定义的属性值,getColor(R.styleable.TopBar_titleTextColor, 0);(这里获取的是我们在layout中设置的值)

5.将我们获取的值赋值给创建的组件元素,值就来源于我们在xml中设置的属性值)

leftButton.setBackground(mleftBackground);

6.我们以LayoutParams的形式把控件添加到ViewGroup中


3.引用我们自定义的控件

像引用系统控件一样(xmlns:android="http://schemas.android.com/apk/res/android"),

 在根节点导入我们的包xmlns:myview="http://schemas.android.com/apk/res/com.example.androidmoudletest"

com.example.androidmoudletest这个是我们创建的控件的包名注意这个名字必须配置文件里面 package="com.example.androidmoudletest"这个包的名字,而不是创建TopBar。java上面显示的包名(如果我们在新建包下创建TopBar的就会发现在两个包名不一样)

下面就可以像系统控件一样(  android:layout_width="match_parent")使用我们自己创建的组合控件了

使用系统控件android:layout_width="match_parent“

使我们的控件 myview:leftTextColor="#ffffff"

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:myview="http://schemas.android.com/apk/res/com.example.androidmoudletest"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.androidmoudletest.MoudleActivity" >

    <com.example.androidmoudletest.TopBar
        android:id="@+id/topbar"
        android:layout_width="fill_parent"
        android:layout_height="40dp"
        myview:leftBackground="@drawable/ic_launcher"
        myview:leftText="left"
        myview:leftTextColor="#ffffff"
        myview:rightBackground="@drawable/ic_launcher"
        myview:rightText="right"
        myview:rightTextColor="#ffffff"
        myview:title="title"
        myview:titleTextColor="#123412"
        myview:titleTextSize="10sp" >
    </com.example.androidmoudletest.TopBar>

</RelativeLayout>



继续对控件进行完善

4.添加点击事件

使用接口回调思想,

定义一个左右按钮的点击接口,并创建两个方法

public interface topbarClickListener{
		public void leftClick();
		public void rightClick();
	}

暴露接口给调用者:

在模板方法中为左右按钮增加点击事件,但不去实现具体的逻辑,而是调用接口中相应的点击方法

public void setOnTopbarClickListener(topbarClickListener listener){
		this.listener = listener;
	}

5.实现接口回调


在调用者的代码中,调用者需要实现这样一个接口,并完成接口中的方法,确定具体的实现逻辑,将接口的对象传递进去,从而完成回调,通常情况使用匿名内部类的形式来实现接口中的方法

在ModelActivity

TopBar topbar = (TopBar) findViewById(R.id.topbar);
		topbar.setOnTopbarClickListener(new topbarClickListener() {

			@Override
			public void rightClick() {
				// TODO Auto-generated method stub
				Toast.makeText(MoudleActivity.this, "left", 1).show();
			}

			@Override
			public void leftClick() {
				// TODO Auto-generated method stub
				Toast.makeText(MoudleActivity.this, "right", 1).show();
			}
		});

暴露方法给调用者对控件进行动态设计

在创建自定义TopBar时对外提供该方法

例如加入设置左边按钮是否显示的方法


//设置左边按钮是否显示
	public void setLeftIsVisiable(boolean flag){
		if(flag){
			leftButton.setVisibility(View.VISIBLE);
		}
		else {
			leftButton.setVisibility(View.GONE);
		}
	}

在ModelActivity中调用该方法对TopBar进行动态控制:

	topbar.setLeftIsVisiable(false);


ModelActivity中:

package com.example.androidmoudletest;

import com.example.androidmoudletest.TopBar.topbarClickListener;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;


public class MoudleActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_moudle);
		TopBar topbar = (TopBar) findViewById(R.id.topbar);
		topbar.setOnTopbarClickListener(new topbarClickListener() {

			@Override
			public void rightClick() {
				// TODO Auto-generated method stub
				Toast.makeText(MoudleActivity.this, "left", 1).show();
			}

			@Override
			public void leftClick() {
				// TODO Auto-generated method stub
				Toast.makeText(MoudleActivity.this, "right", 1).show();
			}
		});
		topbar.setLeftIsVisiable(false);
	}



}




你可能感兴趣的:(android)