I know that similar questions have already been asked but I do not understand what would be the correct approach of solving the issue, yet.
I would like to change the background color of a ListView row when the user clicks it. However due to Android reusing the row layouts when scrolling, the background color gets repeated for other rows. I am wondering what would be the correct approach of maintaining the original layout for all rows except the one changed programmaticaly and also maintain the changed layout information for that row for scrolling back. I am using a SimpleAdapter which is passed the rows layout's XML.
Regards
Your rows' capabilities within your ListView largely depend on the kind of Adapter you are using. In any Adapter where you manually construct or inflate the View per item, you can change the layout properties per item, as long as you do so within the Adapter. Simply add your background color code to when the item's View is built, and it will work like a charm. If you are not able to do so with the current Adapter, consider extending the current one or using a different adapter.
Note: I haven't placed code directly within this answer because where you add it depends upon your own implementation. For instance, I would add .setBackgroundDrawable() to bindView() in an extended CursorAdapter.
Hope this helps,
FuzzicalLogic
Related
This question already has answers here:
Android Recyclerview vs ListView with Viewholder
(7 answers)
Closed 3 years ago.
I was reading about the difference b/w recyclerview and listview and found out that recyclerview is faster than listview.
I tried to search online but not found any satisfactory answer I know it is used ViewHolder pattern and Notifying adapter but what does it does intearlly so it is faster?
Recycler View you could say is an efficient way to create list of views.
If you have 1000 items like ur contact list , and If ur visible screen can show only 10 items at once, it will Create only 10+1 (or +2) Views and as u scroll , items/views that left will be reused (not create) to show new data.
Recycler View by default does this, where as List View by default doesn't do.
There are some differences between these two views.
ListView is a bit heavy and it has a lot of responsibilities. Whenever we have to handle the list, such as to configure it in some way, the only way to do this is through the ListView object or inside the adapter.
A lot of bad things in the ListView were fixed or changed in the RecyclerView. It’s more efficient by default, the layout is separated and we have more possibilities over the data set inside the adapter.
These are some crucial differences between ListView and RecyclerView:
1 ViewHolder
The ViewHolder pattern allows us to make our list scrolling act smoothly. It stores list row views references and, thanks to this, calling the findViewById() method only occurs a couple of times, rather than for the entire dataset and on each bind view.
The RecyclerView’s adapter forces us to use the ViewHolder pattern. The creating part (inflating the layout and finding views) and updating the views is split into two methods — onCreateViewHolder() and onBindViewHolder().
The ListView, on the other hand, doesn’t give us that kind of protection by default, so without implementing the ViewHolder pattern inside the getView() method, we’ll end with inefficient scrolling in our list.
2 LayoutManager
The LayoutManager takes responsibility for layouting row views. Thanks to this, RecyclerView doesn’t have to think about how to position the row view. This class gives us the opportunity to choose the way that we want to show the row views and how to scroll the list. For example, if we want to scroll our list vertically or horizontally, we can choose LinearLayoutManager. For grids, it is more suitable to choose the GridLayoutManager.
Previously, with the use of the ListView, we were only able to create a vertical-scrolling list, so it wasn’t that flexible. If we wanted grids on our list, we had to choose the other widget for that — GridView.
3 ItemDecoration
A duty of the ItemDecoration is simple in theory – add some decorations for the list row views – but in practice, it’s that simple to implement if we want to create a custom one. In this case, we should extend the ItemDecoration class and implement our solution. For example, the RecyclerView list has no dividers between rows by default and it’s consistent with the Material Design guidelines. However, if we want to add a divider for some reason, we can use DividerItemDecoration and add it to the RecyclerView. In case we use the ListView, we have to figure out rows decorations by ourselves. There is no helper class like ItemDecoration for this widget.
4 ItemAnimator
The last but not least component of RecyclerView that I want to mention is ItemAnimator. As we can expect, it’s handling row views animations like list appearance and disappearance, adding or removing particular views and so on. By default, RecyclerView’s list animations are nice and smooth. Of course, we can change that by creating our own ItemAnimator, which is also not that easy. To make it easier, we should extend the SimpleItemAnimator class and implement the methods that we need (just add animations to a ViewHolder’s views). To be honest, implementing animations on the ListView was a pain. Again, we had to figure out how we want to handle them.
5 Notifying adapter
We have a couple of cool notifiers on the RecyclerView’s adapter. We are still able to use notifyDataSetChanged() but there are also ones for particular list elements, like notifyItemInserted(), notifyItemRemoved() or even notifyItemChanged() and more. We should use the most appropriate ones for what is actually happening, so the proper animations will fire correctly.
Using ListView, we were able to use just notifyDataSetChanged() on the adapter and then had to handle the rest ourselves, again.
Because of ViewHolder Pattern.
Thats was the simplest answer. Now for some details.
What recycler view does is what it's name indicates "Recycle", yes it recycles items, and it does it with the help of ViewHolder Pattern.
By Using ViewHolder we do-not need to call findViewByID() every time we go through getView()method. The reference for all rows are stored in-memory. This increases the performance significantly, as findViewByID()is a heavy process.
Hope this clears your confusion.
I'm using Recyclerview to show a list. I want to delete some items like IOS. In my listview template I have added a button to delete item which is invisible by default. In my activity I have another button attached at bottom (Not part of listview) and on tap of this button I want to make all delete buttons of listview visible.
My Question is how can I get reference to all delete buttons of listview in activity and is it the right way to do this?
Thanks
Assuming you have ViewHolders set up, you already have references to all the buttons in your list. All you have to do is to make them visible for every item in the list with a simple loop.
In case you haven't implemented ViewHolders I suggest you check out the documentation and take a look at some simple tutorials on how to use them.
On a side note. If I understood correctly you're making a bottom tab for your app and since you referenced iOS I gotta say this; Remember that Android and iOS are two unique operating systems with their own ways of handling things. Check out Googles pure Android documentation.
In your question title you say RecyclerView, but in your text you say ListView. The solution is similar either way, but it's best to be perfectly clear what you're doing.
In either case, there are at least two different solutions.
First, you could use a boolean flag to determine if all the the item buttons should be showing or not. You check this flag at the time the item view is inflated or created and toggle the button accordingly. If the boolean flag is ever changed, the easiest thing to do is tell the RecyclerView/ListView that the underlying data has changed and to redraw all the views. Call notifyDatasetChanged on the adapter.
The other thing you can do at the time the item buttons should change is iterate all the visible item views, find the button, and change its visibility. With RecyclerView, you can do this, and with ListView you can do this.
I am developing an activity with a ListView in which I need to change the current row by another layout by clicking on the row, and I'm not finding any way to do as much as I look (I take hours searching for possible solutions and I have not seen any reference to this problem). I do not know if this can be done in Android, but if anyone has an idea of how to do this would be appreciated.
Thanks in advance.
PS: The ListView control is normal and just want to replace a layout with a different layout. I'm using the API 15.
Use a ViewSwitcher
http://developer.android.com/reference/android/widget/ViewSwitcher.html
A ViewSwitcher is -
ViewAnimator that switches between two views, and has a factory from
which these views are created. You can either use the factory to
create the views, or add them yourself. A ViewSwitcher can only have
two child views, of which only one is shown at a time.
I suggest merging the two layouts in a single one and hide the second one. In your adapter data you should have a flag or something to indicate which layout to display. When you click a row, toggle that flag for the selected item and notifyDataSetChanged() on the adapter. This will make sure the changed layout remains even if you scroll up and down and the row goes off screen.
A more optimized solution is to have different item types in the adapter.
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.
I want to generate a ListView that has some dividers between some of the entries, like it can be seen in some of the property sections. See the example below. I try to generate a List that consists of some textviews followed by one of the fancy dividers explaining the next part of the list and then again some text views. How can this be done? I thought about creating different views to add to the list? Is this the way to go?
I got a solution. I don't know if it is the best one.
I use a custom adapter derived from ArrayAdapter for the list as described in this tutorial. In the adapter class I check if the position in the getView method is a normal row, then I inflate the row layout. If it is the first row from a new group I inflate a headline layout that is a normal row plus the group headline above it.
If you don't want to mix the header into one of your rows. Consider the following solution:
You can overwrite the two methods getItemViewType and getViewTypeCount.
You now have a list that can display different rows. You need to check the expected view type for the item in the getView Method and inflate different layouts depending on it.
The list will handle the recycling for you in a way that it will return only correct recycle views to your getView method, this means if the recycleView is not null it can be used to display your current cell.
You can use my SectionedAdapter, if GPLv3 is acceptable (licensed that way due to some upstream code). You can use my MergeAdapter, if you need something more flexible and with a less-limiting license (Apache 2).
I think you might be looking for android.widget.ExpandableListView
http://developer.android.com/reference/android/widget/ExpandableListView.html
I'm also interested in an answer to this. There must be a more straightforward way to do this.
In looking at the Adapter, there's a method, Adapter.getItemViewType(int position).
ListView defines a return value, ITEM_VIEW_TYPE_HEADER_OR_FOOTER which indicates if the returned item is a header or footer.
I haven't tried it, but I assume if you create your own Adapter and return an item with the type indicating it is a header or footer, that the ListView will display it appropriately.