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.
Related
I create a vertical list of textviews with an arraylist and attach on onclicklistener to each one. In the onclick I set code to remove that item. When I click in sequence from the last generated to the first this works fine. But if I remove the first one and then the last one it gives me a null pointer exception. I know this is happening because it is attempting to remove an index that is no longer present, or at least that is what I think is happening. But I cannot figure out how to solve that.
private void generateViews(){
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
final TextView[] textView = new TextView[questionArray.size()];
for(int i = 0; i < questionArray.size(); i++){
final int Index = i;
textView[Index] = new TextView(getActivity());
textView[Index].setText(questionArray.get(i));
textView[Index].setId(Index);
textView[Index].setGravity(Gravity.CENTER);
textView[Index].setPadding(15,15,15,15);
textView[Index].setLayoutParams(params);
textView[i].setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (textView[Index].getId() == (v).getId()) {
questionArray.remove(Index);
answerArray.remove(Index);
saveVariables();
updateViews();
((ViewGroup) textView[Index].getParent()).removeView(textView[Index]);
Toast.makeText(getActivity(), "Question and Answer removed!", Toast.LENGTH_SHORT).show();
}
}
});
mainLayout.addView(textView[Index]);
}
EDIT:
I figured out a small fix but it has it's problems. Instead of removing the items from the arrays with the index I can remove them by searching for the text within the textview.
The problem with this solve is that if my array contains 2 items that are identical then it may remove the wrong index.
questionText = textView[Index].getText().toString();
answerText = textView[Index].getText().toString();
if(questionArray.contains(questionText) && questionArray.size() > 0){
questionArray.remove(questionText);
answerArray.remove(answerText);
}
Solved:
I solved it by first searching for the index of the question text and removing that index from both arrays. The arrays are user generated and I plan on preventing the user from entering the same question twice.
questionText = textView[Index].getText().toString();
int questionIndex = questionArray.indexOf(questionText);
questionArray.remove(questionIndex);
answerArray.remove(questionIndex);
Also, I did it this way because I am still an amateur and was not aware of the Recyclerview. I plan on educating myself on that function and hopefully implementing it.
I really have no idea about why you want do this? if you just want remove textview in a list , why don't you use listview or recyclerview instead ?
You should consider using RecyclerView.
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
I've tried a lot of different ways, most of the suggestions found here, but none of them seems to work. What I'm trying to achieve is at chat area below my game area, a SurfaceView. It is supposed to scroll upwards as new lines are added to the textview.
At first, it looks like a really simple task, but having tried all kinds of suggestions, like a TextView in a ScrollView, like a TextView in a TableRow in a TableLayout in a ScrollView, and so on...I've still not made it happen. Of course this must be something easily achieved in Android, right??
The task is to display like 6 lines of text in the bottom of the screen, and as a new message is added last it should scroll the rest upwards, like a terminal window. The important thing is that it should add the latest message after the other and, when reached the bottom line, scroll the text upwards and add the new line(s) at the end.
Any kind of help or suggestions would be highly appreciated!!
I needed the same behavior in one of my apps and I achieved in just with one command:
view.setGravity(Gravity.BOTTOM);
Or, analogously, setting this attribute in your layout:
android:gravity="bottom"
Then simply add your lines using:
your_text_view.append(newLine);
Suppose, you declared your ScrollView as follows...
private ScrollView mScrollView;
you initialized it as...
mScrollView = (ScrollView) findViewById(R.id.scroll_view_chat_window);
Now, create a method to perform scroll down when you call the method. Inside the method implement a thread which will do the scroll down independently. And call the method after every chat message update thats will do the auto-srcoll functionality.
private void scrollDown() {
mScrollView.post(new Runnable() {
#Override
public void run() {
mScrollView.smoothScrollTo(mScrollView.getScrollY(), mScrollView.getScrollY()
+ mScrollView.getHeight());
}
});
}
I've achieved this (crudely!) by maintaining my own list, deleting the lowest element then adding at the end each time. Here i've just got a 3 line window:
public class MessageWindow {
private ArrayList <String> msgs;
private Activity parentActivity;
public MessageWindow(Activity act, int allMsgsMax) {
this.parentActivity = act;
msgs = new ArrayList <String> ();
// create empty list elements for initial display
for (int i = 0; i < allMsgsMax; i++){
msgs.add("");
}
}
//
public void put (String msg){
msgs.remove(0);
msgs.add(msg);
// get a handle to the textview 'messages', a 3-line box
TextView t2v = (TextView) parentActivity.findViewById(R.id.messages);
// crappy but you get the idea:
t2v.setText(msgs.get(0) + "\n" + msgs.get(1) + "\n" + msgs.get(2) );
}
then in the activity:
protected MessageWindow messageWindow;
// setup splash screen
messageWindow = new MessageWindow(this, 3);
// write some stuff - row1 will disappear off the top of the box
messageWindow.put ("row1")
messageWindow.put ("row2")
messageWindow.put ("row3")
messageWindow.put ("row4")
I have a spinner with a few values and I fill it from my webservice.
Filling the spinner
int i = 0;
var dropItems = new List<SpinItem2>();
DataRow[] result = myOPTvalues.Tables[0].Select("FieldValue=" + item.FieldValue);
foreach (DataRow row in result)
{
var optItem = new PrevzemSpin();
optItem.FieldValue = row["FieldValue"].ToString();
if (optItem.FieldValue.Equals(""))
optItem.FieldValue = null;
optItem.FieldTextValue = row["FieldTextValue"].ToString();
if (optItem.FieldTextValue.Equals(""))
optItem.FieldTextValue = null;
dropItems.Add(new SpinItem2(i, optItem.FieldValue.ToString(), optItem.FieldTextValue.ToString()));
}
i = 1;
foreach (DataRow row in myOPTvalues.Tables[0].Rows)
{
var optItem = new PrevzemSpin();
optItem.FieldValue = row["FieldValue"].ToString();
if (optItem.FieldValue.Equals(""))
optItem.FieldValue = null;
optItem.FieldTextValue = row["FieldTextValue"].ToString();
if (optItem.FieldTextValue.Equals(""))
optItem.FieldTextValue = null;
if (optItem.FieldValue != item.FieldValue)
{
dropItems.Add(new SpinItem2(i, optItem.FieldValue.ToString(), optItem.FieldTextValue.ToString()));
}
++i;
}
For some reason it acts like the item that was inserted first is "selected" on default and then triggers the ItemSelected event which I use to send the selected but I don't want that.
Since there's quite a number of these spinners on my screen it really slows down the activity plus it also sends the incorrect values to the field and since I use the ItemSelect to detect if everything went OK (let's say the service fell or the values themselves changed on server (someone added a new field on the server application) while the user is completing the form etc.)
Is there someway to tell the app not to trigger that on activity load but on actual user interaction?
I can't speak for Android specifically, but I have encountered this many times with Windows.
The solution I usually use is to simply add a boolean loading variable. Set it to true at the beginning of your initialisation and then clear it at the end.
In your event handlers like ItemSelected you can simply check if this is being triggered as the result of the initial load.
private void onItemSelected(....)
{
if(loading)
{
return; //Ignore as form is still loading
}
//Normal event handling logic goes here
....
}
Before I declared GetView:
int LastSpinnerSelectedPosition;
Inside my spinner definition:
LastSpinnerSelectedPosition = 0;
My spinner ItemSelected event:
var CurrentSelectedIndex = SpinnerValue.SelectedItemPosition;
if (CurrentSelectedIndex != LastSpinnerSelectedPosition)
{
// WHATEVER I WANTED TO DO ON ITEM SELECT ANYWAY
// Fix the LastSpinnerSelectedPosition ;)
LastSpinnerSelectedPosition = CurrentSelectedIndex;
}
Simple ;D
Just for clarification, the event fires when an item is selected. The semantics are obviously flawed, but technically the item IS selected when it initially loads since you can then immediately ask the spinner for which item is selected, so as the other answers say, just ignore the first time it is selected since it's guaranteed to be the loading select, and then proceed as normal after that.
I got a simple script:
int phases = 6;
final int max = 8;
final TextView[] a = new TextView[(max * phases)];
final Button[] b = new Button[phases]; // creates the buttons to display
// the single phases
for (int x = 0; x < phases; x++) {
b[x] = new Button(this);
b[x].setText("yourbutton");
// linL.addView(b[x]);
b[x].setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (a[(3)].getVisibility() == 0) {
for (int i = 0; i < max; i++)
a[i].setVisibility(View.GONE);
} else {
for (int i = 0; i < max; i++)
a[i].setVisibility(View.VISIBLE);
}
};
});
}
This checks basically if a textview is visible and if it's not then it makes it visible (plus the other way round).
My problem is now that I don't want to switch the same text views on again and again, I want to change the views depending on the x of the current loop of the button creation.
However, when i try to include this x, it says that it has to be final.
So how do i get parameters into that on click listener script? (I tried to add them, however it said then that I have to program the whole listener again...that's why I'm asking if there's a smarter way to do it)
Cheers, Christoph
You have 2 options:
Before the setOnClickListener line you can declare on another variable as final and you can assign the value of x into it. Then you will have final variable that holds the value of x that it can be used inside the function.
You can implement your own class that implements OnClickListener and you can add a constructor that get the value of x.
Some general notes:
I don't know if this is the way you write code or if you masked it when you wrote it here. (Masked, means that you change the variable names that it will be harder to understand what you are doing)
So, if you masked it, please don't, it make it much harder to answer you.
If this is the way you write code, I really encourage you to read some articles about coding standards and there importance. Your code isn't indent properly and the names of your variables have no meaning. After you finish with that project, try to read your code again a month later, you will see how hard it is for you to understand what you wrote
If I undertstand correctly, you want to pass parameters to your OnClickListener. I would suggest implementing your own OnClickListener interface - similar to rekaszeru's answer here