1

I am trying to create a modified NumberPicker for double/float values with an increment and precision setting so I can increment the values by something other than 1. For my use cases, I have a calculator app that I want to use 2-3 of these NumberPickers to input/select a double value. Some inputs might be on the order of 10,000,000 and others might be small like 0.0001 so I need to be able to adjust the increment step and also the precision for each picker. Since there could be a very large range of values I don't want to use setDisplayedValues. I also want to allow the user to input numbers directly through the EditText on the NumberPicker.

This is what I have so far for my NumberPickerDouble class:

import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.text.InputFilter;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.NumberPicker;

import java.math.BigDecimal;

public class NumberPickerDouble extends NumberPicker {
    private double mPrecision = 1;
    private double mIncrement = 1;
    private EditText numberEditText;
    private boolean shouldDisableEditText = true; //set to true to disable edit text input and focus

    public NumberPickerDouble(Context context) {
        super(context);
    }

    public NumberPickerDouble(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(attrs);
    }

    public NumberPickerDouble(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(attrs);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public NumberPickerDouble(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init(attrs);
    }

    private void init(AttributeSet attrs){
        numberEditText = populateEditText((ViewGroup) this);
        if (numberEditText != null && shouldDisableEditText)
            numberEditText.setFocusable(false);
        processAttributeSet(attrs);
    }

    public void setPrecision(double precision){
        mPrecision = precision;
    }

    public double getPrecision(){
        return mPrecision;
    }

    public void setIncrement(double increment) {
        mIncrement = increment;
        setFormat();
    }

    public double getIncrement(){
        return mIncrement;
    }

    public String getValueFormat(){
        int decimalPlaces = BigDecimal.valueOf(mPrecision).scale();
        if (decimalPlaces > 0)
            return "%." + String.valueOf(decimalPlaces) + "f";
        else
            return "%d";
    }

    public void setDoubleValue(double value){
        setValue((int)(value / mIncrement));
        numberEditText.setFilters(new InputFilter[0]);
    }

    private void setFormat() {
        NumberPicker.Formatter formatter = new NumberPicker.Formatter(){
            @Override
            public String format(int value) {
                double temp = value * mIncrement;
                int precision = BigDecimal.valueOf(mPrecision).scale();
                String newValue;
                if (precision > 0)
                    newValue = String.format("%." + precision +"f", temp);
                else
                    newValue = "" + temp;
                return newValue;

            }
        };
        setFormatter(formatter);
    }

    private EditText populateEditText(ViewGroup viewGroup) {
        int count = viewGroup.getChildCount();
        for (int i = 0; i < count; i++) {
            final View child = viewGroup.getChildAt(i);
            if (child instanceof ViewGroup)
                populateEditText((ViewGroup) child);
            else if (child instanceof EditText)
                return (EditText) child;
        }
        return null;
    }

    private void processAttributeSet(AttributeSet attrs) {

    }
}

The increment and precision work as expected for swiping but I have two issues:

  1. Upon first initializing the view, the NumberPickers don't format the first value properly and it either leaves out the decimal or it displays nothing (see image below). Once I scroll the picker, it goes away. I tried some of the proposed solutions in this post but nothing seems to work. NumberPicker formatter not working on first rendering

  2. I can't input numbers in the EditText of the NumberPicker but even if I could, I can't figure out how to best intercept the input value to divide it by the increment like I have in my setDoubleValue method.

Here is how I am setting up the NumberPickers in the image above:

final NumberPickerDouble np1 = (NumberPickerDouble) v.findViewById(R.id.numPicker1);
final NumberPickerDouble np2 = (NumberPickerDouble) v.findViewById(R.id.numPicker2);
final NumberPickerDouble np3 = (NumberPickerDouble) v.findViewById(R.id.numPicker3);

np1.setMaxValue(1000000);
np2.setMaxValue(200000);
np3.setMaxValue(200);

np1.setMinValue(0);
np2.setMinValue(0);
np3.setMinValue(0);

np1.setPrecision(1);
np2.setPrecision(1);
np3.setPrecision(0.001);

np1.setIncrement(100);
np2.setIncrement(1);
np3.setIncrement(0.002);

np1.setWrapSelectorWheel(false);
np2.setWrapSelectorWheel(false);
np3.setWrapSelectorWheel(false);

np1.setDoubleValue(0);
np1.setDoubleValue(0);
np1.setDoubleValue(0);
Community
  • 1
  • 1
JoeDaddy7105
  • 31
  • 1
  • 6
  • I think I just stopped the issue to solve problem number 1. I call setDoubleValue for the first NumberPicker (np1) three times in a row ideas of calling it for each so only the first one is getting the fix on first rendering. I'll fix that in the morning but if still be curious what solutions for problem 2 are. – JoeDaddy7105 Apr 20 '16 at 05:22

0 Answers0