转载请注明出处,谢谢: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
二构造方法
《1.一个参数的context ,自己new 对象的时候使用,传入context上下文对象就行
《2.两个参数的,context,attr 布局文件中声明(没有自定义属性的)
《3.三个参数,context,attr,defStyle(有自定义的属性)
三个构造方法都要写,缺一不可,不然自定义的属性不起作用
然后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);
}
}