转载请注明出处,谢谢: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>
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); } } }
然后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; }
在调用者的代码中,调用者需要实现这样一个接口,并完成接口中的方法,确定具体的实现逻辑,将接口的对象传递进去,从而完成回调,通常情况使用匿名内部类的形式来实现接口中的方法
在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); } }