getting more data from a listview row - android

I have a ListView that contain several TextViews. Once a TextView is pressed I get the onClick called with the view. What is the best practice to get the other text views on that row? IDs of the text views are similar along the rows so I need to keep on the context of the given view. I would guess I need to get the Parent of the given view and then grab the rest of the text views from it.
Thanks.

Yeah, you would need to get the parent of the current textview, then get all the children contained within that parent.
Depending on what you need to do with the textviews you could either call FindViewById on the parent view to get each TextView by ID. Or you can iterate through the children as suggested in this question/answer:
Android - get children inside a View?
I know people mention that calling FindViewByID is a taxing process, so consider storing the references to the textview's in some sort of object so you can quickly get the references to the other textview's within the row without having to look them up all the time.
ViewHolder's work pretty well, as they store the references to the textview's within an object (which you only need to fill once during creation) but it requires setting up your own customized adapter.

Related

How to specify which view is clicked in layout added multiple times

I have a layout which takes user's children information. Let's say that this layout takes info about the children's first name, last name, and age. I am taking inputs with EditText. And there is a spinner which shows children Allergy type, on selecting 1 Allergy type it has to fetch its details from webservice and to fill those details in a textview.
So in this way the User can add as many children as he wants. The problem occurs there. Let's say the user has added that layout 4 times now, he selects the spinner of children 1 and service gets called and it fetches the information and fills it in the last layout textview that was added.
where as it is expected the details should fill in each textview of each layout added accordingly.
Confusions :
How can I exactly get which view is clicked and then how to take action in the same layout of that view not the one which is added recently?
I am inflating layout which has the specific set of fields specified above. So I am maintaining the Array List of each layout added , so Is there a work around to get exactly the same view and its corresponding view in that layout ??
UPDATE 1: Some Idea of my question
There is a main activity it has 1 button named "Add More Children". When user click on this the layout which contains the children info adds in the specified area in the ScrollView, so that user can add as many children as much he want.
so basically I have drawn some views below where as there are too many views in the following layout named children layout.But this layout shows what type of work is need to be done . so see below and have some idea
For demonstration you can see there are different edit text and spinners. Spinners get updated from Webs service and each children may have different data loaded in spinner from webservice. this whole layout inflates into the mainactivity. on button click named Add Children . so on that button I am adding this in the scrollview
private View addChildLayout(int childLayoutid, LinearLayout Targetlayout) {
//where childLayoutid is a layout resourse id of childern layout
// where Target layout is a scrollview in my fragment
LayoutInflater inflater = LayoutInflater.from(getActivity());
View inflatedLayout1 = inflater.inflate(childLayoutid, null, false);
inflatedLayout1.setId(numOfChildAdded);// numOfChildAdded is int number of children added by user so far
Targetlayout.addView(inflatedLayout1, 0);
numOfAddedChildLayout.add(inflatedLayout1);//this is an array list i am creating to keep track of each layout added by user on add button click
return inflatedLayout1;
}
after adding this in layout another method I call that finds the ids of this layout and sets the click listener of each views i.e spinners or edit text or whatever is needed. Now suppose User has added one children. and clicks on the spinnerAllergy types that fetches sub category and populate spinnerSubCatogry, and spinnerSubcategory when clicked the web service again gets called and gets details of allergy and fills in the Textview (the large box shown in picture)
Now the main problems comes in when user added Children no 2. now let suppose user has added 2 childs , but he clicks on the spinnerAllergy of Child1 , the child1 spinners runs the web service but populates the spinnerSubcategory of Child2.
It Looks like that when the new child is added the click listener refers to new layout which is newly added .
so that is the main problem . I want each view in each layout work accordingly in its views and boundaries. I mean child1 layout views click listener should populate its views not the currently added layout views.
I think that is enough information to get some clear idea.
Please help me with this, I've been stuck here for 2 days. Where as all my design is working good.
Well as you stated above that you are keeping track (List of ) every single view you have added. I will suggest you to use that
Here are the lines you are using and setting the id so its mean each parent has the different id where as their child views has the same id ,
View inflatedLayout1 = inflater.inflate(childLayoutid, null, false);
inflatedLayout1.setId(numOfChildAdded);
As you are adding each layout with different ID why dont you simple get the parent and then again get the child with the specific id , for demonstration
Suppose there is a textview in you layout , and that under the Linear layout where as that linear layout has a relative layout as a root/main layout , and every main layout has different id as you have done above. so this is how you will go to the top(parent ID)
ViewGroup row = (ViewGroup) yourTextView.getParent().getParent;
TextView textView = (TextView) row.findViewById(R.id.tvClassLevels); // the next view you can find
so here I will suggest to do this with each view and then set click listener.
this may not be more efficient but this would work. I have done that once When I was inflating my custom layout but keep that in mind every time inflating though may be quick but it would be costly , you need to implement some logic near to getview (as we have its implementation in adapter)
Why I am doing getParent().getParent() twice
As I said that my textview is in linearlayout and that linear layout lies in the main/root layout and hence as we want to approach the mainlayout because we know it is the only one which has different Id , so we are doing getParent() twice as Textview has LinearLayout as first Parent and then the root layout comes, so in this way if you have a view in another layout , you need to dig it by yourself.
Again I am saying , it may be not a cool or best implementation , but it works . At least it worked for me.
I think the problem is : Different views in your layout have SAME id since you're inflating from the same xml layout.
You have different approaches to solve this:
Keep track of a variable and increment the count whenever you add a Child View. Once the inflation is done, you call setId on the newly created View(just as mentioned in Abdul Salam Ali's answer). Although view ids in android are generated at compile time(correct me if I'm wrong), this should work perfectly in practice.
Create a Ids resource file in res/values folder and pre-define a few Id values for future use. It's guaranteed that all id values will be distinct. But as you say, users can add as many child info as they want, this may not be the best choice.
Use Random to generate different ids.
Please note that even if you have same Ids in your layout, your code logic would be correct as long as the childs of ViewGroup on which you call findViewById(or sth similar to this) has a unique id. See this
For some suggestion to your design.
Use the listview and adapter design instead of generating the view in programming.
a. Add the new item
Used floating action button. https://material.google.com/components/buttons-floating-action-button.html#buttons-floating-action-button-floating-action-button
B. Remove the item
Used some list control or multi selector to remove the undesired items.https://material.google.com/components/lists-controls.html#lists-controls-types-of-list-controls
Use listview to show your item instead of generating layout in your code.
https://material.google.com/components/lists.html#lists-usage
To edit the specific child information, suggest to use the full screen dialog for editing.
https://material.google.com/components/dialogs.html#dialogs-full-screen-dialogs
The above is my suggestions toward your design, since it would be difficult if you want to get the clicked view's parent to find your actual position in the layout, and then send to to listen the corresponding on click event. It would be hard to maintain and your code will be hard to debug if there is any nested view in your parent. Try to separate each part to help your debug what is wrong in your code.

