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
- Android自定义数值增减控件
- 自定义控件实战<四> 音量增减控件
- MFC 利用Spin控件增减编辑框控件数值
- android自定义控件(二),简易的数值输入器
- SPin控件增减小数
- DEMO:增减控件
- Android 控件 数值选择器 NumberPicker
- Android开发自定义控件实现一个圆形进度条【带数值和动画】
- [Android自定义控件] Android自定义控件
- Android自定义控件] Android自定义控件
- [Android自定义控件] Android自定义控件
- [Android自定义控件] Android自定义控件
- [Android自定义控件] Android自定义控件
- [Android自定义控件] Android自定义控件
- [Android自定义控件] Android自定义控件
- Android 自定义控件 单页翻书控件
- android虚线控件---自定义控件
- android自定义控件实例 --控件
- VGA.DVI.HDMI.DP
- Linux的用户和用户组管理
- 整理的前端UI框架
- Android动画其实并不难
- 学习SQL语句的经验与体会
- Android自定义数值增减控件
- exit, exec, 守护进程
- 利用hadoop中的hdfs作为海量文件服务器的实践
- IOS 生成pem证书方法
- nfs网络文件系统
- Android开发:Json字符串到Json对象万能解析器
- c#获取简单json的值
- 使用G++编译运行c++(by命令行)
- Spring4的IoC和DI的区别