今天学习了Android自定义模板view的方法,之前还是不太懂这个自定义view到底是如何实现的,但是通过今天的学习,基本上搞懂了自定义view的设计理念。
关于自定义view用处,实际上有很多,我们用过的slidingMenu就是最经典的自定义view,android本身只能提供最基本的layout和一些button,textview等基本控件,但是通过对这些view的组合与设计,我们便可以设计出符合我们自己要求的UI控件。就好像一个actionbar,我们只要写出一个模板来,然后就可以把它当成已有的控件来像button一样使用,这大大的提高了我们的开发效率与增强了程序的健壮性。
现在我以设计一个topbar为例,topbar类似于一个actionbar,左边一个button,右边一个button,中间一个textview来设计一个view模板:
首先我们知道一个系统控件自带很多属性,例如:layout_width等,都是android自己定义好的,现在我们在value下定义一个属性文件attr.xml用于存放我们topbar的属性:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- 自定义属性文件,自定义控件属性名称以及资源格式 -->
<declare-styleable name="Topbar">
<attr name="title" format="string"></attr>
<attr name="titleTextsize" format="dimension"></attr>
<attr name="titleTextcolor" format="color"></attr>
<attr name="leftTextColor" format="color"></attr>
<attr name="leftText" format="string"></attr>
<attr name="leftBackground" format="reference|color"></attr>
<attr name="rightTextColor" format="color"></attr>
<attr name="rightText" format="string"></attr>
<attr name="rightBackground" format="color|reference"></attr>
</declare-styleable>
</resources>
设置好这些属性后,我们就可以创建一个topbar类,来映射这些属性,由于在文件中我已经写好了注释,所以就把完整的代码放出来了,其中主要是步骤:
- 先定义好要实现的组件,我们有两个button还有一个textview
- 定义好与attr.xml中对应的属性值
- 然后通过typedarray数组来获取attr.xml中对应的属性
- 然后实例化子控件
- 再将自定义属性值赋给子控件
- 通过LayouParams将设置好控件的宽高等其他系统默认属性,通过addveiw方法赋值给子控件
- 由于要实现button的点击事件,所以我们可以提供一个接口,让外部添加事件,实现的方法我已经在注释中写清除了
package com.example.zidingyi_view;
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;
/**
* 自定义view的步骤: 1:定义好attr下的xml文件属性
* 2:定义好class
* 3:引入控件,定义好layoutparams,再addview
*
* @author nickming
*实例总结:
*添加名字空间 {
*1.Android Studio中只需要写上res-auto即可
*2.Eclipse中则需要加上完整的包名和控件名
*3.xmlns:custom="http://schmas.android.com/apk/res-auto"}
*
*通过模板复用,接口回调,增加程序的效率,降低程序的耦合度
*接口回调是重点
*
*/
@SuppressLint("NewApi")
public class Topbar extends RelativeLayout {
private Button leftButton, rightButton;
private TextView tvTitle;
// 对应的attr下的属性值
private int leftTextColor;
private Drawable leftBackground;
private String leftTextString;
private int rightTextColor;
private Drawable rightBackground;
private String rightTextString;
private int titleTextColor;
private float titleTextSize;
private String titleString;
LayoutParams leftLayoutParams;
LayoutParams rightLayoutParams;
LayoutParams titleLayoutParams;
private boolean leftButtonVisiable=true;
/**
* 接口回调
* 重点,接口的设计,一般先一个公共接口,然后在里面设置好提供的函数
* 然后再提供一个外部访问的函数接口,再通过实例化一个接口对象,来与方法
* 进行映射,这里面再对button经行事件的设计
* @author nickming
*
*/
public interface topbarClickListener{
public void leftClick();
public void rightClick();
}
public topbarClickListener mListener;
public void setOnTopBarClickListener(topbarClickListener listener){
mListener=listener;
}
public Topbar(Context context) {
this(context, null);
// TODO Auto-generated constructor stub
}
@SuppressLint("NewApi")
public Topbar(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
// 用typeArray来获取xml中的属性集合
TypedArray tArray = context.obtainStyledAttributes(attrs,
R.styleable.Topbar);
leftTextColor = tArray.getColor(R.styleable.Topbar_leftTextColor, 0);
leftTextString = tArray.getString(R.styleable.Topbar_leftText);
leftBackground = tArray.getDrawable(R.styleable.Topbar_leftBackground);
rightBackground = tArray
.getDrawable(R.styleable.Topbar_rightBackground);
rightTextColor = tArray.getColor(R.styleable.Topbar_rightTextColor, 0);
rightTextString = tArray.getString(R.styleable.Topbar_rightText);
titleString = tArray.getString(R.styleable.Topbar_title);
titleTextColor = tArray.getColor(R.styleable.Topbar_titleTextcolor, 0);
titleTextSize = tArray
.getDimension(R.styleable.Topbar_titleTextsize, 0);
tArray.recycle();//最后要回收这个数组
leftButton=new Button(context);
rightButton=new Button(context);
tvTitle=new TextView(context);
//将自定义的属性赋值
leftButton.setTextColor(leftTextColor);
leftButton.setBackground(leftBackground);
leftButton.setText(leftTextString);
rightButton.setTextColor(rightTextColor);
rightButton.setBackground(rightBackground);
rightButton.setText(rightTextString);
tvTitle.setText(titleString);
tvTitle.setTextColor(titleTextColor);
tvTitle.setTextSize(titleTextSize);
tvTitle.setGravity(Gravity.CENTER);
setBackgroundColor(0xFFF59563);
/**
*先定义宽高属性
*然后定义其他属性,用addrule
*最后再调用本函数的addview方法添加控件到viewgroup中
*/
leftLayoutParams=new LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);
leftLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT,TRUE);
addView(leftButton,leftLayoutParams);
rightLayoutParams=new LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);
rightLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT,TRUE);
addView(rightButton,rightLayoutParams);
titleLayoutParams=new LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.MATCH_PARENT);
titleLayoutParams.addRule(RelativeLayout.CENTER_IN_PARENT);
addView(tvTitle,titleLayoutParams);
leftButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
mListener.leftClick();
}
});
rightButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
mListener.rightClick();
}
});
}
public void setLeftIsVisiable(boolean flag)
{
if (flag) {
leftButton.setVisibility(View.VISIBLE);
leftButtonVisiable=true;
}else {
leftButton.setVisibility(View.GONE);
leftButtonVisiable=false;
}
}
public boolean isLeftButtonVisiable()
{
return leftButtonVisiable;
}
}
最后,我们在main.xml中使用我们的控件,注意要记得命名空间一定要写好:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:nickming="http://schemas.android.com/apk/res/com.example.zidingyi_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.zidingyi_view.MainActivity" >
<com.example.zidingyi_view.Topbar
android:id="@+id/topbar"
android:layout_width="match_parent"
android:layout_height="40dp"
nickming:leftBackground="#33333333"
nickming:leftTextColor="#ffffff"
nickming:leftText="你好"
nickming:rightTextColor="#ffffff"
nickming:rightText="我好"
nickming:rightBackground="#87889999"
nickming:title="自定义标题"
nickming:titleTextsize="10sp"
nickming:titleTextcolor="#ffffff">
</com.example.zidingyi_view.Topbar>
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/topbar"
android:layout_centerHorizontal="true"
android:layout_marginTop="102dp"
android:text="更改topbar" />
</RelativeLayout>
最后放出mainActivity的方法:
package com.example.zidingyi_view;
import com.example.zidingyi_view.Topbar.topbarClickListener;
import android.R.bool;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends Activity {
private Topbar topbar;
private Button button;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
topbar=(Topbar) findViewById(R.id.topbar);
topbar.setOnTopBarClickListener(new topbarClickListener() {
@Override
public void rightClick() {
// TODO Auto-generated method stub
Toast.makeText(MainActivity.this, "rightButton", Toast.LENGTH_SHORT).show();
}
@Override
public void leftClick() {
// TODO Auto-generated method stub
Toast.makeText(MainActivity.this, "leftButton", Toast.LENGTH_SHORT).show();
}
});
button=(Button) findViewById(R.id.button1);
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if (topbar.isLeftButtonVisiable()) {
topbar.setLeftIsVisiable(false);
}else {
topbar.setLeftIsVisiable(true);
}
}
});
}
}
基本上就大功告成,这只是一个简单的demo,最主要的就是定义好属性与接口回调方法。如有错误,请大家一起讨论。