Reputation: 614
Hello guys I am facing a problem with number picker. I have some string that needs to be displayed as
but on select second option 'menu' with select button and reopen the dialog containing number picker the data is being shown something like this
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
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
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
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