Android自定义数值增减控件

来源:互联网 发布:王珊数据库第五版视频 编辑:程序博客网 时间:2024/05/22 14:50

    • 前言
    • 效果截图
    • 主要代码
      • attrsxml
      • IncreaseReduceTextView
      • 弹出对话框DialogFragment
      • DiaglogFragment所使用的xml布局文件

前言

最近做一个小App的时候用到了数值增减功能,主要用途就是在将商品添加到购物车时指定购买商品数量;遇到这个需求后首先想到的就是去网上找个现成的来用,但寻找很久也没找到合适的;可能太简单没人觉得这是什么大不了的,或者根本不需要自定义一个控件,这样只能自己动手了。

我本身是个Android新手,很多地方都还是理解不清楚;这次自定义的控件也不知道怎么样,但勉强能满足自己的需求。

效果截图

这里写图片描述

上图中的“数量“即是本控件的样子,可以点击左右的加减号来控制TextView中数值的增减。

这里写图片描述

上图是在点击TextView时弹出的对话框,在对话框中的TextView中输入想要的数字后,确定即可退出对话框,然后将数字填写入控件的TextView。

在控件数值改变后可以触发监听器,用于回调。

主要代码

attrs.xml

首先在attrs.xml文件中定义所要用到的属性,如下所示:

<declare-styleable name="IncreaseReduceTextView">    <attr name="textBackground" format="reference"/>    <attr name="textSize" format="dimension"/>    <attr name="verticalPadding" format="dimension"/>    <attr name="horizontalPadding" format="dimension"/>    <attr name="viewSpace" format="dimension"/></declare-styleable>

简单解释一下:

  • textBackground
    控件TextView文本域背景
  • textSize
    文本域字体大小, 默认为14sp
  • verticalPadding
    文本域垂直方向上的内边距, 默认为2dp
  • horizontalPadding
    文本域水平方向上的内边距, 默认为2dp
  • viewSpace
    TextView左右Margin

IncreaseReduceTextView

接下来是主控件代码,代码较多,但逻辑很简单,如下所示:

