Skip to content Skip to sidebar Skip to footer

Android Numberpicker Decimals

I'm trying to create a numberpicker in Android but the wheel only increase by 1. I want to increase by 0.1. I've looked up on the net but I've found a formated array of floats disa

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: enter image description here 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"