Android提供了比较丰富的组件库来创建UI,但是并不能完全满足我们的需求,考虑到这一点Google给我们提供非常方便的拓展方法,我们可以在原有控件的基础上来自定义满足我们需求的View。掌握自定义View,是Android开发的一项重要内容。那么如何实现自定义view呢,方法有很多。我要说的是比较简单的创建复合控件。
一般有以下几步:
1.继承一个合适的ViewGroup
2.定义属性
3.组合组件
4.定义接口并开发给调用者
继承一个合适的ViewGroup
第一步很简单,根据自己的需要继承合适的ViewGroup就可以了,例如LinearLayout,FrameLayout。这样做的好处是在系统提供的组件的基础上实现我们想要的效果,不必考虑一些其他的问题。
定义属性
这在Android中也非常的简单,只需要在res资源目录的values目录下创建attrs.xml文件,在该文件中做相应的定义即可:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="add_and_sub">
<!--最小数量-->
<attr name="minCount" format="integer"/>
</declare-styleable>
</resources>
其中
<declare-styleable name="add_and_sub"></declare-styleable>
标签申明使用自定义的属性,并且设置引用name为add_and_sub 然后在通过<attr>
申明具体的属性。这里申明的是最小数量minCount,并且设置integer类型。当然这里的format可以使用多种类型,各属性之间用“|”隔开。
组合组件
我们定义类 AddAndSubButton 继承自FrameLayout,在构造方法中使用TypedArray来获取我们定义的属性:
TypedArray ta=context.obtainStyledAttributes(attrs, R.styleable.add_and_sub);
使用TypedArray提供的getXXX()方法获取相应的属性。如:
ta=context.obtainStyledAttributes(attrs, R.styleable.add_and_sub);
//设置默认最小值为1 CurrentCount=minCount=ta.getInt(R.styleable.add_and_sub_minCount,1);
获取完后不要忘记调用recycle()
接下来我们就需要组合我们的控件了:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="35dp"
android:orientation="horizontal" >
<Button
android:id="@+id/btn_sub"
android:layout_width="35dp"
android:layout_height="35dp"
android:padding="10dp"
android:background="@drawable/bg_sub_btn"
android:clickable="false"
android:focusable="false"
/>
<EditText
android:id="@+id/edit_count"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:minWidth="70dp"
android:text="1"
android:inputType="number"
android:maxLength="7"
android:background="@drawable/bg_count_shape"
android:textColor="#595959"
android:textSize="18sp" />
<Button
android:id="@+id/btn_add"
android:layout_width="35dp"
android:layout_height="35dp"
android:padding="10dp"
android:background="@drawable/bg_add_btn"
/>
</LinearLayout>
很简单,就是使用了两个button和一个EditText。然后在AddAndSubButton类中做具体的实现了。
import android.content.Context;
import android.content.res.TypedArray;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.FrameLayout;
import com.chuck.mobile.changecountview.R;
/**
* 自定义可以修改数量的button
*/
public class AddAndSubButton extends FrameLayout {
/**自定义属性集合*/
private TypedArray ta;
/**减按钮*/
private Button btn_sub;
/**加按钮*/
private Button btn_add;
/**数量显示*/
private EditText edit_count;
/**最小数量*/
private int minCount;
/**目前数量*/
private int CurrentCount;
public AddAndSubButton(Context context,AttributeSet attrs) {
super(context, attrs);
ta=context.obtainStyledAttributes(attrs, R.styleable.add_and_sub);
LayoutInflater.from(context).inflate(R.layout.widget_add_and_sub,this);
btn_add= (Button) findViewById(R.id.btn_add);
btn_sub= (Button) findViewById(R.id.btn_sub);
edit_count= (EditText) findViewById(R.id.edit_count);
//设置默认最小值为1
CurrentCount=minCount=ta.getInt(R.styleable.add_and_sub_minCount,1);
ta.recycle();
edit_count.setText(minCount+"");
edit_count.setEnabled(false);
setSubBtnEnable(false);
btn_sub.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
updateSubButtonStatus();
}
});
btn_add.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
updateAddButtonStatus();
}
});
}
private void updateAddButtonStatus() {
if(CurrentCount>=minCount){
setSubBtnEnable(true);
btn_sub.setBackgroundDrawable(getResources().getDrawable(
R.drawable.bg_sub_btn));
}
setTextCount(CurrentCount+1);
}
private void updateSubButtonStatus() {
if (CurrentCount > minCount) {
setTextCount(CurrentCount - 1);
if (CurrentCount == minCount) {
btn_sub.setBackgroundDrawable(getResources().getDrawable(
R.mipmap.ic_sub_btn_error));
}
} else {
setSubBtnEnable(false);
btn_sub.setBackgroundDrawable(getResources().getDrawable(
R.mipmap.ic_sub_btn_error));
}
}
/**
* 设置数量
*
* @param count
*/
public void setTextCount(int count) {
CurrentCount=count;
edit_count.setText(CurrentCount + "");
}
/**
* 设置数量
*
* @param count
*/
public void setTextColor(int color) {
edit_count.setTextColor(color);
}
/**
* 设置是否可编辑
*
* @param editable
*/
public void setEditable(boolean editable) {
edit_count.setEnabled(editable);
}
public void setMinCount(int minCount){
this.minCount = minCount;
}
/**
* 获取当前的数量 (默认返回-1 为无效值 )
*
* @return
*/
public int getCount() {
int count = -1;// 默认返回-1 无效值
String text = edit_count.getText().toString().trim();
if (!TextUtils.isEmpty(text)) {
try {
count = Integer.parseInt(text);
} catch (NumberFormatException e) {
e.printStackTrace();
}
}
return count;
}
/**
* 设置减按钮是否可点击 false不可再点击 true可以点击
*
* @param flag
*/
public void setSubBtnEnable(boolean flag) {
btn_sub.setFocusable(flag);
btn_sub.setClickable(flag);
if (flag) {
btn_sub.setBackgroundDrawable(getResources().getDrawable(
R.drawable.bg_sub_btn));
} else {// 设置减按钮不可继续点击
btn_sub.setBackgroundDrawable(getResources().getDrawable(
R.mipmap.ic_sub_btn_error));
}
}
/**
* 设置加按钮是否可点击 false不可再点击 true可以点击
*
* @param flag
*/
public void setAddBtnEnable(boolean flag) {
btn_add.setFocusable(flag);
btn_add.setClickable(flag);
if (flag) {
btn_add.setBackgroundDrawable(getResources().getDrawable(
R.drawable.bg_add_btn));
} else {// 设置加按钮不可继续点击
btn_add.setBackgroundDrawable(getResources().getDrawable(
R.mipmap.ic_add_btn_error));
}
}
public Button getAddButton() {
return btn_add;
}
public Button getSubButton() {
return btn_sub;
}
}
实现了类似淘宝购物车修改宝贝数量的button。点击左边button数量减1,点击右边button数量加1。这里也可以根据需求的不同提供相应的接口。
定义接口并开发给调用者
在AddAndSubButton类中定义接口,如:
public interface AddbuttonLongClickListener{
public void onLongClick(View view);
}
开发给调用者:
public void setOnAddButtonLongClickListener(AddbuttonLongClickListener listener){
this.listener=listener;
}
这里根据自己的需求,在自定义View中添加相应的接口。也可以将成员方法设置为public 供调用者使用。
然后我们的View可以使用了
<com.chuck.mobile.changecountview.widget.AddAndSubButton
android:id="@+id/aasb_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:minCount="2">
运行结果
总结:自定义View有很多方法,感兴趣的可以去了解一下。这里只是较浅的介绍了其中一种方法。并且自定义View还需要注意很多问题,如滑动冲突的解决,让View支持wrap_content,和View的动画效果,这些都是需要我们深入了解的。