I've created a dialog containing two NumberPicker views. The first contains a list of groups, the second contains the items from the selected group:
Group Group Items
1 2: Group 2 Item 2
[2] [3: Group 2 Item 3]
3 4: Group 2 Item 4
I'm hooking in to the setOnValueChangedListener in the first NumberPicker to populate the second NumberPicker.
mNumberPickerGroup.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
#Override
public void onValueChange(NumberPicker numberPicker, int from, int to) {
int size = mData.getItemsForGroup(to).size();
String[] strings = mData.getItemTitlesForGroup(to);
mNumberPickerItems.setMinValue(1);
mNumberPickerItems.setValue(1);
mNumberPickerItems.setMaxValue(size);
mNumberPickerItems.setDisplayedValues(strings);
}
});
This basically works - until, in certain circumstances, changing the group a few times can cause a crash in the NumberPicker class, when setting the setDisplayedValues strings.
The error is an array index out of bounds exception in the numberpicker for items, a line to do with the string array I passed in. I've set a break point in the update code above, and verified that the String array is always the correct size for the number of items set between min and max value on the number picker, so this has stumped me.
java.lang.ArrayIndexOutOfBoundsException: length=22; index=22
at android.widget.NumberPicker.ensureCachedScrollSelectorValue(NumberPicker.java:1768)
at android.widget.NumberPicker.initializeSelectorWheelIndices(NumberPicker.java:1583)
at android.widget.NumberPicker.setMaxValue(NumberPicker.java:1390)
at uk.co.my.app.fragments.GroupMarkUptoDialog.updateItemPicker(MarkUptoDialog.java:99)
I'm about to start reading through what happens in the NumberPicker to figure out if I'm using it wrong, but any suggestions would be welcome. "ensureCachedScrollSelectorValue" makes me think I need to reset the numberpicker somehow before updating it with new data but I'm not sure.
Can anyone see what I'm doing wrong here?
I realise the NumberPicker is not really a String picker, so if anyone has a better suggestion for how to achieve this sort of UI I'm all ears. Otherwise, I'm heading down the route of trying to implement some kind of debouncer, to update the items picker once all activity on the group picker is complete.
It happens when you setDisplayedValue(String[]) many times.
If the string[]'s length is larger than the current getMaxValue(), Exception happens!
My solution
use
picker.setMaxValue(0);
before
picker.setDisplayedValues(stringArr);
My code
cityPicker.setMaxValue(0);
try {
cityPicker.setDisplayedValues(citySet.toArray(new String[citySet.size()]));
} catch (Exception e) {
Log.e("Ninja", "cityPicker.setDisplayedValues(citys) occurs Error. province is " + province);
}
cityPicker.setMaxValue(citySet.size() - 1);
If you use indexes started from 1 then use:
int size = mData.getItemsForGroup(to-1).size();
Use this to change second picker (if current value is above maximum it will set it to new maximum):
int i = mNumberPickerItems.getValue();
int max = strings.length;
if (i > max)
i = max;
mNumberPickerItems.setMinValue(1);
mNumberPickerItems.setMaxValue(1);
mNumberPickerItems.setDisplayedValues(strings);
mNumberPickerItems.setMaxValue(max);
mNumberPickerItems.setValue(i);
And try to use values as indexes, i.e.
minValue=0
maxValue=strings.length-1
Related
This is driving me a little mad since I know this should be very simple but I am not getting the desired affect.
I have the following arraylist
private List<String> tagStringArray = new ArrayList<>();
Then later I have a method that creates dynamic buttons, based on ID values pulled across from my Retrofit instance.
In my method, I have a count to help me set the title of the button but I also add the values of count to an ArrayList for use in another method.
I have taken a snip of relevant information from the method mentioned.
count = 1;
if (!questionNumber.equals("") && !questionNumber.equals(null)) {
for (final Object value : list) {
try {
/*Dynamically create new Button which includes the question number
*/
final AppCompatButton btn_question = new AppCompatButton(getActivity());
/*LayoutParams (int width, int height,float weight)
As LayoutParams is defaulted in px, I have called a method called dpToPX to make sure
the dynamically added EditText is the same size on all devices.
*/
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(dpToPx(280), dpToPx(45), 1);
btn_question.setBackgroundColor(Color.parseColor("#3B5998"));
btn_question.setTextColor(Color.WHITE);
btn_question.setText("Question "+count);
//set the Tag based on its position in the XML
tagStringArray.add(String.valueOf((count)));
count++;
If a user clicks on say Question 1 Button, I want my fragment to say Question 1, so to try and achieve that, I have tried doing the following:
String tags = String.valueOf(tagStringArray);
tags = tags.substring(1, tags.length() -1);
String[] currentTag = tags.split(",");
if (currentTag[0].contains("1")) {
tv_setQuestions_edit.setText("Question 1");
}else if(currentTag[1].contains("2")) {
tv_setQuestions_edit.setText("Question 2");
}
But this will always set the title to Question 1 and I am not sure what is going wrong.......
If I use the following toast Toast.makeText(getActivity(), Arrays.toString(currentTag), Toast.LENGTH_LONG).show(); it shows [1,2] so I know they are being added ok.
I did look into using tags by doing:
public static int KEY_COUNT=0; public static int KEY_VALUE=1;
btn_question.setTag(KEY_VALUE,value);
btn_question.setTag(KEY_COUNT,count);
But for some reason, when I add more than one tag (as I need a minimum of 2), my dynamic button is missing from the layout. But for some reason when only 1 tag - like this btn_question.setTag(value); is used, it shows up fine (I have a feeling its some issue with my fragment). Therefore I am trying to think of a workaround in the meantime.
Any help or guidance would be really appreciated.
It's because
currentTag[0].contains("1")
is always true. The first item of currentTag always contains "1".
Instead of doing this, why don't you just do String titleForFragment = myButton.getText() in the onClick method for the button? That way, you can set the same onClickListener on all the buttons, and it will reduce the amount of code you need to write.
I have a string array :
private String [] arrFilePaths=new String[4];
and I have a funtion which returns strings and im adding that to array:
#Override
public void accept(List<File> files) throws Exception {
int size = files.size();
while (size-- > 0) {
arrFilePaths[size]=files.get(size).toString();
}
}
Now i have a button and I am accessing array inside of it:
#Override
public void onClick(View v) {
if(arrFilePaths[0]==null){
//some code
}else {
//some code
}
Now the problem is arrFilePaths only return strings in button click sometime. most of time its returning null.The data always getting inserted to array before button click. so i dont know whats going on.
Yes i have tested in debug mode and arrFilePathsis getting data inserted, but somehow after the button click it saying null(even though I am using same variable).
Can anyone explain about this weird output? Thanks!
As far as I can see, you will be getting null every time when your List<File> files has fewer elements than arrFilePaths array.
Imagine this is files list [L1 , L2 , L3]
And your array is [A1 , A2 , A3 , A4 , A5 , A6]
As you're writing from end, the last element from the end of files will appear at last position of arrFilePaths so on so force.
Finally, array will look like [null, null, null, L1 , L2 , L3].
Obviously, the 1st element of this array will be null.
I am not sure how you are seeing the values sometimes because to me it seems like a logical problem in below code
while (size-- > 0) {
arrFilePaths[size]=files.get(size).toString();
}
Lets assume your size is 3 so you travel here in the reverse order. So you fill the position 3 and 2 and 1 but as soon as size becomes 0, your condition fails and it never sets the value for 0th element.
then your if condition checks -
if(arrFilePaths[0]==null)
So its checking if 0th element is null which is obviously the case because your while loop didn't let it enter there. hence no data.
so if your size is more than 4 in that case your 0th element will get filled as your arrFilePaths can only take 4 elements
In my opinion you should Modify this line
while (size-- > 0)
like this
while (size-- >= 0) {
Just replace that while with a fori, I don't see any reason at all why you would want to populate that array from the end to the front.
I want to change dinamically the list entries and entryvalues of a listpreference. Well, finally it works, the list changes, but the problem is that I can see the new values only when I click the second time or more in the listpreference in the preference screen.
The first time, the list is always the original list, from 1 to 10.
numeroIntentosLP.setOnPreferenceClickListener(new OnPreferenceClickListener()
{
#Override
public boolean onPreferenceClick(Preference preference)
{
CharSequence[] NuevosValores = new String[10 - LineaActual];
int Indice = 0;
for(int i = LineaActual + 1; i <= 10; i++)
{
NuevosValores[Indice++] = String.valueOf(i);
}
numeroIntentosLP.setEntries(NuevosValores);
numeroIntentosLP.setEntryValues(NuevosValores);
return true;
}
});
I have tried with numeroIntentosLP.setOnPreferenceChangeListener, but the same result.
LineaActual is an integer value that I passed from MainActivity to PreferenceActivity. This is useful to me to know the new start value for the list.
So, everytime I open the preference screen and I click for the first time in the listpreference, I always get numbers 1 to 10, but when I click again, no matter how many times, I get what I want, I mean the list from LineaActual to 10.
Thanks in advance.
Ok, I found the solution. It was as easy as put the code directly in the onCreate, not in the listeners.
Thank you samgak, I saw your answer a little bit late and you're right, thank you anyway.
I have 4*7 table and I want to handle every Edit text there , when the user clicks on the 5th edit text for long enough so that the menu pops up he can choose what color he wants.
the problem is how should I do this, I have 4*7 edittexts so I should call registerForContextMenu(View) 28 times even if I did this How can I handle it in onContextItemSelected(menuItem) ?
I don't want to put the whole fragment's view since everytime the user clicks for too long on any position the menu will pop up , so I don't want that.
Edit:
I tried this in the onCreateContextMenu:
if(v.getId() == R.id.table_item1){
Position = 1;
}
and check for the position in the onContextItemSelected , is there a better way/ faster way than this ? since I'll need to put 28 if there :(
You could name your EditTexts edit1, edit2, edit3 etc.
Then you could do a loop
for(int i=1; i<=28; ++i) {
int resId = getResources.getIdentifier("edit" + i, "id", getPackageName());
EditText edt = (EditText)findViewById(resId);
edt.registerForContextMenu(...)
}
and the same in other places where you have to iterate over your EditTexts
I am dynamically updating my AutoCompleteTextView on every 3rd / 4th letter.
For some reason, about 5-10% of the time when the user types the third letter, though I know for sure I am making a valid arraylist and populating the AutoCompleteTextView, it does not show for unique cases. Something I noticed that was consistent was that the list of words that did not show up were from length 5-15 (others range 50+)
Any idea what is going ? Am I missing something about AutoCompleteTextView, where it doesn't think showing 10 or so suggestions is worth it if the datalist is not as big? Should I add irrelevant filer data or would that impact performance? Thanks
Here is some relevant source code..
Textwatcher for text view checks that;
if (((start + count) == 3) || ((start + count) == 4)
|| ((start == 3) && (before >= 1))) {
if (!last.equals(s)) {
thread = new Thread(new AutoCompleteThread(s));
thread.start();
}
}
in my custom thread I group up words .. then i call this on my text view and adapter;
if(words.size() > 0)
{
last = s;
// adapter.clear();
// for(String e : words)
// adapter.add(e);
// adapter.notifyDataSetChanged();
adapter = new ArrayAdapter<String>(
getActivity(), android.R.layout.simple_list_item_1, words);
textView.setAdapter(adapter);
textView.showDropDown();
}
Turns out there is a weird glitch that happens very often if my dynamically loading list is very small and my original list (which comes from my RES folder) is substantially large (500 or so). It doesn't glitch out when the dynamically loaded list is large, perhaps it gives enough time to the AutoCompleteTextView to show suggestions while loading? Not sure about that.
Anyways, the solution was to lower my original size of the arraylist in my res folder