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 NumberPickerKotlin extension dialog which scales your Double values into a fitting Int range and converts the Int values back to Doubles 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"