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.
Related
I am trying to create a WearableListView similar to the one in the default Settings app. I have a WearableListView that scrolls, and animates each element. All I need now is a header on top of the list that scrolls up when the list scrolls. This is the same behavior that the title 'Settings' has in the Settings app.
The only method I have found to do this, used here: How to Set the Layout for topEmptyRegion, implements a WearableListView.OnScrollListener(). Then uses the onAbsoluteScrollChange() method to set the displacement of the TextView used as a header. But, according to the Android Developer References, this method is deprecated. The documentation even states: BE ADVISED DO NOT USE THIS This might provide wrong values when the contents of a RecyclerView change.
I would like to know if anyone else has found a way to implement a header that behaves this way, one that is not deprecated. Possibly something that I missed in the Android Wear documentation?
EDIT:
I tried to implement this method anyway. As it turns out, WearableListView.setOnScrollListener() would not take a new WearableListView.OnScrollListener(). Instead it asked for its parent RecyclerView.OnScrollListener, which does not have a onAbsoluteScrollChange() method. It does have an onScrolled() method, which I tried to implement. As it turns out, this completely overrides the default scroll listener for WearableListView and makes it so the centered item can be off-center. Definitely not the effect I was looking for.
Since onScroll() is not deprecated, you may be able to accomplish the same by implementing that in your listener:
#Override
public void onScroll(int scroll) {
header.setY(header.getY() - scroll);
}
where header is the header component.
EDIT: Make sure you use WearableListView.addOnScrollListener not WearableListView.setOnScrollListener()
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 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.
So basically i have a an imageview inside a scrollview, what i want to do is be to be able to scroll infinitely without ever reaching the bottom of the scrollview.
Can this be done in any way ? the image of course will have to be repeated .. but any other method is appreciated
You can use a ListView and an Adapter that is modified slightly to have "infinite" scroll.The change required in your Adapter is something like this:
#Override
public int getCount()
{
return Integer.MAX_VALUE;
}
The trick here is to tell it that the count is MAX_INT.However by doing this, it will make scroll downwards infinitely but not backwards.
In order to make the list go backwards, as in an infinite carrousel, you can trick the system by setting the default element to be something like Integer.MAX_VALUE/2 by calling:
listView.setSelection( Integer.MAX_VALUE/2 );
By doing this, it makes the effect of infinite carrousel in both directions.I think presence of ImageView will not be a problem and it should work then too.Hope this helps.
Edit
For this, as you need to learn how to make a custom ListView and a Adatper, i suggest you to follow this easy and short tutorial.You can also download the entire project from that link.After running that project, add the above mentioned code.
I am developing an application that needs to show calendar agenda, much like the agenda in the native calendar. I have a list view showing different events (Note: in the context of the question events is entity of my system). I want to provide a 'Today' button on this screen. When the user clicks on this button the events are supposed to be scrolled until the first event of the current's day schedule is on top of the screen. The problem occurs when I have only a few events scheduled from today on - so few that they do not fill a whole screen. Then the list view just scrolls until the last event in the calendar is on the bottom. This usually means that the desired effect of having the first today's event on top is not achieved.
Any suggestions how this can be done? I have thought of adding some blank elements at the end, but this seems ugly workaround, and furthermore it will require special device-specific calculations that will tell me how many elements to insert.
Edit:
Adding some code as requested in comment
Actually I am not sure this code will surprise anyone, but:
public void onTodayClicked(View target) {
// calculate the indexOf. It works and is not related to the question
if (indexOf >= 0) {
ListView list = (ListView) findViewById(R.id.events_list_view);
list.setSelection(indexOf);
}
}
I am not sure the layout definition is important to aid the answering of the question, but if you think so I can add it too.
You can achieve this by two ways:
call smoothScrollToPositionFromTop method
call setSelectionFromTop method
Using the smoothScroll method is better, because it actually does the transition smoothly - that means it really scrolls to it.
The only downside is that it's only available after API level 11.
The setSelectionFromTop method works since API level 1, but instead of smoothly scrolling, it jumps to the row.
If you don't need to position to the top of the screen, only to view the row, you can also use smoothScrollToPosition, which is an API level 8 call.
If you give these methods the position, which is the FIRST in the list, they will work well. (From your description I think you probably calculate the last position, but I can't be sure).