✍️作者简介:沫小北/码农小北(专注于Android、Web、TCP/IP等技术方向)
博客主页: 开源中国、稀土掘金、51cto博客、博客园、知乎、简书、慕课网、CSDN
如果文章对您有一定的帮助请关注✨、点赞、收藏、评论。
如需转载请参考【转载须知】
本文将介绍一个自定义的CounterView控件,展示了如何创建一个可定制的数字输入控件,该控件可以设置最小值、最大值、步进值以及其他属性。
CounterView控件由以下几个元素组成:
减少按钮(decreaseButton):用于递减数值。
增加按钮(increaseButton):用于递增数值。
数值编辑框(valueEditText):用于显示和编辑数值。
自定义视图(customView):用于显示自定义内容(如果需要)。
CounterView控件具有以下属性:
最小值(minValue):控制数值的最小允许值。
最大值(maxValue):控制数值的最大允许值。
步进值(increment):控制递增或递减时的步长。
默认值(defaultValue):控件的初始数值。
小数位数控制(decimalEnabled和decimalPlaces):控制是否允许输入小数以及小数位数的限制。
CounterView控件具有以下功能:
支持递增和递减操作。
限制输入数值的范围在最小值和最大值之间。
支持小数输入,可以根据需要设置小数位数。
提供数值变化的监听器,可以在数值变化时进行相应的操作。
主要方法
以下是CounterView控件中的一些重要方法的简要说明:
方法 | 功能 |
---|---|
init | 初始化控件的各个元素,包括按钮、编辑框和自定义视图 |
applyAttributes | 用于应用从XML布局中传递的属性 |
setDefaultValue | 设置控件的默认数值 |
setMinValue | 设置数值的最小 |
setMaxValue | 设置最大值限制 |
setIncrement | 设置递增或递减的步长 |
setValue | 设置控件显示的数值 |
decreaseValue | 递减数值,并根据设置的范围进行限制和提示 |
increaseValue | 递增数值,并根据设置的范围进行限制和提示 |
setDecimalEnabled | 用于启用或禁用小数输入,并根据设置的小数位数进行限制 |
applyDecimalFilter | 应用小数过滤器,以确保输入的数值符合设置的小数位数要求 |
notifyValueChanged | 在数值发生变化时通知监听器 |
setOnValueChangedListener | 设置数值变化的监听器,以便在数值发生变化时进行相应的操作 |
import android.content.Context;
import android.icu.math.BigDecimal;
import android.text.Editable;
import android.text.InputFilter;
import android.text.InputType;
import android.text.Spanned;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
/**
* Copyright (C) 2023-2024 Author
*
* 数量加减控件
* 前面减号后面加号中间输入
*
* @author xiaolu
* @date 2023/11/8
* @version 1.0.0
*/
public class CounterView extends LinearLayout {
private Button decreaseButton; // 减少按钮
private Button increaseButton; // 增加按钮
private EditText valueEditText; // 数值编辑框
private View customView; // 自定义视图
private BigDecimal minValue = BigDecimal.ZERO; // 最小值
private BigDecimal maxValue = BigDecimal.valueOf(100); // 最大值
private BigDecimal increment = BigDecimal.ONE; // 步进值
private BigDecimal defaultValue = BigDecimal.ZERO; // 默认值
private OnValueChangedListener valueChangedListener; // 数值变化监听器
private boolean decimalEnabled = false; // 是否允许小数
private int decimalPlaces = 0; // 小数位数
/**
* 构造方法,用于创建 CustomCounterView 实例。
*
* @param context 上下文参数,不能为空
*/
public CounterView(Context context) {
super(context);
init(context);
}
/**
* 构造方法,用于创建 CustomCounterView 实例。
*
* @param context 上下文参数,不能为空
* @param attrs 属性参数
*/
public CounterView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
applyAttributes(context, attrs);
}
/**
* 构造方法,用于创建 CustomCounterView 实例。
*
* @param context 上下文参数,不能为空
* @param attrs 属性参数
* @param defStyle 默认样式参数
*/
public CounterView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
applyAttributes(context, attrs);
}
// 初始化方法
private void init(Context context) {
decreaseButton = new Button(context);
decreaseButton.setText("-");
addView(decreaseButton);
valueEditText = new EditText(context);
valueEditText.setInputType(InputType.TYPE_CLASS_NUMBER);
addView(valueEditText);
increaseButton = new Button(context);
increaseButton.setText("+");
addView(increaseButton);
customView = new View(context);
addView(customView);
decreaseButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
decreaseValue();
}
});
increaseButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
increaseValue();
}
});
valueEditText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
try {
BigDecimal currentValue = new BigDecimal(s.toString());
if (currentValue.compareTo(minValue) < 0) {
ToastUtil.showShort("输入数字不能小于最小值 " + minValue);
setEditTextValue(minValue.toString());
} else if (currentValue.compareTo(maxValue) > 0) {
ToastUtil.showShort("输入数字不能大于最大值 " + maxValue);
setEditTextValue(maxValue.toString());
}
} catch (NumberFormatException e) {
e.printStackTrace();
}
}
@Override
public void afterTextChanged(Editable s) {
}
});
}
// 应用属性方法
private void applyAttributes(Context context, AttributeSet attrs) {
}
// 设置默认值方法
public void setDefaultValue(BigDecimal defaultValue) {
this.defaultValue = defaultValue;
setValue(defaultValue);
}
// 设置最小值方法
public void setMinValue(BigDecimal minValue) {
this.minValue = minValue;
}
// 设置最大值方法
public void setMaxValue(BigDecimal maxValue) {
this.maxValue = maxValue;
}
// 设置步进值方法
public void setIncrement(BigDecimal increment) {
this.increment = increment;
}
// 获取当前数值方法
public BigDecimal getValue() {
return BigDecimal.ZERO;
}
// 设置数值方法
public void setValue(BigDecimal value) {
valueEditText.setText(value.toString());
// 将光标移动到文本末尾
valueEditText.setSelection(valueEditText.getText().length());
}
// 更新文本数据方法
private void setEditTextValue(String value) {
valueEditText.setText(value);
// 将光标移动到文本末尾
valueEditText.setSelection(valueEditText.getText().length());
}
// 减少数值方法
private void decreaseValue() {
try {
String input = valueEditText.getText().toString().trim();
if (!input.isEmpty()) {
BigDecimal currentValue = new BigDecimal(input);
BigDecimal newValue = currentValue.subtract(increment);
if (newValue.compareTo(minValue) < 0) {
ToastUtil.showShort("输入数字不能小于最小值 " + minValue);
newValue = minValue;
}
setEditTextValue(newValue.toString());
notifyValueChanged();
}
} catch (NumberFormatException e) {
setEditTextValue("0");
notifyValueChanged();
}
}
// 增加数值方法
private void increaseValue() {
try {
String input = valueEditText.getText().toString().trim();
if (!input.isEmpty()) {
BigDecimal currentValue = new BigDecimal(input);
BigDecimal newValue = currentValue.add(increment);
if (newValue.compareTo(maxValue) > 0) {
ToastUtil.showShort("输入数字不能大于最大值 " + maxValue);
newValue = maxValue;
}
setEditTextValue(newValue.toString());
notifyValueChanged();
}
} catch (NumberFormatException e) {
setEditTextValue("0");
notifyValueChanged();
}
}
/**
* 开启小数输入
* @param decimalEnabled 是否开启 开:true 关:false
* @param decimalPlaces 小数位数控制,如果是-1不控制位数,否则就是小数位数
*/
public void setDecimalEnabled(boolean decimalEnabled, int decimalPlaces) {
this.decimalEnabled = decimalEnabled;
this.decimalPlaces = decimalPlaces;
if (decimalEnabled) {
if (decimalPlaces == -1) {
valueEditText.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL);
} else {
valueEditText.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL | InputType.TYPE_NUMBER_FLAG_SIGNED);
}
} else {
valueEditText.setInputType(InputType.TYPE_CLASS_NUMBER);
}
applyDecimalFilter();
}
private void applyDecimalFilter() {
valueEditText.setFilters(new InputFilter[]{new InputFilter() {
@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
if (decimalEnabled) {
String value = dest.toString().substring(0, dstart) + source.toString() + dest.toString().substring(dend);
if (!value.isEmpty() && !value.equals(".") && !value.equals("-")) {
try {
BigDecimal newValue = new BigDecimal(value);
if (decimalPlaces >= 0 && newValue.scale() > decimalPlaces) {
return "";
}
} catch (NumberFormatException | ArithmeticException e) {
return "";
}
}
}
return null;
}
}});
}
// 通知值已经改变方法
private void notifyValueChanged() {
if (valueChangedListener != null) {
valueChangedListener.onValueChanged(new BigDecimal(valueEditText.getText().toString()));
}
}
// 设置数值变化监听器方法
public void setOnValueChangedListener(OnValueChangedListener listener) {
this.valueChangedListener = listener;
}
// 数值变化监听器接口
public interface OnValueChangedListener {
void onValueChanged(BigDecimal newValue);
}
}
<你的包名.CounterView
android:id="@+id/counterView"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
binding.counterView.setMinValue(BigDecimal.ZERO);
binding.counterView.setMaxValue(BigDecimal.TEN);
binding.counterView.setIncrement(BigDecimal.ONE);
binding.counterView.setDefaultValue(BigDecimal.ZERO);
binding.counterView.setDecimalEnabled(true,2);
binding.counterView.setOnValueChangedListener(new CounterView.OnValueChangedListener() {
@Override
public void onValueChanged(BigDecimal newValue) {
// 在这里处理数值变化事件
Logger.d("CounterViewActivity CounterView onValueChanged 数据变化 " + newValue.toString());
}
});
本文介绍了CounterView控件的基本结构、功能和使用方法,希望对开发人员在创建定制化数字输入控件时有所帮助。通过灵活应用这些方法和功能,可以根据具体的应用需求进行定制和调整,为用户提供更好的应用体验。
无论是哪个阶段,坚持努力都是成功的关键。不要停下脚步,继续前行,即使前路崎岖,也请保持乐观和勇气。相信自己的能力,你所追求的目标定会在不久的将来实现。加油!