淺談自定義View

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

源碼下載

發佈了42 篇原創文章 · 獲贊 19 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章