About the author: Xiaobei Programming (focusing on HarmonyOS, Android, Java, Web, TCP/IP and other technical directions)
Blog homepage: Open Source China, Rare Earth Nuggets, 51cto Blog, Blog Park, Zhihu, Jianshu, MOOC, CSDN
If the article is helpful to you, please follow, like, collect, and comment.
If you need to reprint, please refer to [Reprint Instructions]
Introduction
This article will introduce a custom CounterView control and show how to create a customizable numeric input control that can set the minimum value, maximum value, step value, and other properties.
Control structure
The CounterView control consists of the following elements:
Decrease button (decreaseButton): used to decrement the value.
Increase button (increaseButton): used to increment the value.
Value edit box (valueEditText): used to display and edit values.
Custom View (customView): used to display custom content (if needed).
Control properties
The CounterView control has the following properties:
Minimum value (minValue): The minimum allowed value of the control value.
Maximum value (maxValue): The maximum allowed value of the control value.
Increment: Controls the step size when increasing or decreasing.
Default value (defaultValue): the initial value of the control.
Decimal place control (decimalEnabled and decimalPlaces): Control whether decimals are allowed to be entered and the limit of decimal places.
Control functions
The CounterView control has the following functions:
Supports increment and decrement operations.
Limits the range of input values to between the minimum and maximum values.
Supports decimal input and can set the number of decimal places as needed.
Provides a listener for value changes, which can perform corresponding operations when the value changes.
main method
The following is a brief description of some important methods in the CounterView control:
Method | Function |
---|---|
init | Initialize each element of the control, including buttons, edit boxes and custom views |
applyAttributes | Used to apply attributes passed from XML layout |
setDefaultValue | Set the default value of the control |
setMinValue | Set the minimum value |
setMaxValue | Set the maximum value limit |
setIncrement | Set increment or decrement The step size |
setValue | Set the value displayed by the control |
decreaseValue | Decrease the value and limit and prompt according to the set range |
increaseValue | Increase the value, and limit and prompt according to the set range |
setDecimalEnabled | Used to enable or disable decimal input and limit it according to the set number of decimal places |
applyDecimalFilter | Apply a decimal filter to ensure that the entered value meets the set decimal place requirements |
notifyValueChanged | Notify the listener when the value changes |
setOnValueChangedListener | Set a listener for value changes to perform corresponding operations when the value changes |
The control code can be modified according to your needs
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 * * Quantity addition and subtraction controls * Enter the minus sign in front and the plus sign in the middle * * @author xiaolu * @date 2023/11/8 * @version 1.0.0 */ public class CounterView extends LinearLayout { private Button decreaseButton; // decrease button private Button increaseButton; // Add button private EditText valueEditText; // Numeric edit box private View customView; // Custom view private BigDecimal minValue = BigDecimal.ZERO; // minimum value private BigDecimal maxValue = BigDecimal.valueOf(100); // maximum value private BigDecimal increment = BigDecimal.ONE; // step value private BigDecimal defaultValue = BigDecimal.ZERO; //Default value private OnValueChangedListener valueChangedListener; // Value change listener private boolean decimalEnabled = false; // Whether to allow decimals private int decimalPlaces = 0; // number of decimal places /** * Constructor, used to create CustomCounterView instances. * * @param context context parameter, cannot be empty */ public CounterView(Context context) { super(context); init(context); } /** * Constructor, used to create CustomCounterView instances. * * @param context context parameter, cannot be empty * @param attrs attribute parameters */ public CounterView(Context context, AttributeSet attrs) { super(context, attrs); init(context); applyAttributes(context, attrs); } /** * Constructor, used to create CustomCounterView instances. * * @param context context parameter, cannot be empty * @param attrs attribute parameters * @param defStyle default style parameters */ public CounterView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context); applyAttributes(context, attrs); } //Initialization method 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("The input number cannot be less than the minimum value" + minValue); setEditTextValue(minValue.toString()); } else if (currentValue.compareTo(maxValue) > 0) { ToastUtil.showShort("The input number cannot be greater than the maximum value " + maxValue); setEditTextValue(maxValue.toString()); } } catch (NumberFormatException e) { e.printStackTrace(); } } @Override public void afterTextChanged(Editable s) { } }); } //Apply attribute method private void applyAttributes(Context context, AttributeSet attrs) { } // Set default value method public void setDefaultValue(BigDecimal defaultValue) { this.defaultValue = defaultValue; setValue(defaultValue); } //Set the minimum value method public void setMinValue(BigDecimal minValue) { this.minValue = minValue; } //Set the maximum value method public void setMaxValue(BigDecimal maxValue) { this.maxValue = maxValue; } // Set step value method public void setIncrement(BigDecimal increment) { this.increment = increment; } // Get the current value method public BigDecimal getValue() { return BigDecimal.ZERO; } //Set numerical method public void setValue(BigDecimal value) { valueEditText.setText(value.toString()); // Move the cursor to the end of the text valueEditText.setSelection(valueEditText.getText().length()); } //Update text data method private void setEditTextValue(String value) { valueEditText.setText(value); // Move the cursor to the end of the text valueEditText.setSelection(valueEditText.getText().length()); } // Reduce numerical method 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("The input number cannot be less than the minimum value" + minValue); newValue = minValue; } setEditTextValue(newValue.toString()); notifyValueChanged(); } } catch (NumberFormatException e) { setEditTextValue("0"); notifyValueChanged(); } } // Add numerical method 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("The input number cannot be greater than the maximum value" + maxValue); newValue = maxValue; } setEditTextValue(newValue.toString()); notifyValueChanged(); } } catch (NumberFormatException e) { setEditTextValue("0"); notifyValueChanged(); } } /** * Enable decimal input * @param decimalEnabled Whether to enable on: true off: false * @param decimalPlaces The number of decimal places is controlled. If it is -1, the number of decimal places is not controlled. Otherwise, it is the number of decimal places. */ 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() & amp; & amp; !value.equals(".") & amp; & amp; !value.equals("-")) { try { BigDecimal newValue = new BigDecimal(value); if (decimalPlaces >= 0 & amp; & amp; newValue.scale() > decimalPlaces) { return ""; } } catch (NumberFormatException | ArithmeticException e) { return ""; } } } return null; } }}); } // Notification value has changed method private void notifyValueChanged() { if (valueChangedListener != null) { valueChangedListener.onValueChanged(new BigDecimal(valueEditText.getText().toString())); } } //Set the value change listener method public void setOnValueChangedListener(OnValueChangedListener listener) { this.valueChangedListener = listener; } // Numeric change listener interface public interface OnValueChangedListener { void onValueChanged(BigDecimal newValue); } }
xml reference
<your package name.CounterView android:id="@ + id/counterView" android:layout_width="wrap_content" android:layout_height="wrap_content" />
Set in code
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) { //Handle value change events here Logger.d("CounterViewActivity CounterView onValueChanged data change " + newValue.toString()); } });
This article introduces the basic structure, functions and usage of the CounterView control, hoping to be helpful to developers when creating customized numeric input controls. By flexibly applying these methods and functions, they can be customized and adjusted according to specific application needs to provide users with a better application experience.
No matter what stage you are at, persistence is the key to success. Don’t stop and keep moving forward. Even if the road ahead is rough, stay optimistic and courageous. Believe in your abilities and the goals you pursue will be achieved in the near future. come on!