Recyclerview with multiple dynamic views being inflated inside row

I'm getting my data via an API that supplies me with an array of rows for my RecyclerView. Inside each of these rows there is an array of elements which I want to add dynamically to each of my RecyclerView rows. Each element corresponds to a view. So for example I might get a title, then an image, then text. Or I might get just an image. Or a title and text. These are just some of the elements, there are more and maybe hundreds of different possible combinations. For this reason it's not viable to create and inflate different row types as you would normally do if you need just a few different types of rows.
I tried to inflate and attach my views to the row on the onBindViewHolder method, but this caused the elements to be added again and again everytime that method was called.
I have searched around and have found no similar questions to what I am after, and I was wondering if there was a nice clean and elegant way of achieving what I need.
I managed to achieve what I was looking for using the following method I had already tried:
I tried to inflate and attach my views to the row on the onBindViewHolder method, but this caused the elements to be added again and again everytime that method was called.
To prevent the views to being continuously added everytime a view was recycled, I overrided the onViewRecycled method, and removed all the views from the linear layout inside the row.
So far, I haven't had any problems with this method, but it's probably not the most efficient.

How to get all children (visible and invisible) from a ListView?

My problem is similar to ListView getChildAt returning null for visible children, but despite searching I cannot find a solution.
I have a ListView with a Scroll. The ListView has 10 items, 7 of which are visible and 3 are hidden by scroll. I also have an external method (out of adapter) that must get all of the children from this ListView (e.g. using getChildAt()).
I need all 10 of the items, but the last 3 are null objects. I've tried code like the following:
getListView().smoothScrollToPosition();
But this doesn't work.
I think that I don't need to post the rest of my code, as the description says everything?
As you have already seen you can't get all the child row views from a ListView simply because a ListView holds only the views for the visible rows(plus some recycled rows but you can't reach those). The correct way to do what you want is to store whatever data in the adapter's data and retrieve it from there.
But the ListView doesn't keep the current values from RadioGroup in
running time.
I've seen that you have some problems with this so I've adapted some old code to build a basic example, code that you can find here.
I don't think so you need to add scroll view for a listView. Scroll automatically works on ListView. Try your application without adding scroll view and I'm sure it'll work as you needed.
The reason those children are null it's because they really do not exist and they will never exist, if only 7 children are on the screen at one time, the system will only create 7 and re-use by passing the convertView back to the adapter getView() method.
If you want to grab information regarding your whole dataset you should search on the dataset itself, instead of the views on the screen. E.g. if it's an ArrayAdapter, loop the array; if it's a CursorAdapter, loop the cursor; etc.
The non-visible children of a listView don't actually exist. When they become visible, one of the redundant views is recycled or a new view is generated. So you can't actually access all the views. Why do you want to? Whatever changes you want to make should be made to the data that populates the views rather than the views themselves.
There are a few point that you need to take care of:
1. List view provides inbuilt scroll functionality, So don't use Scroll view. It will only mess up things.
2. List view doesn't contain ALL the children. When you scroll it, it creates only visible items on run time.
3. If you want to get all the children altogether, Better keep an ArrayList of the child objects that your list has. You can add or remove children to this ArrayList as per requirement.

