Custom animation when item removed in recycleview - android

I'm trying to fade out items when it's removed then collapse recycleview. But it doesn't work.
Please help me
for(Object appData : mInvisibleEntries){
mVisibleEntries.remove(appData);
}
for(View view:viewHoldersList){
Animation a = new AlphaAnimation(1.00f, 0.00f);
a.setDuration(2000);
view.startAnimation(a);
}
notifyItemRangeRemoved(MAX_VISIBLE_APPS_COUNT + 1, mInvisibleEntries.size());
collapseRv();
private void collapseRv(){
final int initialHeight = mRecyclerView.getMeasuredHeight();
ValueAnimator valueAnimator = ValueAnimator.ofInt(initialHeight,HEIGHT_VIEW_APPDATA*3+HEIGHT_SECTION_FOOTER);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
mRecyclerView.getLayoutParams().height = (int) animation.getAnimatedValue();
mRecyclerView.requestLayout();
}
});
valueAnimator.setInterpolator(new DecelerateInterpolator());
valueAnimator.setDuration(2000);
valueAnimator.start();
}

To make it simlpe, You can use library like https://github.com/wasabeef/recyclerview-animators

Related

ValueAnimator working with Button but not with LinearLayout

The following code is working when the supplied view is a Button but when it's a LinearLayout nothing happens (Background color doesn't change).
If I manually set the color on the LinearLayout without the ValueAnimator it works. I also tried using a ObjectAnimator but the result looked terrible.
An example call:
playBlinkAnimation(view, activity.getResources().getColor(R.color.transparent), activity.getResources().getColor(R.color.colorRed), 5000);
view.getBackground().setColorFilter(activity.getResources().getColor(R.color.colorRed), PorterDuff.Mode.DARKEN);
private void playBlinkAnimation(final View view, int colorFrom, int colorTo, int duration) {
ValueAnimator colorAnimation = new ValueAnimator();
colorAnimation.setIntValues(colorFrom, colorTo);
colorAnimation.setEvaluator(new ArgbEvaluator());
colorAnimation.setDuration(duration);
colorAnimation.setRepeatCount(ValueAnimator.INFINITE);
colorAnimation.setRepeatMode(ValueAnimator.REVERSE);
colorAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animator) {
view.getBackground().setColorFilter((int) animator.getAnimatedValue(), PorterDuff.Mode.DARKEN);
}
});
colorAnimation.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
}
#Override
public void onAnimationEnd(Animator animation) {
view.getBackground().setColorFilter(null);
}
#Override
public void onAnimationCancel(Animator animation) {
view.getBackground().setColorFilter(null);
view.setAlpha(1);
view.getBackground().setColorFilter(null);
}
#Override
public void onAnimationRepeat(Animator animation) {
}
});
colorAnimation.start();
}
You can try using AnimatorSet and it's playTogether function. It takes an array of Animators, and it's designed to run multiple animations together, but it should work with only one animation as well.
Hope that helps you!
Since you seem to want your layout to transition from transparent background to opaque red, you should animate the layout's alpha parameter
ObjectAnimator animator = ObjectAnimator.ofInt(view, "alpha", 0, 1);
animator.setDuration(5000);
animator.setInterpolator(new LinearInterpolator());
animator.start();

How to playSequentially a list of AnimatorSet?

I'm trying to make an animation of an imageview that revolves around a circle shape.
Here is the currrent code who works but without repeating the animation with different values:
public void runAnimation(){
ImageView worldView=findViewById(R.id.imageView);
int radius=worldView.getHeight()*30/70;
int centerx = worldView.getLeft()+radius;
int centery = worldView.getTop()+radius;
//List<Animator> myList = new ArrayList<>();
for (int i=0;i<360;i++) {
/*---I calculate the points of the circle---*/
int angle= (int) ((i * 2 * Math.PI) / 360);
int x= (int) (centerx+(radius*Math.cos(angle)));
int y= (int) (centery+(radius*Math.sin(angle)));
/*---Here carView is the ImageView that need to turn around the worldView---*/
ObjectAnimator animatorX =ObjectAnimator.ofFloat(carView, "x",x);
ObjectAnimator animatorY =ObjectAnimator.ofFloat(carView, "y",y);
ObjectAnimator animatorR =ObjectAnimator.ofFloat(carView, "rotation", i);
animatorX.setDuration(500);
animatorY.setDuration(500);
animatorR.setDuration(500);
AnimatorSet animatorSet=new AnimatorSet();
animatorSet.playTogether(animatorX,animatorY,animatorR);
animatorSet.start();
//myList.add(animatorSet);
}
//AnimatorSet animatorSet=new AnimatorSet();
//animatorSet.playSequentially(myList);
}
The commentary ("//") are here to illustrate what I want to create.
Thank in advance for your help.
You can add a listener to each AnimatorSet by using addListener(Animator.AnimatorListener listener).
for (int i=0;i<360;i++) {
// ...skipped some lines here...
AnimatorSet animatorSet=new AnimatorSet();
animatorSet.playTogether(animatorX,animatorY,animatorR);
myList.add(animatorSet);
animatorSet.addListener(myListener);
}
where myListener is defined as follows:
private Animator.AnimatorListener myListener = new Animator.AnimatorListener(){
#Override
public void onAnimationStart(Animator animation){
// no op
}
#Override
public void onAnimationRepeat(Animator animation){
// no op
}
#Override
public void onAnimationCancel(Animator animation){
// no op
}
#Override
public void onAnimationEnd(Animator animation){
startNextAnimation();
}
};
In addition to that, you need some variable private int counter; to iterate over the list.
Before starting the first animation, you set it to zero:
counter = 0;
myList.get(0).start();
To start the next animation (if there is one left):
private void startNextAnimation(){
counter++;
if(counter == myList.size()){
return;
}
myList.get(counter).start();
}

