Android ListView Animation - android

I am trying to add Animation for ListView I am using getView()to draw some views in list. all works fine.
public View getView(int position, View convertView, ViewGroup parent) { }
I am trying to add animation when user click on list cell then all list cells should slide left and new data should come from right at same time, means cell data is moving towards left and same time new data coming from right side.
I Have implemented following code in OnItemClickListener
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
Animation slideOutAnimation=AnimationUtils.loadAnimation(this, R.anim.slide_out);
slideOutAnimation.setDuration(900);
Animation slideInAnimation=AnimationUtils.loadAnimation(this, R.anim.slide_in);
slideInAnimation.setDuration(500);
listView.startAnimation(slideOutAnimation);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
data = newData();
listView.startAnimation(slideInAnimation);
myAdapterClass.notifyDataSetChanged();
}
}, slideOutAnimation.getDuration());
}
};
above code is working but not getting desire output I am getting one empty view while changing Animation.
Left Sliding Animation Starts--- Empty View----Right Sliding Animation Starts
Not getting why Empty view (shows empty screen for while) is coming, I have played with Animation time and handler but no luck.
How to remove that empty view ? how to achieve this output ?
Left Sliding Animation Starts(Data moving)( Same time data coming from Right) Right Sliding Animation Starts

I am trying to add animation when user click on list cell then all
list cells should slide left and new data should come from right at
same time, means cell data is moving towards left and same time new
data coming from right side.
Your code works as intended but it will not do what you want simply because you use a single ListView widget which you first animate sliding left and then animate sliding right after the first animation ends.
Try to use a ViewFlipper containing two ListViews(one will be the visible one the other will be the one that comes with new data). You'll set your animations on the ViewFlipper(in and out animations) and then on a list item click you'll do:
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
data = newData();
//set the data for the second list, which currently isn't visible
secondListViewAdapter.notifyDataSetChanged();
viewFlipper().showNext(); //show the next list with animation
}

you can change animation behaviour by editing android:fromXDelta or alpha values,
slideout.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="-100%p" android:toXDelta="-100%p" android:duration="#android:integer/config_shortAnimTime"/>
<alpha android:fromAlpha="1.0" android:toAlpha="0.0"
android:duration="#android:integer/config_mediumAnimTime" />
</set>
slidein.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="-100%p" android:toXDelta="0" android:duration="#android:integer/config_shortAnimTime"/>
<alpha android:fromAlpha="0.0" android:toAlpha="1.0"
android:duration="#android:integer/config_mediumAnimTime" />
</set>

Related

Android dimsiss ImageView on swipe gesture

In a RelativeLayout I have a TextView and a Button under the TextView and an ImageView covering both of the other objects. As the user opens the activity, the ImageView should cover the other items.
As the user swipes on the image (left or right), it should dismiss so the user can operate the button and read the textfield.
Whith an onClick listener I could dismiss the Image when clicked but I would like an animation, exactly like in a RecicleView when swiping to delete an element.
You could add the desired animation to the onClick event.
1) create(or add if existing) the anim folder inside the res directory and put slide_animation.xml
<?xml version="1.0" encoding="utf-8"?>
<set
xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="#android:anim/linear_interpolator"
android:fillAfter="true">
<translate
android:fromXDelta="0%p"
android:toXDelta="75%p"
android:duration="800" />
</set>
2) Add this code to the onclick action of the image view :
// Refer the ImageView like this
imageView = (ImageView) findViewById(R.id.imageView);
// Load the animation like this
animSlide = AnimationUtils.loadAnimation(getApplicationContext(),
R.anim.slide_animation);
// Start the animation like this
imageView.startAnimation(animSlide);
You can modify the animation specs in the xml so you can get the desired effect.
And then just implement AnimatorListener so you can dismiss the image view at animation end.
animSlide.setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
//remove image view from the layout
}
});

RecyclerView add Item animation