Hidden Field in ListView Android?

I'm wondering if there is a way to hide a field in Android.
I tried with setting the value in a TextEdit and then making the TextEdit invisible, but the result is that the value is invisible, but the control takes space.
In my case, I want to store an extra value in a row of a ListView.
Is there another solution besides using hidden fields?
Use View's public static final int GONE field.
In your case textEdit.setVisibility(View.GONE), or in xml android:visibility="gone"
Setting the view to INVISIBLE does not take layout into consideration, but GONE does.
View has methods setTag() and getTag() that you can use to associate some extra data with row of ListView. For example I'm using CursorAdapter class and in newView() and bindView() methods I call view.setTag(). Then in OnItemClickListener I call view.getTag().
I bet the only invisible data contained by rows of ListView is id (long). I was also trying to find a way to pass some data (like uuid) to the row click handler, however seems a "GONE" TextView is the best solution for now...

How to implement custom view with variable fields?

I have a ListView that displays a set of notes, each with varying ammounts of data (i.e. some have a due date, others don't).
Currently, each view in the list is a RelativeLayout containing a TextView for each field, plus two Button and a CheckBox. I then simply hide the unused fields by setting visible false on each one.
This has worked well, but I'm about to add a lot more data fields to the notes and inflating that many unneeded views for each row will surely kill my app. I need a more dynamic solution.
I've decided the best way to go is to create a custom view. How can I implement/design my view so that it can display a variable number of text fields without creating/destroying textviews each time (which would be quite expensive and worse than my current situation), or maintaining a large pool of hidden textviews?
You can create a class that extends LinearLayout
and use addView to dynamically place your views.
Sounds like you might want to look into a view with a stub. The stubs will save space until they are inflated, so each row will be lighter until it is used on a heftier view. If you have a relatively low number of these larger views you might save a bit of overhead.

Categories

Resources