Anand Kumar Jha
Anand Kumar Jha

Reputation: 614

Number picker data is not showing correctly android

Hello guys I am facing a problem with number picker. I have some string that needs to be displayed as enter image description here

but on select second option 'menu' with select button and reopen the dialog containing number picker the data is being shown something like this

enter image description here

Here it can be seen that menu 1 is being shown in both of the Number picker option menu the upper one and the middle one. But on scrolling the correct data is being displayed. The code is as follows

MainActivity

package com.example.anakumar6.numberpickerexample;

import android.app.Dialog;
import android.graphics.Color;
import android.os.Bundle;
import android.app.Activity;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.Window;
import android.widget.Button;
import android.widget.TextView;
import android.widget.NumberPicker;


public class MainActivity extends AppCompatActivity {
    int index =0;
    TextView tv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //Get the widgets reference from XML layout
        tv = (TextView) findViewById(R.id.tv);
        tv.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                showDialog(MainActivity.this);
            }
        });

    }

    public void showDialog(Activity activity){
        final Dialog dialog = new Dialog(activity);
        dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
        dialog.setCancelable(false);
        dialog.setContentView(R.layout.dialog);

        final NumberPicker np = (NumberPicker) dialog.findViewById(R.id.np);

        //Set TextView text color
        tv.setTextColor(Color.parseColor("#FF2C834F"));

        //Initializing a new string array with elements
        final String[] values= {"Menu 1", "Menu", "Menu 2"};
//        modifyDataForNumberPicker(values);


        //Populate NumberPicker values from String array values
        //Set the minimum value of NumberPicker
        np.setMinValue(0); //from array first value
        //Specify the maximum value/number of NumberPicker
        np.setMaxValue(values.length-1); //to array last value

        //Specify the NumberPicker data source as array elements
        np.setDisplayedValues(values);
        np.setValue(index);

        //Gets whether the selector wheel wraps when reaching the min/max value.
        np.setWrapSelectorWheel(true);

        //Set a value change listener for NumberPicker
        np.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
            @Override
            public void onValueChange(NumberPicker picker, int oldVal, int newVal){
                //Display the newly selected value from picker
                tv.setText("Selected value : " + values[newVal]);
                index = newVal;
            }
        });

        Button dialogButton = (Button) dialog.findViewById(R.id.btnClick);
        dialogButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                dialog.dismiss();
            }
        });

        dialog.show();

    }

}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/rl"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ffffff"
    android:padding="16dp"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Select a number..."
        android:textSize="25dp" />
</RelativeLayout>

dialog.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#ffffffff"
    >

    <NumberPicker
        android:id="@+id/np"
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        android:layout_below="@id/tv"
        android:layout_weight="1"/>

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/btnClick"
        android:text="select"/>
</LinearLayout>

I think it is android number picker native issue. Please help me to fix this issue.

Upvotes: 3

Views: 3312

Answers (3)

Rijento
Rijento

Reputation: 41

I think I found what's causing this to happen. Looking in the source code for NumberPicker, within the "getSelectedPos" function (line 1819 at time of writing) we see this:

private int getSelectedPos(String value) {
    if (mDisplayedValues == null) {
        try {
            return Integer.parseInt(value);
        } catch (NumberFormatException e) {
            // Ignore as if it's not a number we don't care
        }
    } else {
        for (int i = 0; i < mDisplayedValues.length; i++) {
            // Don't force the user to type in jan when ja will do
            value = value.toLowerCase();
            if (mDisplayedValues[i].toLowerCase().startsWith(value)) {
                return mMinValue + i;
            }
        }
        /*
         * The user might have typed in a number into the month field i.e.
         * 10 instead of OCT so support that too.
         */
        try {
            return Integer.parseInt(value);
        } catch (NumberFormatException e) {
            // Ignore as if it's not a number we don't care
        }
    }
    return mMinValue;
}

This code is used to take user typed input into the NumberPicker and translate it into an actual value from the provided display strings.

I believe that the for loop in the middle of this function is to blame here. As if a value is a sub-string of a previous value within the display list, it will cause the two to fight over which one is displayed.

There's another function that sets the display while/after scrolling hence why scrolling fixes the visuals.

This is why Anand Kumar Jha's solution works, it causes the subsequent values to no longer be sub-strings of previous ones.

Upvotes: 1

Trần Leo
Trần Leo

Reputation: 455

I have faced the same issue, and I have resolved by determine fixed width for NumberPicker.

<NumberPicker
    android:id="@+id/np"
    android:layout_width="50dp" // <=== replace "wrap_content" with fixed width
    android:layout_height="0dp"
    android:layout_below="@id/tv"
    android:layout_weight="1"/>

Upvotes: 0

Anand Kumar Jha
Anand Kumar Jha

Reputation: 614

I have tried many a workarounds to fix it like extending class, in which there is a function getSelectedPos which returns the position on the base of start with function rather than equals or equalignorecase. But due to being private method of NumberPicker class it can't be done. I also tried other work around that did not work.

Finally I got a simple work around for this issue. I created my own function to modify the data to be set on NumberPicker before set on NumberPicker.

modifyDataForNumberPicker(values);
np.setDisplayedValues(values);

private void modifyDataForNumberPicker(String[] dataList){
        int i=0;
        for(String data : dataList){
            int pos = i++;
            dataList[pos] = data+" ";
        }
    } 

This function prevents any string to be substring of any string from the given array to be set on NumberPicker.

Upvotes: 3

Related Questions