Loop through all "widgets"/elements in a Activity - java

I started my own android app a few days ago since I needed a mobile application to store a bunch of data I collect in the hospital.
I'm pretty new to Java and android environment, although it seems easy to understand and very similar to C++.
Anyway, my application has a bunch of "EditText" and radio buttons and my question is:
How can I iterate through all those widgets (EditTexts and radio buttons)?
In .NET you could do a "for each element in container " loop but I can't seem to find a way to do this in Java/android environment.
Note: I don't know how many "widgets" exist in the activity, since some are created dinamicaly, others are hardcoded and some others show if some user preferences are set
Any help or hint would be appreciated.

for (int i = 0; i < rootView.getChildCount(); i++)
rootView.getChildAt(i)
Note that this will return View-s, you will have to check at runtime exactly what type of View you are currently looking at

It works.
Regarding the View type (ie Spinner, radioButton, EditText, etc) we can tag each type we want to parse in the Layout XML file and then add a conditional, ie:
if (Widget_Tag != null){
View Current_Widget = (View) rootView.getChildAt(i);
String Widget_Tag = (String) Current_Widget.getTag();
if (Widget_Tag.equals("MyEdiText")) {
//do something
}
}
the if (Widget_Tag != null){ is to prevent NullPointReferences. You can also doi it with a Try / Catch.

You can try this code:
LayoutInflater inflater = getLayoutInflater();
LinearLayout l = (LinearLayout) inflater.inflate(R.layout.main, null);
ViewGroup Current_Widget = (ViewGroup)l.getRootView();
for (int i = 0; i < Current_Widget.getChildCount(); i++)
Current_Widget.getChildAt(i);

Related

I want to add Edit Text dynamically not more not less than 5 Edit Texts in android java

I need to add 5 Input fields (EditText) dynamically one by one on button click and want to take values from them and store them into database using Room Persistence with MVVM.
Here I'm adding the view dynamically
private void addEditTextView() {
View inputView = getLayoutInflater().inflate(R.layout.row_edit_text, null, false);
EditText val1 = inputView.findViewById(R.id.input_value_1);
binding.layoutList.addView(inputView);
}
Any suggestion would be very helpful.
Thank you in advance.
Add view based on child count
private void addEditTextView() {
if (binding.layoutList.getChildCount() <= 5) {
View inputView = getLayoutInflater().inflate(R.layout.row_edit_text, null, false);
EditText val1 = inputView.findViewById(R.id.input_value_1);
binding.layoutList.addView(inputView);
}
}
"When I clicked Add button it is adding input field one by one, this code is working but I just want to limit for 5 fields not more not less and take values from them."
If you want to add exactly 5 fields on button click I recommend designing a fragment with the 5 fields in place, then when the button is clicked, inflate the fragment into your parent view. Then code the fragment appropriately with the data you're working with.
Then if you wanted, you could deflate the fragment on button click to clear the view or add some other way to clear the fragment when you want. Much easier than what you're doing currently in my own opinion.
You might as well include a submit button in your fragment assuming this is some kind of form.
You can simply define an integer and increase it every time you add the EditText but you should check if your integer is less than 5 everytime the method is called.
Example
private void addEditTextView() {
int count = 0;
if (count < 5){
View inputView = getLayoutInflater().inflate(R.layout.row_edit_text, null, false);
EditText val1 = inputView.findViewById(R.id.input_value_1);
binding.layoutList.addView(inputView);
count++;
}
}

Android method executing and results not on time

I have noticed that Android code is being executed by chunks, take this code for example
actionButton.setOnClickListener(new View.OnClickListener() {
#Override public void onClick(View view) {
revealButton.setVisibility(View.VISIBLE);
final LayoutInflater inflater = getLayoutInflater();
for(int i = 0; i <= 50; i++)
{
View child = inflater.inflate(R.layout.item, mainLinear, false);
mainLinear.addView(child, 2);
}
}
});
The Reveal button is not being visible untill the rest of the code is completed and delivered which in this case takes a second or two. So i tried to put it in chunks of code like:
{
revealButton.setVisibility(View.VISIBLE);
}
{
final LayoutInflater inflater = getLayoutInflater();
for(int i = 0; i <= 50; i++)
{
View child = inflater.inflate(R.layout.item, mainLinear, false);
mainLinear.addView(child, 2);
}
}
I have also tried to make a two different static method trying to go too far to get this right which resulted in the same behaviour. The problem comes when i need to do some work but have to update the UI with instant results.
What is it that you're trying to do, exactly?
From the code it looks as if you're trying to render a list of views and show a reveal button to the user. Is that correct?
Either way, it seems to me the reason it's not updating immediately is because all the instructions are being executed on the same thread, which seems to be the Main Thread, so it will only update after it leaves the onClick block.
But I can't be sure on my answer. Could you give more details as to what you want to do, exactly? Is it to render a list of sorts or something else?

getText() always return empty string from dynamically created Chip component?

