写在前面:
我们写应用的时候,常常会发现很多界面都是有相同或是相似的部分的,比如相同的Topbar或是相同的底部之类。
我们以QQ为例:
而且这些相似的部分一旦修改,就是所有的一起修改,如果就改一两个倒还好,多了你试试?都说懒惰是程序员进步的阶梯,所以懒惰的程序员们就使用模板这种东西来提高自己的生产效率,同时也提高了代码的可读性、可维护性。本文就和大家一起来实现我们自己的模板,一个Topbar。效果如下:
麻雀虽小,五脏俱全,重要的是思想。
1.declare-styleable的使用
2.自定义控件
3.在界面中复用自定义控件
public class TopBar extends RelativeLayout {
private Button leftButton, rightButton;
private TextView title;
// 左侧button属性
private int leftTextColor;
private Drawable leftBackground;
private String leftText;
// 右侧button属性
private int rightTextColor;
private Drawable rightBackground;
private String rightText;
// title属性
private int titleTextColor;
private float titleTextSize;
private String titleText;
// 布局属性
private LayoutParams leftParams, rirhtParams, titleParams;
private TopBarClickListener listener;
public TopBar(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO 自动生成的构造函数存根 //这个方法还是空的,下面会填充!
}
// 点击事件监听器接口
public interface TopBarClickListener {
public void leftclick();
public void rightclick();
}
// 设置监听器
public void setOnTopBarClickListener(TopBarClickListener listener) {
this.listener = listener;
}
public void setLeftIsVisible(boolean visible) {
if (visible) {
leftButton.setVisibility(View.VISIBLE);
} else {
leftButton.setVisibility(View.GONE);
}
}
public void setRightIsVisible(boolean visible) {
if (visible) {
rightButton.setVisibility(View.VISIBLE);
} else {
rightButton.setVisibility(View.GONE);
}
}
}
可以看到,我们在这个布局中定义了所需要的三个控件,以及这三个控件的属性。我们还建立了接口回调机制,使用这个自定义控件的其他布局可以通过这个接口来设定监听机制。同时还可以调用setIsvisible方法来隐藏或者显示左右两边的按钮。不过现在我们还没有为这些属性赋值,所以我们继续看下去。
什么是declare-styleable?是在values文件夹下attrs.xml中用来定义属性集的。
首先来看看attrs.xml文件。
该文件是定义属性名和格式的地方,需要用<declare-styleable name="TopBar"></declare-styleable>包围所有属性。其中name为该属性集的名字,主要用途是标识该属性集。那在什么地方会用到呢?在我们的自定义控件获取某属性标识时,会用到"R.styleable.TopBar..."(稍后会看到),很显然,他在每个属性前面都加了"TopBar_"。
在来看看各种属性都有些什么类型吧:string , integer , dimension , reference , color , enum......
前面几种的声明方式都是一致的,例如:<attr name="buttonNum" format="integer"/>。
只有enum是不同的,用法举例:
<span style="color:#330000;"><attr name="testEnum">
<enum name="fill_parent" value="-1"/>
<enum name="wrap_content" value="-2"/>
</attr></span>
现在大家应该明白attrs.xml的用途以及写法了,我们来为自定义的Topbar写个attrs.xml(放在values文件夹下):
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="TopBar"> <!-- 文字 --> <attr name="leftText" format="string" /> <attr name="rightText" format="string" /> <attr name="titleText" format="string" /> <!-- 文字颜色 --> <attr name="leftTextColor" format="color" /> <attr name="rightTextColor" format="color" /> <attr name="titleTextColor" format="color" /> <!-- 文字大小 --> <attr name="titleTextSize" format="dimension" /> <!-- 背景色 --> <attr name="leftBackground" format="reference|color" /> <attr name="rightBackground" format="reference|color" /> </declare-styleable> </resources>
然后我们补充上边Topbar类的构造函数:
public TopBar(Context context, AttributeSet attrs){
super(context, attrs);
//获取自定义属性和值的映射集合
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.TopBar);
//取出自定义属性 - 左侧
leftTextColor = ta.getColor(R.styleable.TopBar_leftTextColor, Color.BLACK);
leftBackground = ta.getDrawable(R.styleable.TopBar_leftBackground);
leftText = ta.getString(R.styleable.TopBar_leftText);
//取出自定义属性 - 右侧
rightTextColor = ta.getColor(R.styleable.TopBar_rightTextColor, Color.BLACK);
rightBackground = ta.getDrawable(R.styleable.TopBar_rightBackground);
rightText = ta.getString(R.styleable.TopBar_rightText);
//取出自定义属性 - 标题
titleTextColor = ta.getColor(R.styleable.TopBar_titleTextColor, Color.BLACK);
titleTextSize = ta.getDimension(R.styleable.TopBar_titleTextSize, 12);
titleText = ta.getString(R.styleable.TopBar_titleText);
//回收TypedArray(避免浪费资源,避免因为缓存导致的错误)
ta.recycle();
leftButton = new Button(context);
rightButton = new Button(context);
title = new TextView(context);
//设置属性 - 左侧
leftButton.setText(leftText);
leftButton.setTextColor(leftTextColor);
leftButton.setBackground(leftBackground);
//设置属性 - 左侧
rightButton.setText(rightText);
rightButton.setTextColor(rightTextColor);
rightButton.setBackground(rightBackground);
//设置属性 - 标题
title.setText(titleText);
title.setTextSize(titleTextSize);
title.setTextColor(titleTextColor);
title.setGravity(Gravity.CENTER);
//设置整体背景颜色
setBackgroundColor(0xfff59563);
//设置布局 - 左
leftParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
leftParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT, TRUE);
leftParams.addRule(RelativeLayout.CENTER_VERTICAL, TRUE);
addView(leftButton, leftParams);//将按钮添加进布局中
//设置布局 - 右
rirhtParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
rirhtParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, TRUE);
rirhtParams.addRule(RelativeLayout.CENTER_VERTICAL, TRUE);
addView(rightButton, rirhtParams);//将按钮添加进布局中
//设置布局 - 标题
titleParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
titleParams.addRule(RelativeLayout.CENTER_IN_PARENT, TRUE);
addView(title, titleParams);//将按钮添加进布局中
//设置监听器
leftButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v){
listener.leftclick();
}
});
rightButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v){
listener.rightclick();
}
});
}这个构造函数就是用传进来的值对控件的属性进行赋值,另外给控件加了监听,加入到自己的布局中。我们在MainActivity中要使用这个Topbar,那首先我们要在它的布局文件中(activity_main.xml)引用我们的自定义控件:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res/com.sloop.topbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.sloop.topbar.MainActivity" >
<com.example.mytopbar.TopBar
android:minHeight="48dp"
android:id="@+id/topbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:leftBackground="@drawable/blue_button"
app:leftText="左侧"
app:titleTextSize="8sp"
app:rightBackground="@drawable/blue_button"
app:rightText="右侧"
app:titleText="自定义标题"
app:titleTextColor="#ffffff" >
</com.example.mytopbar.TopBar>
</RelativeLayout>在这个文件中我们为它的三个组成部分的属性赋了值,细心的朋友可能发现对button的背景使用了自定义的blue_button,以下是blue_button.xml(在drawable文件夹下):
<?xml version="1.0" encoding="utf-8"?>
<!-- shape如果不声明形状默认是正方形 -->
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<!-- 设置圆角 -->
<corners android:radius="2dp" >
</corners>
<!-- 设置填充色 -->
<solid android:color="#4285f4" >
</solid>
<!-- 设置边框的颜色和宽度 -->
<stroke
android:width="1dp"
android:color="#4285f4" >
</stroke>
</shape>
要长成什么样,大家可以自己根据需求修改。
然后是MainActicity的代码:public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//获取自定义控件
TopBar topBar = (TopBar) findViewById(R.id.topbar); //id是在acitivity_main中定义的
topBar.setOnTopBarClickListener(new TopBarClickListener() {
@Override
public void rightclick(){
Toast.makeText(MainActivity.this, "Right Clicked", Toast.LENGTH_SHORT).show();
}
@Override
public void leftclick(){
Toast.makeText(MainActivity.this, "Left Clicked", Toast.LENGTH_SHORT).show();
}
});
}
}
其中实现了Topbar中定义的接口,从而根据不同的需求来添加不同的监听。也可以调用setvisible方法来控制是否显示。
到这里,我们就实现了我们自定义的Topbar,实现了高度的可复用性。
效果如下:
========================================
写在后面:
任何问题,欢迎留言交流!
原文地址:http://blog.csdn.net/u012422829/article/details/46402167