I have a RecyclerView. Each of its items of the recycler view can be either expanded or not. There can be only one item expanded at the same time.
In essence, I'm trying to re-create the history list in lolipop dialier.
I have found that using a LayoutTransition on RecyclerView makes it crash.
But I have not been able to correctly animate the item view change between both states.
I have tried getItemAnimator().setSupportsChangeAnimations(true) in conjunction with notifyItemChanged(getPosition()) but there is two problems:
The view is re-created, making the transition quite weird as it fades in above the next item at the same time as the item is moving. The new view that appears is not resizing, it is already at full size.
As the view is re-created, the old view is fade out while the new is fade in, which makes the view background color flicker.
I have also tried setting a LayoutTransition on the item view for the duration of the animation but the problem with this approach is that the layout of the RecycleView updates immediately and does not follow the animation.
I have created a small demo project of this issue for both tries.
The projects sources are here.
How can I create a smooth transition on item layout change ?
OK, So I have found a solution that does not involve calling notifyItemChanged so the view is not replaced. The con is that you have to manualy check the view consistency. For that, I have created a small library that allows exactly what I was looking for, for 5 loc in the ViewHolder.
The trick is to animate height change manualy rather than using a LayoutTransition.
The demo project can be found here.
You should just use notifyItemChanged(getPosition(), new Object()) instead.
In your adapter, override onBindViewHolder(GigExtraViewHolder holder, int position, List<Object> payloads) , if payloads is null or empty do your original bind logics, else, just do your own expand/collapse animation.
Related
i am using a recycler view with a list adapter. When submitting a list with a completely or almost completely different items the animation doesn't look good. Another problem is that i have no control on the scroll position as scroll to position is not processed as expected. It makes perfect sense to reset the scroll position to zero when the data is changed.
I ended up setting up a new adapter when switching all the data.
Would be helpful to have a better solution.
I would expect to have a method where you notify the adapter/recycler view that you want to switch all the data without trying to applying the diff mechanism and animating the changes.
I would like to be able to animate the appearance of the new list but avoid trying to animate what actually changed.
I was going through this thread on this topic :
RecyclerView Animation on Item Click
But I have one question on the technique used.
I tried implementing it based on solution above. Although the approach seems to work in the current view of my recyclerview. But as soon as i scroll further to Right (in my case its a Horizontal Recyclerview), i still see the view being expanded since the views are being recycled and the isExpanded value is still true for them. I was thinking shouldn't the isExpanded property be at the data being displayed, so that we don't keep the same state of the reused view ?
Curious to know, how does RecyclerView behaves when you scroll it to the next page.
Thanks,
Ok, basically you need to check each item "state" and prepare the recycled viewholder for the new item to bind.
Please have a look at my ExampleAdapter (in onBindViewHolder()) in my FlexibleAdapter, where you can also find basic click and long click listener already implemented as example.
Feel free to ask questions.
Recently I've improved and created a FlexibleAdapter pattern for all RecyclerView.
Very simple to use, just copy 2 classes in your common files + some xml in order to enable the selection (Single/Multi) as it was for ListView.
Please have a look at the description and full working example: https://github.com/davideas/FlexibleAdapter
I have a ListView that displays a list of items, each of which has an icon and a few bits of text.
I am making use of the "convertView" parameter of the ListAdapter.getView() method, altering an existing view rather than creating a new one when the parameter is non-null.
I had expected the ListView to recycle old views only after they had scrolled out of the visible viewport, but this appears not to be the case. It appears that the ListView is providing the same object in the "convertView" parameter on each invocation of ListAdapter.getView(). The single view is rendered to the screen, and then sent in again on the next call to getView().
This poses a significant problem for me, as I wish to modify previously rendered views. I have a background thread retrieving the icons for items, which takes "considerable" time and would be an unacceptable user interface burden to place within the ListAdapter.getView() view rendering code.
Is there any means to make the ListView not reuse views which are currently displayed on the screen? I'd like to realize the performance/efficiency gains of view reuse and be able to load the icons in a background thread.
I think you're having a similar problem I had for a while: Old items visible a while, in listview or gridview, when recycling
You have to "reset" the recycled items of the list at the beginning of getView(). Set them back to progress bar, or invisible, whatever the initial state is. Until they fetch the correct data.
I've found the issue is that Android is creating an additional, never-rendered temporary view for use in layout/measurement under certain conditions. My assumption that this view was rendered to the screen was not correct.
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.
Is it possible to apply an expand or collapse animation for expandableListView?
It can be done using a simple ListView that contains an initially hidden view and a custom class that extends Animation.
The basic idea is to start with View.GONE then gradually re-size the margin from a negative value to the required size while setting visibility to View.VISIBLE.
See:
https://github.com/tjerkw/Android-SlideExpandableListView
Android Animation: Hide/Show Menu
How do I animate View.setVisibility(GONE)
..and finally
Cool toolbar for ListView items + source
The last example contains all the code you need. It looks a bit hackish to me, especially the fact that you must initially set view.bottomMargin = -50 or more, otherwise the animation does not work properly the first time, but so far I did not find any viable alternative (apart from using a ScrollView with your own container items instead of a ListView).
And finally, this app includes the above example, among lots of other useful examples with links to sources:
https://market.android.com/details?id=com.groidify.uipatterns
Update: Google removed the app from play store allegedly for intellectual property violation (although it only contained demos and links to open source projects), the author now made the apk available for direct download from http://goo.gl/ihcgs
For more details see https://plus.google.com/108176685096570584154/posts. NB: I'm not affiliated with the author.
I have done a similar job for a simple list view.For doing that I overrode the getView method and applied translate up( or down) animation on each list item.The degree of translation was decided by the position of the list item.
I've found a possible (partial) workaround for this problem.
first you need to store the scroll state of the ExpnadableListView :
#Override
public void onScrollStateChanged(final AbsListView view, final int scrollState) {
this.mScrollState = scrollState;
}
public int getScrollState() {
return this.mScrollState;
}
for the listView itself, you need to store which group was clicked, so that only its children will get animated:
mListView.setOnGroupClickListener(...
#Override
public boolean onGroupClick(...){
mGroupPosition=groupPosition;
now, in the getChildView() method, you check the state of the scrolling , and if it's idle, you start the animation, for example:
public View getChildView(...) {
// <=prepare rootView and return it later
if (groupPosition==mGroupPosition&&getScrollState() == OnScrollListener.SCROLL_STATE_IDLE)
rootView.setAnimation(...)
this will set an animation for the child views each time you expand the group.
the drawback of this are:
only for the expanded child views. you will need to think of extra logic to animate them when collapsing the group.
all animations start at once . you will need to add multiple animations one after another if you wish that it would work otherwise.