写在前面:
我们写应用的时候,常常会发现很多界面都是有相同或是相似的部分的,比如相同的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