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的動畫效果,這些都是需要我們深入瞭解的。