11-自定義組合控制元件以及使用

weixin_34377065發表於2016-08-04

一、自定義組合控制元件介紹

開發中,為了使用的方便,經常把一些控制元件組合成一個控制元件,那樣就成為了我們的自定義組合控制元件,嚴格意義來說,自定義組合控制元件並不屬於“自定義控制元件”。

二、自定義組合控制元件步驟

1、建立一個java類,繼承View(或者View的子類),改寫建構函式。如下所示,NumberAddSubView是我們的自定義組合控制元件的名字。通過建構函式的改造,使得一個呼叫另外一個,最終我們只要修改的是引數最多的那個就可以了。

public NumberAddSubView(Context context) {
        this(context, null);
    }

    public NumberAddSubView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public NumberAddSubView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
}

2、為這個自定義組合控制元件建立一個佈局:

<?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="wrap_content"
    android:background="@drawable/shape_number_view_bg"
    android:gravity="center"
    android:orientation="horizontal"
    android:padding="5dp">

    <Button
        android:id="@+id/btn_sub"
        style="@style/NumberAddSubDefStyle"
        android:gravity="center"
        android:text="-"/>

    <EditText
        android:id="@+id/et_num"
        style="@style/TextDefStyle"
        />

    <Button
        android:id="@+id/btn_add"
        style="@style/NumberAddSubDefStyle"
        android:gravity="center"
        android:text="+"/>

</LinearLayout>

3、載入佈局,通過ID找到所有控制元件。

private void initView(Context context) {
    View view = LayoutInflater.from(context).inflate(R.layout.number_add_sub_view, this, true);
    btn_add = (Button) view.findViewById(R.id.btn_add);
    btn_sub = (Button) view.findViewById(R.id.btn_sub);
    et_num = (EditText) view.findViewById(R.id.et_num);

    btn_add.setOnClickListener(this);
    btn_sub.setOnClickListener(this);
    et_num.addTextChangedListener(this);
}

4、自定義屬性:在value資料夾建立attrs.xml檔案,並且新增自定義屬性:

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <declare-styleable name="NumberAddSubView">

        <attr name="value" format="integer|reference"/>
        <attr name="maxValue" format="integer|reference"/>
        <attr name="minValue" format="integer|reference"/>
        <attr name="btnDrawable" format="reference"/>

    </declare-styleable>

</resources>

5、最後,在自定義控制元件裡面做一切你想做的事情,例如按鈕點選回撥,文字變化回撥等。

下面是菜鳥商城專案中的需求:

自定義數字加減控制元件
1.輸入框只能是數字,且不能通過鍵盤輸入 2.通過加減按鈕運算元字 3.監聽加減按鈕 4.數字有最小值和最大值的限制 5.自定義屬性

下面給出完整的java程式碼:

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.support.v7.widget.TintTypedArray;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;

/**
 * 自定義數字加減控制元件
 */
public class NumberAddSubView extends LinearLayout implements View.OnClickListener, TextWatcher {

    private int maxValue;
    private int minValue;
    private int value;

    private Button btn_add;
    private Button btn_sub;
    private EditText et_num;

    public NumberAddSubView(Context context) {
        this(context, null);
    }

    public NumberAddSubView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public NumberAddSubView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        //初始化佈局
        initView(context);

        //讀取自定義屬性的值並且設定
        TintTypedArray a = TintTypedArray.obtainStyledAttributes(context, attrs, R.styleable.NumberAddSubView, defStyleAttr, 0);

