11-自定义组合控件以及使用

一、自定义组合控件介绍

开发中,为了使用的方便,经常把一些控件组合成一个控件,那样就成为了我们的自定义组合控件,严格意义来说,自定义组合控件并不属于“自定义控件”。

二、自定义组合控件步骤

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();
            }
        });
    }
}

四、效果

为了方便看,我把activity的背景颜色换了一下。好了,今天的笔记就到这里(≧▽≦)/啦啦啦。

如果觉得我的文字对你有所帮助的话,欢迎关注我的公众号:

公众号:Android开发进阶

我的群欢迎大家进来探讨各种技术与非技术的话题,有兴趣的朋友们加我私人微信huannan88,我拉你进群交(♂)流(♀)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,045评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,114评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,120评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,902评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,828评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,132评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,590评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,258评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,408评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,335评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,385评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,068评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,660评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,747评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,967评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,406评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,970评论 2 341

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,279评论 25 707
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 11,982评论 4 60
  • sqlite:关系型数据库以表格的形式存储 在sqlite中类似表格的表头的位置叫做《字段》(字段名不能重复)字段...
    磊CC阅读 203评论 0 0
  • 现在时间是凌晨两点四十六分,我睡意全无,胃打了个结有点难受。我花了快一个小时的时间尝试睡觉,还是睡不着,简直了,烦...
    就是陈三岁阅读 273评论 5 3