Disabling animations on a device crashes the app

I have an AnimationDrawable, which plays a frame animation and then the next Activity is started with a circular reveal animation:
#Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
AnimationDrawable animationDrawable =
(AnimationDrawable) mAnimationSceneImage.getDrawable();
animationDrawable.start();
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
startMapActivityWithAnimation();
}
}, 1000);
}
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void startMapActivityWithAnimation() {
int colorFrom = ContextCompat.getColor(this, R.color.window_background_splash);
int colorTo = ContextCompat.getColor(this, android.R.color.white);
ValueAnimator colorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), colorFrom, colorTo);
colorAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
mCircularRevealView.setBackgroundColor((Integer) valueAnimator.getAnimatedValue());
}
});
int cx = mCircularRevealView.getWidth() / 2;
int cy = mCircularRevealView.getHeight() / 2;
float finalRadius = Math.max(cx, cy);
Animator circularRevealAnimation = ViewAnimationUtils
.createCircularReveal(mCircularRevealView, cx, cy, 0, finalRadius);
mCircularRevealView.setVisibility(View.VISIBLE);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.setDuration(200);
animatorSet.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationStart(Animator animation) {
mLogoImage.animate()
.alpha(0.0f)
.setDuration(200)
.setInterpolator(new AccelerateInterpolator())
.start();
}
#Override
public void onAnimationEnd(Animator animation) {
startMapActivity();
}
});
animatorSet.playTogether(colorAnimation, circularRevealAnimation);
animatorSet.start();
}
The animations run perfectly on a normal device. I also have some Espresso UI tests, so I've disabled all the animations in the developer options screen on the test device and now I'm getting the following exception:
java.lang.IllegalStateException: Animator has already started, cannot change it now!
at android.view.RenderNodeAnimator.checkMutable(RenderNodeAnimator.java:149)
at android.view.RenderNodeAnimator.setDuration(RenderNodeAnimator.java:324)
at android.view.RenderNodeAnimator.setDuration(RenderNodeAnimator.java:322)
at android.animation.AnimatorSet.updateAnimatorsDuration(AnimatorSet.java:760)
at android.animation.AnimatorSet.getTotalDuration(AnimatorSet.java:1721)
at android.animation.AnimatorSet.forceToEnd(AnimatorSet.java:446)
at android.animation.AnimatorSet.doAnimationFrame(AnimatorSet.java:981)
at android.animation.AnimationHandler.doAnimationFrame(AnimationHandler.java:145)
at android.animation.AnimationHandler.-wrap2(Unknown Source:0)
at android.animation.AnimationHandler$1.doFrame(AnimationHandler.java:54)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:884)
at android.view.Choreographer.doCallbacks(Choreographer.java:698)
at android.view.Choreographer.doFrame(Choreographer.java:630)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:872)
at android.os.Handler.handleCallback(Handler.java:769)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6540)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
Do you have any suggestions how to fix this problem?
I met the same problem and I have resolved it. You can't use method setDuration in class AnimatorSet, it may cause this problem on devices 8.0. You can use method setDuration in each Animator instead.
private void startMapActivityWithAnimation() {
int colorFrom = ContextCompat.getColor(this, R.color.window_background_splash);
int colorTo = ContextCompat.getColor(this, android.R.color.white);
ValueAnimator colorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), colorFrom, colorTo);
colorAnimation.setDuration(200);
colorAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
mCircularRevealView.setBackgroundColor((Integer) valueAnimator.getAnimatedValue());
}
});
int cx = mCircularRevealView.getWidth() / 2;
int cy = mCircularRevealView.getHeight() / 2;
float finalRadius = Math.max(cx, cy);
Animator circularRevealAnimation = ViewAnimationUtils
.createCircularReveal(mCircularRevealView, cx, cy, 0, finalRadius);
circularRevealAnimation.setDuration(200);
mCircularRevealView.setVisibility(View.VISIBLE);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationStart(Animator animation) {
mLogoImage.animate()
.alpha(0.0f)
.setDuration(200)
.setInterpolator(new AccelerateInterpolator())
.start();
}
#Override
public void onAnimationEnd(Animator animation) {
startMapActivity();
}
});
animatorSet.playTogether(colorAnimation, circularRevealAnimation);
animatorSet.start();
}
What about checking if the animator has already started?
if (!animatorSet.isStarted()) {
animatorSet.start();
}
You could enable the animations for that specific test in the #Before method. After the test is done, you could disable the animations again in the #After method. That way your subsequent tests will not get affected.
You could also create a test Rule to enable/disable animations for a specific class as shown here