I am currently working on adding a income animation for RecyclerView items. I want it just likes the Google+ Android App. Here is my code snippets:
anim/up_from_bottom.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="#android:anim/decelerate_interpolator">
<translate
android:fromXDelta="0%" android:toXDelta="0%"
android:fromYDelta="60%" android:toYDelta="0%"
android:duration="500" />
</set>
and in the Adapter class I add the function startAnimation(itemHolder.itemView, position); in the funcitononBindViewHolder
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
...
startAnimation(holder.rootView, position);
}
the startAnimation() is like this:
protected void startAnimation(View view, int position) {
if (position > lastPosition) {
Animation animation = AnimationUtils.loadAnimation(mContext, R.anim.up_from_bottom);
view.startAnimation(animation);
lastPosition = position;
}
}
It seems looks like the Google+ Android App's list animation, but it has a bug, when I scroll fast, it animate not perfect, such as it seems that the first position and the current postion perform the animation at the same time.
I just want the animation like Google+, how can I fix it, or there has any other way.
I hava try recyclerview-animators, it's a great lib, but I still do what I want.
Any help please! Thanks!
Your "bug" occurs when you scroll fast because the animation on the viewholder is still running when it is scrolled out of the display and you are binding a new animation to the viewholder when the recyclerview recycles it.
You should override onViewDetachedFromWindow and clear the animation on the view in the method.
This will ensure that any animation that is running on the view will be cleared before it is sent to the recycler for resuse, and you can safely run a new animation on the view.

rotate a refresh button in ListView