I'm trying to dynamically create some choice chip components based on an ArrayList of String from some computation and following are the code to create the chips and adding them to a ChipGroup created in layout XML file.
if (mChipGroup.getChildCount() == 0 ){
int i = 0;
for (Classifier.Recognition res: results){
Chip resultChip = new Chip(getDialog().getContext());
ChipDrawable chipDrawable =
ChipDrawable.createFromAttributes(
getActivity(),
null,
0,
R.style.Widget_MaterialComponents_Chip_Choice);
resultChip.setId(i++);
resultChip.setChipDrawable(chipDrawable);
resultChip.setText(res.getTitle());
mChipGroup.addView(resultChip);
}
}
The Chips displayed correctly with the text but when I tried to call getText() on the chips, it always return empty String but not the text contained by the chips. I tested this by setting the OnCheckedChangeListener on the ChipGroup and making a Toast with the text (though it didn;'t work). When I tried to display only the checkedId it works.
mChipGroup.setOnCheckedChangeListener(new ChipGroup.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(ChipGroup group, int checkedId) {
Chip chip = group.findViewById(checkedId);
if(chip != null){
Toast.makeText(getContext(), chip.getText().toString(),Toast.LENGTH_SHORT).show();
}
}
});
My current workaround is to have a variable holding the array results and use ArrayList.get(selectedChipId.getTitle()). but don't think it should be that way though
I also found that it is able to get text from Chips added in layout file but not run-time added Chips. Tried with both 1.1.0/alpha06 and 1.1.0/alpha07 release but am having no luck. Would like to have some advice if possible. Thank you very much.
So, it seems like a bug as per answered in here and here. Current workaround is to use ((ChipDrawable) chip.getChipDrawable()).getText() instead.

Outputting editText and textViews based off user input?

I was wondering if it was possible to ouput xml elements such as editText and textView based off user input. For example I'm making a simple game app and in the app you get taken to a new activity where it asks the amount of players. Based off the input (e.g. 5) I woulld like to display editText's and textViews so the players can be given names. Is this possible with Java and if so, how?
Sure is, though without having to go through XML.
Pass the number of players to the next activity as an argument. Then make sure you have a ViewGroup (LinearLayout for example) in the second activity's layout.
Then loop through and create the Views dynamically:
ViewGroup container = findViewById(R.id.linearLayout);
for( int i = 0; i < numberOfPlayers; i++ ){
EditText et = new EditText(this);
et.setHint(R.string.new_player_hint);// String providing a hint to the user
container.addView(et);
}
You can put the EditTexts in a List or if that's all you'll have you can directly cycle over the ViewGroup's children to get their values later on:
for( int i = 0; i < container.getChildCount(); i++ ){
String playerName = ((EditText) container.getChildAt(i)).getText().toString();
}
If you're going to have many possible players you should wrap the LinearLayout in a ScrollView.
Because you'll likely use this in onCreate remember that you can't rely on the EditText to save its own data in case the Activity is destroyed, so save them yourself and feed them back in when re-creating.

Force Close When Dynamically Creating Widget from XML in Android

I'm attempting to create a few radio buttons and add them a RadioGroup dynamically. When I use the LayoutInflater method of pulling in the xml and adding it to the current view, everything works fine. The correct radio buttons show up.
However when I try to cast the View that LayoutInflater.inflate returned to a RadioButton (so I can setText), I get a force close with a java.lang.ClassCastException.
for (int i = 0; i < options.length(); i++) {
JSONObject option = options.getJSONObject(i);
View option_view = vi.inflate(R.layout.poll_option, radio_group, true);
option_view.setId(i);
RadioButton rb = (RadioButton) option_view.findViewById(i);
rb.setText(option.getString("response"));
}
poll_option.xml:
<RadioButton xmlns:android="http://schemas.android.com/apk/res/android"
android:text="RadioButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
The problem is you're not getting the views you think you're getting. LayoutInflater.inflate() called with a supplied root view means the view returned to you is THAT root view (not the inflated view). The method in which you are calling it inflates a new RadioButton and attaches it to the Group, but the return value (option_view) is the group itself, not the individual item. Since you need to play with the view before attaching it to the group, I'd recommend code like this (which works):
//I added these for posterity, I'm sure however you get these references is fine
LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
RadioGroup radio_group = new RadioGroup(this);
//Get the button, rename it, then add it to the group.
for(int i = 0; i < options.length(); i++) {
JSONObject option = options.getJSONObject(i);
RadioButton option_view = (RadioButton)vi.inflate(R.layout.poll_option, null);
option_view.setText(option.getString("response"));
radio_group.addView(button);
}
Editorial Note:
Just my $0.02, for such a simple layout, running this inflation process over and over in a loop may be a bit too much (inflation is expensive). You could easily create the same RadioButton in code, and add it with your LayoutParams, like:
LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);
for (int i = 0; i < options.length(); i++) {
RadioButton option_view = new RadioButton(this);
option_view.setText(option.getString("response"));
radio_group.addView(option_view, params);
}
This code I didn't test, but it should be pretty close :p
Hope that Helps!
You probably want to use findViewById and locate the radio button in the inflated view. Something like:
RadioButton rb = (RadioButton)option_view.findViewById(R.id.yourButtonId);
See http://developer.android.com/reference/android/view/View.html#findViewById(int)
you want to radiobutton.setId(INT)
and then later get it by findViewById() to get the button.
The setID(Int) should be used when you dynamically create the button. You can now access it later with findViewById.

Categories