How to implement increasing number animation from 0 to 600 in 5 secs on TextVIew on android

I plan to implement integer number increase on textView from 0 to some value with animation within certain seconds.
e.g show animation which increase number from 0 to 600 on textview for 5 seconds duration.
How can I implement this?
You could use the ValueAnimator for that:
private void startCountAnimation() {
ValueAnimator animator = ValueAnimator.ofInt(0, 600);
animator.setDuration(5000);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
public void onAnimationUpdate(ValueAnimator animation) {
textView.setText(animation.getAnimatedValue().toString());
}
});
animator.start();
}
Take a look at this simple solution:
public void animateTextView(int initialValue, int finalValue, final TextView textview) {
ValueAnimator valueAnimator = ValueAnimator.ofInt(initialValue, finalValue);
valueAnimator.setDuration(1500);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
textview.setText(valueAnimator.getAnimatedValue().toString());
}
});
valueAnimator.start();
}
Use a ValueAnimator
TextView textview = findViewById(R.id.textview1);
ValueAnimator valueAnimator = ValueAnimator.ofInt(0, 600);
valueAnimator.setDuration(5000);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
textview.setText(valueAnimator.getAnimatedValue().toString());
}
});
valueAnimator.start();
I propose answer here for Kotlin developers :
fun startAnimation(textView: TextView) {
val animator = ValueAnimator.ofInt(0, 600)
animator.duration = 5000 // 5 seconds
animator.addUpdateListener { animation ->
textView.text = animation.animatedValue.toString()
}
animator.start()
}
Look here :
Animate TextView to increase integer and stop at some point?
and a nice lib here : https://github.com/sd6352051/RiseNumber

Android padding left animation in RelativeLayout

I am trying to create a padding left animation in RelativeLayout. I wrote code which can animate left in click listener.
This is my code, but it is not working completely.
list.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
holder = (UserHolder) view.getTag();
layoutParams = (RelativeLayout.LayoutParams) holder.layoutmain
.getLayoutParams();
if (holder.layout.getVisibility() != View.VISIBLE) {
ValueAnimator varl = ValueAnimator.ofInt(-170);
varl.setDuration(1000);
varl.addUpdateListener(new AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
layoutParams.setMargins(
(Integer) animation.getAnimatedValue(), 0,
0, 0);
holder.layoutmain.setLayoutParams(layoutParams);
holder.layout.setVisibility(View.VISIBLE);
}
});
varl.start();
}
else
{
ValueAnimator varl = ValueAnimator.ofInt(0);
varl.setDuration(1000);
varl.addUpdateListener(new AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(
ValueAnimator animation) {
layoutParams.setMargins(0, 0,
(Integer) animation.getAnimatedValue(),
0);
// lp.setMargins(left, top, right, bottom)
holder.layoutmain.setLayoutParams(layoutParams);
holder.layout.setVisibility(View.INVISIBLE);
}
});
varl.start();
}
}
});
The first time, it works (I can animate padding left), but the second time I click the animation is not working. What am I doing wrong?
Through ValueAnimator class you can update margin or padding of any with animation. Please go through the following code :
ValueAnimator animator = ValueAnimator.ofInt(0,50);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator){
frameLayout.setPadding(0, (Integer) valueAnimator.getAnimatedValue(),0,0);
}
});
animator.setInterpolator(new DecelerateInterpolator(2));
animator.start();
Let me know in case of more explanation in comments.
You should try using ValueAnimator.ofInt(fromInt,toInt)
//first
ValueAnimator.ofInt(-70,0)
//second
ValueAnimator.ofInt(0,-70)
Otherwise the value animator doesn't know from or to which value it should animate.

Categories

Resources