        value = a.getInt(R.styleable.NumberAddSubView_value, 1);
        maxValue = a.getInt(R.styleable.NumberAddSubView_maxValue, 1);
        minValue = a.getInt(R.styleable.NumberAddSubView_minValue, 1);
        Drawable btnBg = a.getDrawable(R.styleable.NumberAddSubView_btnDrawable);
        if (btnBg != null) {
            btn_add.setBackgroundDrawable(btnBg);
            btn_sub.setBackgroundDrawable(btnBg);
        }
        a.recycle();

    }

    private void initView(Context context) {
        View view = LayoutInflater.from(context).inflate(R.layout.number_add_sub_view, this, true);
        btn_add = (Button) view.findViewById(R.id.btn_add);
        btn_sub = (Button) view.findViewById(R.id.btn_sub);
        et_num = (EditText) view.findViewById(R.id.et_num);

        btn_add.setOnClickListener(this);
        btn_sub.setOnClickListener(this);
        et_num.addTextChangedListener(this);
    }

    /**
     * 數字變化的監聽
     */
    public interface OnNumberChangeListener {
        void onChange(int value, boolean isInRange);
    }

    private OnNumberChangeListener mListener;

    public void setOnNumberChangeListener(OnNumberChangeListener listener) {
        this.mListener = listener;
    }

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {

    }

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
        if (mListener != null) {
            if (!TextUtils.isEmpty(s)) {
                int val = Integer.parseInt(s.toString());

                if (val <= maxValue && val >= minValue) {
                    mListener.onChange(val, true);
                } else {
                    mListener.onChange(val, false);
                }

            }
        }
    }

    @Override
    public void afterTextChanged(Editable s) {

    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_add:
                valueAdd();
                break;
            case R.id.btn_sub:
                valueSub();
                break;
        }
    }

    public void valueAdd() {
        if (!TextUtils.isEmpty(et_num.getText())) {
            int val = Integer.parseInt(et_num.getText().toString());
            if (val < maxValue) {
                val++;
            }
            setValue(val);
        }
    }

    public void valueSub() {
        if (!TextUtils.isEmpty(et_num.getText())) {
            int val = Integer.parseInt(et_num.getText().toString());
            if (val > minValue) {
                val--;
            }
            setValue(val);
        }
    }

    public int getMaxValue() {
        return maxValue;
    }

    public void setMaxValue(int maxValue) {
        this.maxValue = maxValue;
    }

    public int getMinValue() {
        return minValue;
    }

    public void setMinValue(int minValue) {
        this.minValue = minValue;
    }

    public int getValue() {
        return value;
    }

    public void setValue(int value) {
        this.value = value;
        et_num.setText(value + "");
    }

    public void setRange(int minValue, int maxValue) {
        this.minValue = minValue;
        this.maxValue = maxValue;
    }
}

三、自定義組合控制元件的使用

根據自己如何定義,使用的方法都不一樣。例如我在自定義控制元件裡面新增了文字變化的回撥,那麼我們就可以進行監聽。

不過大體來說,跟基本控制元件以及“自定義控制元件”的使用一模一樣。

1、在佈局檔案中放置自定義組合控制元件:
需要注意的是,名稱空間需要自定義一個,隨便寫“app”即可,至於寫什麼沒有要求,但是它的值需要使用res-auto。
注意新增上我們自定義的屬性。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/holo_green_light">

    <com.nan.numaddsubview.NumberAddSubView
        android:id="@+id/num_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:maxValue="5"
        app:minValue="1"
        app:value="1"/>

</RelativeLayout>

2、java程式碼中的使用:
這裡我設定文字變化的監聽。

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        NumberAddSubView numberAddSubView = (NumberAddSubView) findViewById(R.id.num_view);

//      numberAddSubView.setMaxValue(10);

        numberAddSubView.setOnNumberChangeListener(new NumberAddSubView.OnNumberChangeListener() {
            @Override
            public void onChange(int value, boolean isInRange) {
                Toast.makeText(MainActivity.this, value + "" + isInRange, Toast.LENGTH_SHORT).show();
            }
        });
    }
}

四、效果

2570030-8ba48ed0e7904d70.png

為了方便看,我把activity的背景顏色換了一下。好了,今天的筆記就到這裡(≧▽≦)/啦啦啦。

如果覺得我的文字對你有所幫助的話,歡迎關注我的公眾號:

2570030-83ea355270eebc16
公眾號:Android開發進階

我的群歡迎大家進來探討各種技術與非技術的話題,有興趣的朋友們加我私人微信huannan88,我拉你進群交(♂)流(♀)

相關文章