recently I wrote a function.it's about a refresh button in each list item. what I want is click the button or List Item, the refresh button starts rotate. stops when the request finished.
I use animation as follows:
<?xml version="1.0" encoding="UTF-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:fillAfter="true"
android:fromDegrees="0"
android:interpolator="#android:anim/linear_interpolator"
android:pivotX="50%"
android:pivotY="50%"
android:repeatCount="infinite"
android:toDegrees="358" />
and some source code are here:
public void refresh(View v) {
Animation rotation = AnimationUtils.loadAnimation(mContext,
R.anim.rotate);
rotation.setFillAfter(true);
v.startAnimation(rotation);
}
public void completeRefresh(View v) {
v.clearAnimation();
}
when the request finished, I call notifyDataSetChanged() to refresh the LiseView.
the problem is that the button was indeed rotating. but when I click it the second time. it's rotating but a little fuzzy. just like this:
any suggestions? thanks a lot.
What is most likely happening on your second (and subsequent clicks) is that the animation is running on it again.
In your current implementation, try using setTag(...) like this:
public void refresh(View v) {
if(v.getTag() != null && (boolean)v.getTag()) {
//do nothing, since we are setting the tag to be true once pressed
} else {
//this view hasn't been clicked yet, show animation and set tag
v.setTag(true);
Animation rotation = AnimationUtils.loadAnimation(mContext, R.anim.rotate);
rotation.setFillAfter(true);
v.startAnimation(rotation);
}
}
In your Adapter, you should keep track of which list items are being animated (I'm assuming multiple items can be clicked at the same time). Once you know that the 'request' is finished, you can update the adapter with the correct items and then call notifyDataSetChanged()

Animate RecyclerView when scrolling

Is there any way to animate the elements of a RecyclerView when I scroll it?
I took a look at DefaultItemAnimator and RecyclerView.ItemAnimator, but that animations seems to be only called if the dataset has changed, please correct me if I am wrong.
I'm a little confused about RecyclerView.ItemAnimator.animateMove() when is it called? I put some breakpoints into that class but none of them stops my app.
However back to my question how can I animate the RecyclerView? I want that some elements have another opacity, depended on some custom rules.
I did some more reaseach it seems that animation move is exactly that what I'm looking for. That methods are called from dispatchLayout(). Here is the javadoc of that method:
Wrapper around layoutChildren() that handles animating changes caused by layout.
Animations work on the assumption that there are five different kinds of items
in play:
PERSISTENT: items are visible before and after layout
REMOVED: items were visible before layout and were removed by the app
ADDED: items did not exist before layout and were added by the app
DISAPPEARING: items exist in the data set before/after, but changed from
visible to non-visible in the process of layout (they were moved off
screen as a side-effect of other changes)
APPEARING: items exist in the data set before/after, but changed from
non-visible to visible in the process of layout (they were moved on
screen as a side-effect of other changes)
The overall approach figures out what items exist before/after layout and
infers one of the five above states for each of the items. Then the animations
are set up accordingly:
PERSISTENT views are moved ({#link ItemAnimator#animateMove(ViewHolder, int, int, int, int)})
REMOVED views are removed ({#link ItemAnimator#animateRemove(ViewHolder)})
ADDED views are added ({#link ItemAnimator#animateAdd(ViewHolder)})
DISAPPEARING views are moved off screen
APPEARING views are moved on screen
So far I'm looking for PERSISTENT, DISAPPEARING and APPEARING, but that methods are never called because of this line here:
boolean animateChangesSimple = mItemAnimator != null && mItemsAddedOrRemoved
&& !mItemsChanged;
mItemsAddedOrRemoved is simply always false so none of that callback are ever reached. Any idea how to set set flag correctly?
I ended in using an OnScrollListener and animating it in a custom animate() method. In my case that code takes just 2ms so that is no problem for the 60fps.
recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(int newState) {
if(newState == RecyclerView.SCROLL_STATE_IDLE) {
// special handler to avoid displaying half elements
scrollToNext();
}
animate();
}
#Override
public void onScrolled(int dx, int dy) {
animate();
}
});
I did it this way. Might help someone. I don't know whether it's the best way to do it but works fine for me.
UPDATE:
To fix fast scrolling behaviour, override onViewDetachedFromWindow method of the adapter and call clearAnimation on the animated view (in this case, holder.itemView.clearAnimation() ).
up_from_bottom.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="#android:anim/decelerate_interpolator">
<translate
android:fromXDelta="0%" android:toXDelta="0%"
android:fromYDelta="100%" android:toYDelta="0%"
android:duration="400" />
</set>
down_from_top.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="#android:anim/decelerate_interpolator">
<translate
android:fromXDelta="0%" android:toXDelta="0%"
android:fromYDelta="-100%" android:toYDelta="0%"
android:duration="400" />
</set>
And finally put this code in onBindViewHolder of recyclerView. Create a field called lastPosition and initialize it to -1.
Animation animation = AnimationUtils.loadAnimation(context,
(position > lastPosition) ? R.anim.up_from_bottom
: R.anim.down_from_top);
holder.itemView.startAnimation(animation);
lastPosition = position;
The good solution is to animate holder in adapter in onBindViewHolder method.
Snippet taken from Material Test project Slidenerd:
#Override
public void onBindViewHolder(ViewHolderBoxOffice holder, int position) {
Movie currentMovie = mListMovies.get(position);
//one or more fields of the Movie object may be null since they are fetched from the web
holder.movieTitle.setText(currentMovie.getTitle());
//retrieved date may be null
Date movieReleaseDate = currentMovie.getReleaseDateTheater();
if (movieReleaseDate != null) {
String formattedDate = mFormatter.format(movieReleaseDate);
holder.movieReleaseDate.setText(formattedDate);
} else {
holder.movieReleaseDate.setText(Constants.NA);
}
int audienceScore = currentMovie.getAudienceScore();
if (audienceScore == -1) {
holder.movieAudienceScore.setRating(0.0F);
holder.movieAudienceScore.setAlpha(0.5F);
} else {
holder.movieAudienceScore.setRating(audienceScore / 20.0F);
holder.movieAudienceScore.setAlpha(1.0F);
}
if (position > mPreviousPosition) {
AnimationUtils.animateSunblind(holder, true);
} else {
AnimationUtils.animateSunblind(holder, false);
}
mPreviousPosition = position;
here is a link

Android: Updating a LinearLayout position after animation is complete

Any help with the following problem would be greatly appreciated. I know what I need to do and I have checked the Developer docs, but the exact syntax I need to use eludes me (I'm a noob).
Here's what I'm doing. I have a translate.xml file in res/anim that works fine. It looks like this:
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXDelta="0%"
android:toXDelta="0%"
android:fromYDelta="0%"
android:toYDelta="10%"
android:repeatCount="0"
android:duration="1000"
android:fillEnabled="true"
android:fillAfter="true"/>
I'm executing my code like this:
l = (LinearLayout) findViewById(R.id.linearLayout1);
a = AnimationUtils.loadAnimation(this, R.anim.translate);
a.setAnimationListener(new AnimationListener() {
public void onAnimationStart(Animation anim){};
public void onAnimationRepeat(Animation anim){};
public void onAnimationEnd(Animation anim){
//l.setLayoutParams(params);
};
});
l.startAnimation(a);
When the animation is done I would like the LinearLayout it animated to move to it's new position (where the animation moved it to). The reason for this is the LinearLayout contains several form elements the user can interact with.
This is a real simple animation for a fairly simple project. It simply moves the element about 30 pixels down the screen. I wouldn't ask for help except I've been struggling with this for several hours now. I know I need to update the LinearLayout's parameters on the end of the animation, but how exactly? I've read of several different ways and they're all a bit confusing.
Thanks in advance.
Instead of creating a new AnimationListener, try implementing the AnimationListener interface to your current (or a new) class. Then just override the onAnimationEnd() method.
Example:
public class ThisClass implements AnimationListener {
private otherMethod() {
l.getAnimation().setAnimationListener(this);
}
public void onAnimationStart(Animation anim){};
public void onAnimationRepeat(Animation anim){};
public void onAnimationEnd(Animation anim){
l.setLayoutParams(params);
};
}
Finally got a way to work around,the right way to do this is setFillAfter(true),
if you want to define your animation in xml then you should do some thing like this
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="#android:anim/decelerate_interpolator"
android:fillAfter="true">
<translate
android:fromXDelta="0%"
android:toXDelta="-100%"
android:duration="1000"/>
</set>
you can see that i have defined filterAfter="true" in the set tag,if you try to define it in translate tag it won't work,might be a bug in the framework!!
and then in the Code
Animation anim = AnimationUtils.loadAnimation(this, R.anim.slide_out);
someView.startAnimation(anim);
OR
TranslateAnimation animation = new TranslateAnimation(-90, 150, 0, 0);
animation.setFillAfter(true);
animation.setDuration(1800);
someView.startAnimation(animation);
then it will surely work!!
Now this is a bit tricky it seems like the view is actually move to the new position but actually the pixels of the view are moved,i.e your view is actually at its initial position but not visible,you can test it if have you some button or clickable view in your view(in my case in layout),to fix that you have to manually move your view/layout to the new position
public TranslateAnimation (float fromXDelta, float toXDelta, float fromYDelta, float toYDelta)
new TranslateAnimation(-90, 150, 0, 0);
now as we can see that our animation will starts from -90 x-axis to 150 x-axis
so what we do is set
someView.setAnimationListener(this);
and in
public void onAnimationEnd(Animation animation)
{
someView.layout(150, 0, someView.getWidth() + 150, someView.getHeight());
}
now let me explain public void layout (int left, int top, int right, int botton)
it moves your layout to new position first argument define the left,which we is 150,because translate animation has animated our view to 150 x-axis, top is 0 because we haven't animated y-axis,now in right we have done someView.getWidth() + 150 basically we get the width of our view and added 150 because we our left is now move to 150 x-axis to make the view width to its originall one, and bottom is equals to the height of our view.
I hope you people now understood the concept of translating, and still you have any questions you can ask right away in comment section,i feel pleasure to help :)
EDIT Don't use layout() method as it can be called by the framework when ever view is invalidated and your changes won't presist, use LayoutParams to set your layout parameters according to your requirement

Categories

Resources