package com.witmoon.xmb.ui.widget;import android.content.Context;import android.content.res.TypedArray;import android.graphics.Paint;import android.support.v4.app.FragmentActivity;import android.util.AttributeSet;import android.util.TypedValue;import android.view.Gravity;import android.view.View;import android.view.ViewGroup;import android.widget.ImageView;import android.widget.TextView;import com.witmoon.xmb.R;import com.witmoon.xmb.activity.common.fragment.PurchaseQuantityDialogFragment;import com.witmoon.xmb.util.DensityUtils;/** * 自定义数值增减控件, 用于购买数量 * Created by zhyh on 2015/5/26. */public class IncreaseReduceTextView extends ViewGroup implements View.OnClickListener {    private Context mContext;    private int number = 1;    private int mTargetWidth;    private ImageView mMinusImageButton;    private TextView mNumberTextView;    private ImageView mAddImageButton;    private int mBackground;                // TextView背景资源    private int mTextSize = 14;             // 字体大小, 默认为14sp    private int mVerticalPadding = 2;       // TextView上下内边距, 默认为2dp    private int mHorizontalPadding = 2;     // TextView左右内边距, 默认为2dp    private int mViewSpace = 0;             // TextView左右Margin    public IncreaseReduceTextView(Context context) {        this(context, null);    }    public IncreaseReduceTextView(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public IncreaseReduceTextView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        if (getChildCount() > 0) {            throw new RuntimeException("IncreaseReduceTextView不允许有子元素.");        }        this.mContext = context;        // 读取自定义属性        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.IncreaseReduceTextView);        mBackground = ta.getResourceId(R.styleable.IncreaseReduceTextView_textBackground, 0);        mTextSize = ta.getDimensionPixelSize(R.styleable.IncreaseReduceTextView_textSize,                DensityUtils.sp2px(context, mTextSize));        mVerticalPadding = ta.getDimensionPixelSize(R.styleable                .IncreaseReduceTextView_verticalPadding, DensityUtils.dp2px(context,                mVerticalPadding));        mHorizontalPadding = ta.getDimensionPixelSize(R.styleable                .IncreaseReduceTextView_horizontalPadding, DensityUtils.dp2px(context,                mHorizontalPadding));        mViewSpace = ta.getDimensionPixelSize(R.styleable.IncreaseReduceTextView_viewSpace,                mViewSpace);        ta.recycle();        Paint paint = new Paint();        paint.setTextSize(mTextSize);        mTargetWidth = (int) paint.measureText("00");        initializeView();    }    // 初始化视图    private void initializeView() {        LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT,                LayoutParams.MATCH_PARENT);        mMinusImageButton = new ImageView(mContext);        mMinusImageButton.setLayoutParams(params);        mMinusImageButton.setImageResource(R.mipmap.icon_minus_rounded_square);        mMinusImageButton.setOnClickListener(new OnClickListener() {            @Override            public void onClick(View v) {                if (number > 1) {                    number--;                    numberChanged();                }            }        });        addView(mMinusImageButton);        mNumberTextView = new TextView(mContext);        LayoutParams editLayoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams                .WRAP_CONTENT);        mNumberTextView.setLayoutParams(editLayoutParams);        mNumberTextView.setBackgroundResource(mBackground);        mNumberTextView.setPadding(mHorizontalPadding, mVerticalPadding, mHorizontalPadding,                mVerticalPadding);        mNumberTextView.setGravity(Gravity.CENTER);        mNumberTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextSize);        mNumberTextView.setText(String.valueOf(number));        mNumberTextView.setOnClickListener(this);        addView(mNumberTextView);        mAddImageButton = new ImageView(mContext);        mAddImageButton.setLayoutParams(params);        mAddImageButton.setImageResource(R.mipmap.icon_add_rounded_square);        mAddImageButton.setOnClickListener(new OnClickListener() {            @Override            public void onClick(View v) {                if (number < 999) {                    number++;                    numberChanged();                }            }        });        addView(mAddImageButton);        numberChanged();    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        measureChildren(widthMeasureSpec, heightMeasureSpec);        int widthSum;   // 总宽度, 最终结果为自定义组件的宽度        // 处理中间的TextView        View middleView = getChildAt(1);        int childHeight = middleView.getMeasuredHeight();        int childWidth = middleView.getMeasuredWidth();        widthSum = childWidth + mTargetWidth;        middleView.measure(MeasureSpec.makeMeasureSpec(childWidth + mTargetWidth, MeasureSpec                .EXACTLY), MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.EXACTLY));        // 处理左右ImageView,重新计算其尺寸        int count = getChildCount();        for (int i = 0; i < count; i++) {            if (i == 1) continue;            View child = getChildAt(i);            int ms = MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.EXACTLY);            child.measure(ms, ms);            widthSum = widthSum + childHeight;        }        // 设置组件自身尺寸, 总宽度再加上两个间距(间距默认为0)        setMeasuredDimension(widthSum + mViewSpace * 2, childHeight);    }    @Override    protected void onLayout(boolean changed, int l, int t, int r, int b) {        int childCount = getChildCount();        int left = 0;        for (int i = 0; i < childCount; i++) {            View childView = getChildAt(i);            int childWidth = childView.getMeasuredWidth();            int childHeight = childView.getMeasuredHeight();            childView.layout(left, 0, left + childWidth, childHeight);            left += childWidth;            if (i != childCount - 1) {                left += mViewSpace;            }        }    }    public void setNumber(int number) {        this.number = number;        numberChanged(false);    }    private void numberChanged() {        numberChanged(true);    }    private void numberChanged(boolean isTriggerChanged) {        mNumberTextView.setText(String.valueOf(number));        if (mOnNumberChangeListener != null && isTriggerChanged) {            mOnNumberChangeListener.onNumberChange(number);        }        if (number <= 1) {            mMinusImageButton.setImageResource(R.mipmap.icon_minus_rounded_square_grey);        } else {            mMinusImageButton.setImageResource(R.mipmap.icon_minus_rounded_square);        }    }    public int getNumber() {        return this.number;    }    @Override    public void onClick(View v) {        PurchaseQuantityDialogFragment pqFragment = new PurchaseQuantityDialogFragment();        pqFragment.setInitNumber(this.number);        pqFragment.setOnInputCompleteListener(new PurchaseQuantityDialogFragment                .OnInputCompleteListener() {            @Override            public void onInputComplete(String data) {                number = Integer.parseInt(data);                numberChanged();            }        });        pqFragment.show(((FragmentActivity) mContext).getSupportFragmentManager(),                "DialogFragment");    }    // ------------------- 数值更改回调接口 -------------------    private OnNumberChangeListener mOnNumberChangeListener;    public void setOnNumberChangeListener(OnNumberChangeListener listener) {        mOnNumberChangeListener = listener;    }    public interface OnNumberChangeListener {        void onNumberChange(int number);    }}

代码还算清晰,首先是读取自定义属性;然后初始化控件内容,测量各内部控件的尺寸,并将它们摆放好;最后注册事件监听器。

弹出对话框DialogFragment

在点击控件TextView时将弹出一个AlertDialog,用户可以直接输入一个数字;点击确定可以将用户输入更新到控件的TextView中,弹出对话框在这里使用DialogFragment来实现,代码如下所示:

package com.witmoon.xmb.activity.common.fragment;import android.app.AlertDialog;import android.app.Dialog;import android.content.Context;import android.content.DialogInterface;import android.os.Bundle;import android.support.annotation.NonNull;import android.support.v4.app.DialogFragment;import android.support.v7.widget.AppCompatEditText;import android.text.InputFilter;import android.text.InputType;import android.text.TextUtils;import android.view.Gravity;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.EditText;import android.widget.LinearLayout;import com.witmoon.xmb.R;import com.witmoon.xmb.util.DensityUtils;/** * 数量增减对话框 * Created by zhyh on 2015/6/6. */public class PurchaseQuantityDialogFragment extends DialogFragment {    private OnInputCompleteListener mOnInputCompleteListener;    public void setOnInputCompleteListener(OnInputCompleteListener listener) {        mOnInputCompleteListener = listener;    }    private EditText mEditText;    private String mInitInput;    @NonNull    @Override    public Dialog onCreateDialog(Bundle savedInstanceState) {        LayoutInflater inflater = getActivity().getLayoutInflater();        View view = inflater.inflate(R.layout.layout_purchase_quantity, null);//        View view = createView(getActivity());        mEditText = (EditText) view.findViewById(R.id.edit);        mEditText.setText(mInitInput);        mEditText.selectAll();        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());        builder.setView(view).setTitle("修改购买数量").setPositiveButton(R.string.text_confirm, new                DialogInterface.OnClickListener() {                    @Override                    public void onClick(DialogInterface dialog, int which) {                        String data = mEditText.getText().toString();                        if (isInputValid(data)) {                            if (mOnInputCompleteListener != null) {                                mOnInputCompleteListener.onInputComplete(data);                            }                            dialog.dismiss();                        }                    }                }).setNegativeButton(R.string.text_cancel, null);        return builder.create();    }    // 创建对话框View    private View createView(Context context) {        LinearLayout layout = new LinearLayout(context);        layout.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,                ViewGroup.LayoutParams.MATCH_PARENT));        layout.setGravity(Gravity.CENTER);        AppCompatEditText editText = new AppCompatEditText(context);        editText.setFilters(new InputFilter[]{new InputFilter.LengthFilter(3)});        editText.setInputType(InputType.TYPE_CLASS_NUMBER);        editText.setId(R.id.edit);        editText.setGravity(Gravity.CENTER_HORIZONTAL);        editText.setPadding(12, 0, 12, 0);        editText.setMinWidth(DensityUtils.dp2px(context, 40));        layout.addView(editText, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,                ViewGroup.LayoutParams.WRAP_CONTENT));        return layout;    }    // 设置初始值    public void setInitNumber(int number) {        this.mInitInput = String.valueOf(number);    }    private boolean isInputValid(String input) {        if (TextUtils.isEmpty(input)) {            return false;        }        if (!input.matches("\\d+")) {            return false;        }        try {            return Integer.parseInt(input) > 0;        } catch (NumberFormatException e) {            return false;        }    }    public interface OnInputCompleteListener {        void onInputComplete(String data);    }}

DiaglogFragment所使用的xml布局文件

接下来还有一个上面DialogFragment要使用的XML布局文件,内容很简单,仅仅是一个EditText控件而已,如下所示:

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"              android:layout_width="match_parent"              android:layout_height="wrap_content"              android:gravity="center"              android:paddingTop="12dp"              android:orientation="vertical">    <android.support.v7.widget.AppCompatEditText        android:id="@+id/edit"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:gravity="center"        android:inputType="number"        android:maxLength="3"        android:background="@drawable/bg_input_area"        android:minWidth="48dp"        android:padding="4dp"/></LinearLayout>
0 0
原创粉丝点击