I have read many posts about implementing an OnItemClickListener in the RecyclerView, but the more I read, the more I get confused. It seems that we have two ways to implement the OnItemClickListener:
Adding setOnClickListener inside the adapter as shown here
Implementing RecyclerView.OnItemTouchListener as shown here
As I read the posts I figure out that the first method is better and has more features than the second method. For example, there's item click support. What is the benefit of the second method? Why and whe should I use it? Any suggestions?
An OnItemTouchListener functions a bit differently than the normal OnItemClickListener. Using the OnItemTouchListener, it is possible to allow the application to intercept touch events from the View hierarchy. What this basically means is that you can implement various forms of gesture manipulation like swipe straight into the Views of your RecyclerView.
When should you use it?
An OnItemClickListener should be used when you need to determine what happens when the user clicks on a View in your RecyclerView. This could be deleting something or starting up a new activity. The OnItemTouchListener Is generally used to create gestural interactivity to certain Views in your RecyclerView.
If you want to implement an OnItemTouchListener into your RecyclerView, you will need to determine the MotionEvent that you're going to use. For more information, I suggest you read more about OnItemTouchListener from the Android Developers site.
Related
In my case I have a list of objects and each object has a list of other objects, like:
class Parent(val title, val childs: List<Child>)
class Child(val title)
The above code is an example and there are a lot more fields to implement, like images (for the sake of the question lets keep it simple).
Now what I want is:
To use custom layout for both parent and child items
The child items must be displayed inside the parent item
Based on the above, I decided to use a RecyclerView inside a RecyclerView.
Some other options are:
The parent RecyclerView will be scrollable but the child RecyclerView will have fixed height (so there is no need to implement nested scrolling).
Both RecyclerViews have a vertical orientation.
When clicking the parent item the visibility of the child RecyclerView will be toggled (this is not very relevant to the actual question, but just to get an idea of what I have in mind).
Using my poor skills, I would initialize the child RecyclerView inside the parent RecyclerView.ViewHolder and onBindViewHolder method (of the parent RecyclerView.Adapter) I would assign the LayoutManager and initialize/assign the child RecyclerView.Adapter to the child RecyclerView.
I would also implement a Listener that when clicking a child item, a callback will be called containing two parameters, the index of parent and index of child.
I know how to implement what I described above, the actual question is if this is "correct"
or better say, the best practice.
As far as I can think, this implementation seems dirty and not very optimized (maybe I am wrong). I want you to explain me if there is better way to implement what I described above (with examples if possible). If not, providing an explanation why there is no better way will be also useful.
There are multiple ways to go on about this.
The method I would use is the one you described above, however, you should be careful so that you "set up" Child's RecyclerView in the init block of the Parent's ViewHolder, so you don't do too much work on the binding process of the Parent's items binding process. And, I would use this method, because it is easier to implement the:
When clicking the parent item the visibility of the child RecyclerView will be toggled (this is not very relevant to the actual question, but just to get an idea of what I have in mind).
feature, so this is kinda relevant, in the aspect that you can have a harder time to implement it using the next method.
Another way of doing this, is by implementing an adapter that takes into consideration the RecyclerView.Adapter's viewType, which you can use to distinguish between Parent and Child model types so you use the corresponding ViewHolder for each type, making the list look like a list with clear sections, the section headers of which are the Parent's model. This method is great for making a list with sections, however, making a toggle functionality requires careful considerations on how you want to hide the ViewHolders by looking for them specifically or using extra variables to save the state of the sections and careful conditions on the RecyclerView.Adapter's ViewHolder's bind() method, which may or may not cause a headache.
So basically I would use the first method. Hope this helps!
Which one of the two approaches is better regarding the performance and maintainance:
Implementing listView.setOnItemClickListener()
Adding click listener to convertView or view object in getView()
method.
Also does adding click listener in getView method of adapter violates Single Responsibility Principle?
Thanks in advance :-)
It depends on the implementation. With a simple list the first approach is recommended. If you have a custom adapter with focusable views I recommend the second approach.
Respeonsibilty is not related to adding of the click listener but to what the click listener does. If it performs some business logic (with a symptom of change) inside the adapter it violates SRP.
Are there any best practices on using the new RecyclerView animations together with a SQLite database?
In particular, I'm thinking about a pattern that's been around for a while now: sliding a list item off the screen to delete, and giving the user the option to undo.
Like in the Gmail app:
I don't think this is hard. My approach to solving this is in two parts, a custom view that shims around the adapter view, and a scroll listener on the recycler view.
The custom view is to handle the sliding item part. The key part is to mark the associated item for deletion when it is put into the slid state. I also like to allow for a second slide to dismiss the undo option.
The scroll listener on the recycler view simply deletes any marked items when onScrollStateChanged is called, you only need to care about changes away from SCROLL_STATE_IDLE. I prefer my deletion to be more lenient than the gmail implementation, so I post a delayed message on the scroll event rather than deleting straight away. You have to remember to cancel it if undo is pressed.
Oh, you also have to do any deletions if the screen is navigated away from.
You need to implements SwipeDismiss, use this library
SwipeDismissRecyclerViewTouchListener.java
On dismis you need implements a custom view or use visibility GONE from xml.
I'm working on creating a swipe-to-dismiss list view adapter. My basic methodology is to wrap the list item's view as the second view in a ViewPager and provide the necessary callbacks in the item change listener of the ViewPager. Through much pain I've got the View recycler working as intended, as well as ViewHolder and ViewBinder patterns implemented. I even managed to keep the ListView from taking over the touch events while the ViewPager is being scrolled without having to make a custom subclass of ListView (I can do it all from the Adapter).
Where I'm running into trouble is getting the selector and the OnItemClickListener to work. After looking at ListView's source it seemed that by overriding the ViewPager's hasFocusable() method to always return false (later on I'll pull this value from the child view) these things should have been reenabled. Unfortunately this is not the case. I've tried the setDecendantFocusability() workaround and I'm still stuck.
I'd like to avoid having to extend ListView if possible to provide the greatest amount of modularity. For similar reasons I don't want to add the selector to the ViewPager's background (if the dev changes the ListView's selector this wouldn't be reflected). Essentially I'm looking to make the ViewPager code transparent between the ListView and child View. Any ideas?
You are saying that you are making each list item a view pager, so that you can implement swiping to delete? If so... no no, this is not what view pager is for. First sorry it is just not intended to be used as an item in a list. Second it is for switching between views, not swiping to delete.
Unfortunately we don't have a sample code to show how to do this, but you can look at the platform's implementation of the notification pane or recent apps to get some ideas.
I am trying to get a button to show up on my list item (declared as android:visibility:"gone" in the XML) to show as visible when I perform some gestures on it. However, how can I actually notify the getView method correctly to display the button only on the listview item?
I tried using getChildAt(position) which ended up displaying several buttons at once.
I tried passing in the position for example I detected that the gesture was performed on from pointToPosition and passed it into the adapter for the getView method to display, but it had the same problem of displaying several at once.
do anyone know how can I solve this?
I think you may have a misunderstanding of how Adapter.getView() works its meant to create or reuse layouts when rendering the ListView it also needs to be fast so conditional manipulation in this method is discouraged. Although ListView.getChildAt() may work it does not effectively use the API. Your adapter will have a setViewBinder() unless you're using an ArrayAdapter (if so I suggest using SimpleAdapter because of the additional features). Use your ViewBinder implementation to switch the visibility of the button.
If you'd prefer to continue to use ArrayAdapter use ListView.getChildAt(int) to findViewById(R.id.your_button).setVisibility(). If this is what you already tried and its setting all the buttons visible then please post the related code.