Android Numberpicker Decimals
Solution 1:
You can do it with custom strings:
NumberPickerpicker=newNumberPicker(this);
picker.setMinValue(0);
picker.setMaxValue(100);
picker.setDisplayedValues( newString[] { "0.0", "0.1", ..., "10.0" } );
double = picker.getValue() / 10.0;
Solution 2:
You can create your own DecimalPicker view based on ElegantNumberButton. Add following classes to your project:
/path/to/your/DecimalPicker.java
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.util.Locale;
import ru.alanov.cashbox.R;
import ru.alanov.cashbox.Utils;
publicclassDecimalPickerextendsRelativeLayout {
private Context context;
private AttributeSet attrs;
privateint styleAttr;
private OnClickListener mListener;
privatedouble initialNumber, finalNumber, lastNumber, currentNumber;
private EditText editText;
private String format;
private OnValueChangeListener onValueChangeListener;
publicDecimalPicker(Context context) {
super(context);
this.context = context;
initView();
}
publicDecimalPicker(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
this.attrs = attrs;
initView();
}
publicDecimalPicker(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.context = context;
this.attrs = attrs;
this.styleAttr = defStyleAttr;
initView();
}
privatevoidinitView(){
inflate(context, R.layout.decimal_picker, this);
finalResourcesres= getResources();
finalintdefaultColor= res.getColor(R.color.colorPrimary);
finalintdefaultTextColor= res.getColor(R.color.colorText);
finalDrawabledefaultDrawable= res.getDrawable(R.drawable.decimal_picker_shape);
TypedArraya= context.obtainStyledAttributes(attrs, R.styleable.DecimalPicker, styleAttr, 0);
initialNumber = a.getInt(R.styleable.DecimalPicker_initialNumber, 0);
finalNumber = a.getInt(R.styleable.DecimalPicker_finalNumber, Integer.MAX_VALUE);
floattextSize= a.getDimension(R.styleable.DecimalPicker_textSize, 24);
intcolor= a.getColor(R.styleable.DecimalPicker_backGroundColor,defaultColor);
inttextColor= a.getColor(R.styleable.DecimalPicker_textColor,defaultTextColor);
Drawabledrawable= a.getDrawable(R.styleable.DecimalPicker_backgroundDrawable);
ButtonbuttonMinus= (Button) findViewById(R.id.subtract_btn);
ButtonbuttonPlus= (Button) findViewById(R.id.add_btn);
editText = (EditText) findViewById(R.id.number_counter);
editText.setOnEditorActionListener(newTextView.OnEditorActionListener() {
@OverridepublicbooleanonEditorAction(TextView v, int actionId, KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_DONE || actionId == EditorInfo.IME_ACTION_NEXT) {
Stringnum= ((EditText) v).getText().toString();
setNumber(num, true);
}
returnfalse;
}
});
editText.addTextChangedListener(newTextWatcher() {
@OverridepublicvoidbeforeTextChanged(CharSequence s, int start, int count, int after) {
}
@OverridepublicvoidonTextChanged(CharSequence s, int start, int before, int count) {
}
@OverridepublicvoidafterTextChanged(Editable s) {
Stringvalue= s.toString().trim();
doublevalueDouble= -1;
try {
valueDouble = parseDouble(value.isEmpty() ? "0" : value);
} catch (NumberFormatException e) {
e.printStackTrace();
}
if (valueDouble >= 0){
lastNumber = currentNumber;
currentNumber = valueDouble;
callListener(DecimalPicker.this);
}
}
});
LinearLayoutmLayout= (LinearLayout) findViewById(R.id.decimal_picker_layout);
buttonMinus.setTextColor(textColor);
buttonPlus.setTextColor(textColor);
editText.setTextColor(textColor);
buttonMinus.setTextSize(textSize);
buttonPlus.setTextSize(textSize);
editText.setTextSize(textSize);
if (drawable == null){
drawable = defaultDrawable;
}
assert drawable != null;
drawable.setColorFilter(newPorterDuffColorFilter(color, PorterDuff.Mode.SRC));
if (Build.VERSION.SDK_INT > 16)
mLayout.setBackground(drawable);
else
mLayout.setBackgroundDrawable(drawable);
editText.setText(String.valueOf(initialNumber));
currentNumber = initialNumber;
lastNumber = initialNumber;
buttonMinus.setOnClickListener(newView.OnClickListener() {
@OverridepublicvoidonClick(View mView) {
doublenum= parseDouble(editText.getText().toString());
setNumber(String.valueOf(num - 1)/*, true*/);
}
});
buttonPlus.setOnClickListener(newView.OnClickListener() {
@OverridepublicvoidonClick(View mView) {
doublenum= parseDouble(editText.getText().toString());
setNumber(String.valueOf(num + 1)/*, true*/);
}
});
a.recycle();
}
privatevoidcallListener(View view){
if (mListener != null)
mListener.onClick(view);
if (onValueChangeListener != null && lastNumber != currentNumber)
onValueChangeListener.onValueChange(this, lastNumber, currentNumber);
}
public String getNumber(){
return String.valueOf(currentNumber);
}
publicvoidsetNumber(String number) {
try {
doublen= parseDouble(number);
if (n > finalNumber)
n = finalNumber;
if (n < initialNumber)
n = initialNumber;
if (format != null) {
Stringnum= String.format(Utils.getCurrentLocale(getContext()), format, n);
num = removeTrailingZeroes(num);
editText.setText(num);
} else
editText.setText(String.valueOf(number));
lastNumber = currentNumber;
currentNumber = parseDouble(editText.getText().toString());
} catch (NumberFormatException e) {
e.printStackTrace();
}
}
privatedoubleparseDouble(String str)throws NumberFormatException {
return Double.parseDouble(str.replace(",","."));
}
private String removeTrailingZeroes(String num) {
NumberFormatnf= NumberFormat.getInstance();
if (nf instanceof DecimalFormat) {
DecimalFormatSymbolssym= ((DecimalFormat) nf).getDecimalFormatSymbols();
chardecSeparator= sym.getDecimalSeparator();
String[] split = num.split((decSeparator == '.' ? "\\" : "") + String.valueOf(decSeparator));
if (split.length == 2 && split[1].replace("0", "").isEmpty())
num = split[0];
}
return num;
}
publicvoidsetNumber(String number, boolean notifyListener){
setNumber(number);
if (notifyListener)
callListener(this);
}
publicvoidsetOnClickListener(OnClickListener onClickListener) {
mListener = onClickListener;
}
publicvoidsetOnValueChangeListener(OnValueChangeListener onValueChangeListener){
this.onValueChangeListener = onValueChangeListener;
}
publicinterfaceOnClickListener {
voidonClick(View view);
}
publicinterfaceOnValueChangeListener {
voidonValueChange(DecimalPicker view, double oldValue, double newValue);
}
publicvoidsetRange(Double startingNumber, Double endingNumber) {
initialNumber = startingNumber;
finalNumber = endingNumber;
}
publicvoidsetFormat(String format){
this.format = format;
}
}
/layout/decimal_picker.xml
<?xml version="1.0" encoding="utf-8"?><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:orientation="horizontal"android:layout_gravity="center_horizontal"android:layout_width="wrap_content"android:id="@+id/decimal_picker_layout"android:layout_height="wrap_content"><Buttonandroid:id="@+id/subtract_btn"android:layout_weight="1"android:layout_width="0dp"android:layout_height="match_parent"android:text="-"android:background="@android:color/transparent" /><EditTextandroid:id="@+id/number_counter"android:gravity="center"android:imeOptions="flagNoExtractUi"android:inputType="numberDecimal"android:text = "1"android:layout_weight="1"android:layout_width="0dp"android:layout_height="match_parent"android:background="@android:color/transparent" /><Buttonandroid:id="@+id/add_btn"android:layout_weight="1"android:layout_width="0dp"android:layout_height="match_parent"android:text="+"android:background="@android:color/transparent" /></LinearLayout>
/drawable/decimal_picker_shape.xml
<?xml version="1.0" encoding="utf-8"?><shapexmlns:android="http://schemas.android.com/apk/res/android"android:shape="rectangle"><cornersandroid:radius="4dp" /></shape>
/values/attrs.xml
<?xml version="1.0" encoding="utf-8"?><resources><declare-styleablename="DecimalPicker"><attrname="backGroundColor"format="color"/><attrname="initialNumber"format="integer"/><attrname="finalNumber"format="integer" /><attrname="textColor"format="color"/><attrname="textSize"format="dimension"/><attrname="backgroundDrawable"format="reference"/><attrname="decimalFormat"format="reference"/></declare-styleable></resources>
In /values/colors.xml add <color name="colorText">#FFFFFF</color>
Usage example:
In your activity layout place
<path.to.your.DecimalPicker
android:id="@+id/decimal_picker"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16sp"/>
In your Activity#onCreate()
place
DecimalPickerdecimalPicker= (DecimalPicker) view.findViewById(R.id.decimal_picker);
decimalPicker.setFormat("%.3f");//Weight format
decimalPicker.setOnValueChangeListener(newDecimalPicker.OnValueChangeListener() {
@OverridepublicvoidonValueChange(DecimalPicker picker, double oldValue, double newValue) {
//Do what you want to handle value change.
}
});
The result of efforts:
Click on +/- will change integer part of number. If you want to change fractional part - click on number and edit it by hands. If there is no fractional part you will see a integer part only without zeroes.
Solution 3:
Alternatively you can use this handy NumberPicker
Kotlin extension dialog which scales your Double
values into a fitting Int
range and converts the Int
values back to Double
s before calling any of the callback. It basicallly hides away the fact that NumberPicker
only supports Int
and adds support for Double
!
Here's the Fragment extension you need to copy & paste:
fun Fragment.showNumberPickerDialog(
title: String,
value: Double,
range: ClosedRange<Double>,
stepSize: Double,
formatToString: (Double) -> String,
valueChooseAction: (Double) -> Unit
) {
val numberPicker = NumberPicker(context).apply {
setFormatter { formatToString(it.toDouble() * stepSize) }
wrapSelectorWheel = false
minValue = (range.start / stepSize).toInt()
maxValue = (range.endInclusive / stepSize).toInt()
this.value = (value.toDouble() / stepSize).toInt()
// NOTE: workaround for a bug that rendered the selected value wrong until user scrolled, see also: https://stackoverflow.com/q/27343772/3451975
(NumberPicker::class.java.getDeclaredField("mInputText").apply { isAccessible = true }.get(this) as EditText).filters = emptyArray()
}
MaterialAlertDialogBuilder(context)
.setTitle(title)
.setView(numberPicker)
.setPositiveButton("OK") { _, _ -> valueChooseAction(numberPicker.value.toDouble() * stepSize) }
.setNeutralButton("Cancel") { _, _ -> /* do nothing, closes dialog automatically */ }
.show()
}
Then use it like this:
showNumberPickerDialog(
title = "Your Weight",
value = 75.0, // in kilogramsrange = 10.0 .. 300.0,
formatToString = { "$it kg" },
valueChooseAction = { saveNewWeight(it) }
)
Post a Comment for "Android Numberpicker Decimals"