前面已学习了两种自定义控件的实现,还没学习的同学可以学习下,学习了的同学也要去温习下,一定要自己完全的掌握了,再继续学习,贪多嚼不烂可不是好的学习方法,我们争取学习了一种技术就会一种技术,而且不光看了就算了,最好的方法就是看完我自己再练习下,再扩展下,在原来的基础上在添加一些东西,比如,增加一些功能实现等等。效果图:
今天我们打算学习下另外一种自定义控件,就是创建可重复使用的组合控件,那么问题来了:
- 什么是可重复使用?
就是在应用中,可以在多个地方共同使用一套代码。这样不仅能减少我们的工作量,而且还能保持应用风格的一致,这种应用最多最直接的体现就是统一风格样式的标题栏。
- 那什么又是组合控件呢?
组合控件,顾名思义就是多个控件组合在一起,相互协作共同完成某些特定的功能。
下面我们就针对app应用中风格统一的标题栏来开始我们的学习。
首先,既然是一组组合的控件,那就必须有一个可以来包含这些控件的容器,我们所接触的可以存放控件的容器很多,比如LinearLayout、RelativeLayout等等多种Layout,今天我们就选择RelativeLayout来做我们的容器。和以前一样,我们先定义一个CompositeViews类来继承RelativeLayout类,并重写它的构造方法,代码如下:
/**
* 作者:chengxiangtong on 2016/11/10 17:15
* 邮箱:528440900@qq.com
* 复合视图--控件组合
*/
public class CompositeViews extends RelativeLayout {
private TextView mTextViewleft;
private TextView mTextViewcenter;
private TextView mTextViewright;
private LayoutParams mLayoutParamsleft;
private LayoutParams mLayoutParamscenter;
private LayoutParams mLayoutParamsright;
private tabBarListener mTabBarListener;
public CompositeViews(Context context) {
this(context, null);
}
public CompositeViews(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CompositeViews(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
mTextViewleft = new TextView(context);
mTextViewcenter = new TextView(context);
mTextViewright = new TextView(context);
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CompositeViews);
//获取其他属性和背景颜色一样
int colorleftBackgroundColor = typedArray.getColor(R.styleable.CompositeViews_leftTextBackground, 0);
mLayoutParamsleft = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
mLayoutParamsleft.addRule(RelativeLayout.ALIGN_PARENT_LEFT, TRUE);
mTextViewleft.setText("左左左");
mTextViewleft.setBackgroundColor(colorleftBackgroundColor);
mTextViewleft.setTextSize(22);
addView(this.mTextViewleft, mLayoutParamsleft);
int colorcenterBackgroundColor = typedArray.getColor(R.styleable.CompositeViews_centerTextBackground, 0);
mLayoutParamscenter = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
mLayoutParamscenter.addRule(RelativeLayout.CENTER_HORIZONTAL, TRUE);
mTextViewcenter.setText("标题栏");
mTextViewcenter.setBackgroundColor(colorcenterBackgroundColor);
mTextViewcenter.setTextSize(22);
addView(mTextViewcenter, mLayoutParamscenter);
int colorrightBackgroundColor = typedArray.getColor(R.styleable.CompositeViews_rightTextBackground, 0);
mLayoutParamsright = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
mLayoutParamsright.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, TRUE);
mTextViewright.setText("右右右");
mTextViewright.setBackgroundColor(colorrightBackgroundColor);
mTextViewright.setTextSize(22);
addView(mTextViewright, mLayoutParamsright);
setOnListener();
}
public void settabBarOnclcikLisenter(tabBarListener mtabBar) {
mTabBarListener = mtabBar;
}
public void setOnListener() {
mTextViewleft.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
mTabBarListener.mTextViewleftListener();
}
});
mTextViewright.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
mTabBarListener.mTextViewrightListener();
}
});
}
public interface tabBarListener {
void mTextViewleftListener();
void mTextViewrightListener();
}
}
自定义属性其实也是相当的简单,首先,我们现在资源文件res下values目录下新建一个attrs.xml文件(as自建),新建的attrs.xml是一个包含如下代码的文件:
<declare-styleable name="CompositeViews"> <attr name="centerText" format="string"></attr> <attr name="centerTextSize" format="dimension"></attr> <attr name="centerTextColor" format="color"></attr> <attr name="centerTextBackground" format="color|reference"></attr> <attr name="leftText" format="string"></attr> <attr name="leftTextSize" format="dimension"></attr> <attr name="leftTextColor" format="color"></attr> <attr name="leftTextBackground" format="color|reference"></attr> <attr name="rightText" format="string"></attr> <attr name="rightTextSize" format="dimension"></attr> <attr name="rightTextColor" format="color"></attr> <attr name="rightTextBackground" format="color|reference"></attr> </declare-styleable>
attr代表的是一个属性,它里面所包含name字段是这条属性名,通过该属性名可以获取以format的约束为真的属性值;formate是该属性的格式,分别包含string,dimension,color,reference等等,分别代表字符串,大小,颜色,引用。其他的大家可以自行学习resources所包含的属性,但是在使用是之前必须在指定引用第三方控件的命名空间,在跟布局文件中添加如下一行代码:
xmlns:app=”http://schemas.android.com/apk/res-auto”
app是我们第三方命名空间的名字,可以任意命名,我们在使用自定义属性时必须以它开头。请看代码:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <test.com.test.CompositeViews android:id="@+id/CompositeViews" android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingBottom="@dimen/activity_horizontal_margin" app:centerTextBackground="@android:color/holo_blue_bright" app:leftTextBackground="@android:color/holo_purple" app:rightTextBackground="@android:color/holo_purple"/> </LinearLayout>
我们是使用custom加上我们自定义属性里面<attr name="centerTextBackground" format="color|reference"></attr>
里的name值来动态设置属性值的,如:app:centerTextBackground="@android:color/holo_blue_bright"
在我们xml文件中已设定好属性值,那么该怎么显示出来呢?这个是需要通过一个类型组TypedArray来获取
的,它里面包含各种从AttributeSet属性集中获取属性的方法,所以我们修改上面的构造方法和 init(Context context, At
tributeSet attrs)方
法,如下所示:
private void init(Context context, AttributeSet attrs) {
mTextViewleft = new TextView(context);
mTextViewcenter = new TextView(context);
mTextViewright = new TextView(context);
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CompositeViews);
//获取其他属性和背景颜色一样
int colorleftBackgroundColor = typedArray.getColor(R.styleable.CompositeViews_leftTextBackground, 0);
mLayoutParamsleft = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
mLayoutParamsleft.addRule(RelativeLayout.ALIGN_PARENT_LEFT, TRUE);
mTextViewleft.setText("左左左");
mTextViewleft.setBackgroundColor(colorleftBackgroundColor);
mTextViewleft.setTextSize(22);
addView(this.mTextViewleft, mLayoutParamsleft);
int colorcenterBackgroundColor = typedArray.getColor(R.styleable.CompositeViews_centerTextBackground, 0);
mLayoutParamscenter = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
mLayoutParamscenter.addRule(RelativeLayout.CENTER_HORIZONTAL, TRUE);
mTextViewcenter.setText("标题栏");
mTextViewcenter.setBackgroundColor(colorcenterBackgroundColor);
mTextViewcenter.setTextSize(22);
addView(mTextViewcenter, mLayoutParamscenter);
int colorrightBackgroundColor = typedArray.getColor(R.styleable.CompositeViews_rightTextBackground, 0);
mLayoutParamsright = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
mLayoutParamsright.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, TRUE);
mTextViewright.setText("右右右");
mTextViewright.setBackgroundColor(colorrightBackgroundColor);
mTextViewright.setTextSize(22);
addView(mTextViewright, mLayoutParamsright);
setOnListener();
}
代码解释:首先通过上下文context获取到属性存放到TypedArray 中,然后通过TypedArray 里封装好的各种方法获取对应的属性值,然后再分别为我们的控件设置属性。这样就完成了,自定义属性的使用,并且复用度高,每当需要使用标题栏是都只需要在xml中添加我们定义的View控件,为其配置属性即可使用,节约了开发时间,提高了效率,并且还保持的app风格的一致。
好,到这里感觉已经讲完了整个过程吧,其实还有一个重要的实现还没有讲。我们的控件已经可以呈现出来了,但是怎么完成里面控件的作用呢?
这里比较常见的做法是利用回调机制来实现功能的开发,首先我们先定义一个接口,创建两个方法,用于左右控件的点击事件。
把定义好的接口暴露给调用者
public void settabBarOnclcikLisenter(tabBarListener mtabBar) { mTabBarListener = mtabBar; }
然后在构造方法中为左右控件添加点击事件,等待调用者自己实现:
public void setOnListener() { mTextViewleft.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { mTabBarListener.mTextViewleftListener(); } }); mTextViewright.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { mTabBarListener.mTextViewrightListener(); } }); } public interface tabBarListener { void mTextViewleftListener(); void mTextViewrightListener(); }谁调用,谁实现.在这里我们只在MainActivity中代码如下:
public class MainActivity extends AppCompatActivity implements CompositeViews.tabBarListener { private CompositeViews mCompositeViews; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.layout3); mCompositeViews = (CompositeViews) findViewById(R.id.CompositeViews); mCompositeViews.settabBarOnclcikLisenter(this); } @Override public void mTextViewleftListener() { Toast.makeText(this,"mTextViewleftListener",Toast.LENGTH_LONG).show(); } @Override public void mTextViewrightListener() { Toast.makeText(this,"mTextViewrightListener",Toast.LENGTH_LONG).show(); } }
已经可以实现我们的需求了,下一篇是自定viewGroup
github地址:https://github.com/xiangtongcheng/customerView