Android circle reveal animation not smooth - android

am creating login and signup in same page with circle reveal animation ,switch the view using a floating action button, it very lag when switching one view to another view,
Login page Contain two relative layout and a floating action button
one view for login and other for signup
when floating action button click view will switch to another ie login to signup and vise versa.. i achieved but it is too lag how can i make it smooth
in tab(big screen) it works very smoothly(am creating two layout one for mobile and other for tab)
can anyone help me.. this is my code..
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void viewMenu() {
if (!isOpen) {
// int x = layoutContent.getRight();
// int y = layoutContent.getBottom();
int x = Math.round(fab.getX() + fab.getWidth() / 2);
int y = Math.round(fab.getY() - fab.getHeight());
int startRadius = 0;
int endRadius = (int) Math.hypot(layoutMain.getWidth(), layoutMain.getHeight());
fab.setBackgroundTintList(ColorStateList.valueOf(ResourcesCompat.getColor(getResources(),android.R.color.white,null)));
fab.setImageResource(R.drawable.ic_cross);
Animator anim = ViewAnimationUtils.createCircularReveal(layoutButtons, x, y, startRadius, endRadius);
anim.setInterpolator(new AccelerateDecelerateInterpolator());
layoutButtons.setVisibility(View.VISIBLE);
anim.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animator) {
// fst_view.setVisibility(View.GONE);
}
#Override
public void onAnimationEnd(Animator animator) {
}
#Override
public void onAnimationCancel(Animator animator) {
}
#Override
public void onAnimationRepeat(Animator animator) {
}
});
anim.start();
isOpen = true;
} else {
// int x = layoutButtons.getRight();
// int y = layoutButtons.getBottom();
int x = Math.round(fab.getX() + fab.getWidth() / 2);
int y = Math.round(fab.getY() + fab.getHeight()/2) - toolbar.getHeight();
int startRadius = Math.max(layoutContent.getWidth(), layoutContent.getHeight());
int endRadius = 0;
fab.setBackgroundTintList(ColorStateList.valueOf(ResourcesCompat.getColor(getResources(),R.color.colorAccent,null)));
fab.setImageResource(R.drawable.ic_menu_camera);
// fst_view.setVisibility(View.VISIBLE);
Animator anim = ViewAnimationUtils.createCircularReveal(layoutButtons, x, y, startRadius, endRadius);
anim.setInterpolator(new AccelerateDecelerateInterpolator());
anim.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animator) {
}
#Override
public void onAnimationEnd(Animator animator) {
layoutButtons.setVisibility(View.GONE);
}
#Override
public void onAnimationCancel(Animator animator) {
}
#Override
public void onAnimationRepeat(Animator animator) {
}
});
anim.start();
isOpen = false;
}
}

As far as I can see, you could use FastOutLinearInInterpolator() instead of AccelerateDecelerateInterpolator(), and add anim.setDuration() with animation duration you want.
And set layoutButtons.setVisibility() to View.INVISIBLE like described here in the bottom of the article.
Furthermore, you can rid of from Math.round() when you calculate view x, y coordinates.
It worked great for my case.
Here is my example code

Related

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();
}

Android CircularReveal library View visibility bug

I use this libary to create CircularReveal animation on pre-Lollipop devices. The problem is in hiding View with animation. Animation is performed as well, but after animation end, View become visible for a second and then disappears. How can I prevent blinking of View?
Here is my method for hiding View with CircularReveal animation:
public static void revealCloseTopRight(final View view) {
int cx = view.getRight();
int cy = view.getTop();
// get the final radius for the clipping circle
int dx = Math.max(cx, view.getWidth() - cx);
int dy = Math.max(cy, view.getHeight() - cy);
float finalRadius = (float) Math.hypot(dx, dy);
SupportAnimator animator = ViewAnimationUtils.createCircularReveal(view, cx, cy, 0, finalRadius);
animator.setInterpolator(new AccelerateDecelerateInterpolator());
animator.setDuration(animDuration);
animator = animator.reverse();
try {
animator.start();
} catch (Exception ex) {
ex.printStackTrace();
}
view.postDelayed(new Runnable() {
#Override
public void run() {
view.setVisibility(View.INVISIBLE);
}
}, animDuration);
}
UPDATE
I also tried to add SupportAnimator.AnimatorListener() like this:
animator.addListener(new SupportAnimator.AnimatorListener() {
#Override
public void onAnimationStart() {
Log.d(AnimationSupport.TAG, TAG + " -> 1onAnimationStart()");
}
#Override
public void onAnimationEnd() {
Log.d(AnimationSupport.TAG, TAG + " -> 1onAnimationEnd()");
view.setVisibility(View.INVISIBLE);
}
#Override
public void onAnimationCancel() {
Log.d(AnimationSupport.TAG, TAG + " -> 1onAnimationCancel()");
}
#Override
public void onAnimationRepeat() {
Log.d(AnimationSupport.TAG, TAG + " -> 1onAnimationRepeat()");
}
});
And Animator.AnimatorListener() like this:
animator.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
Log.d(AnimationSupport.TAG, TAG + " -> onAnimationStart()");
}
#Override
public void onAnimationEnd(Animator animation) {
Log.d(AnimationSupport.TAG, TAG + " -> onAnimationEnd()");
view.setVisibility(View.INVISIBLE);
}
#Override
public void onAnimationCancel(Animator animation) {
Log.d(AnimationSupport.TAG, TAG + " -> onAnimationCancel()");
}
#Override
public void onAnimationRepeat(Animator animation) {
Log.d(AnimationSupport.TAG, TAG + " -> onAnimationRepeat()");
}
});
In both cases none on this callbacks are never called. I have no idea why.
Make sure that in your layout where you're trying to animate the view, there is no
android:animateLayoutChanges="true"
property in the root viewGroup.
Removing that will help you to overcome blinking view after animation end and setting visibility to GONE (or INVISIBLE).
The view is being visible because there is a very small delay between the animation completing and your handler's execution.
You can solve this problem by adding an animation listener to your circular reveal animation and setting the view to invisible in the onAnimationEnd() callback.

Api 21 Circular Reveal Animation not working

I can't get the circular reveal animation to work.
I think I checked the most obvious things:
It starts, width and height are > 0 and it is visible, no Exception..
I load some data from the internet and display it in the view(fab)
The animation should only play after the download finishes.
TmdbHelper helper = new TmdbHelper();
helper.getMovieById(id, "en", new TmdbHelper.ResultListener() {
#Override
public void onResultReceived(JSONObject result) {
// called when finished downloading
try {
String rating = result.getString("vote_average");
AnimationHelper.circularReveal(fab, 500, 0);
fab.setText(rating);
} catch (JSONException e) {
e.printStackTrace();
}
}
});
AnimationHelper:
public static void circularReveal(final View view, final long duration, long startDelay) {
// get the center for the clipping circle
int cx = (view.getLeft() + view.getRight()) / 2;
int cy = (view.getTop() + view.getBottom()) / 2;
// get the final radius for the clipping circle
int finalRadius = Math.max(view.getWidth(), view.getHeight());
// create the animator for this view (the start radius is zero)
Animator anim =
ViewAnimationUtils.createCircularReveal(view, cx, cy, 0, finalRadius);
anim.setDuration(duration);
anim.setStartDelay(startDelay);
anim.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
view.setVisibility(View.VISIBLE);
}
#Override
public void onAnimationEnd(Animator animation) {
}
#Override
public void onAnimationCancel(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {}
});
// make the view visible and start the animation
anim.start();
}
I use the circular reveal animation in other parts like this to make sure the view is attached, and it works:
headerContainer.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
headerContainer.getViewTreeObserver().removeOnGlobalLayoutListener(this);
AnimationHelper.circularReveal(headerContainer, 500, 200);
}
});
Perhaps you should erase this line inside your onResultRecieved():
fab.setVisibility(View.VISIBLE);
My assumption is that your circular reveal method is working just fine. It is because of you have made the FAB visible before the animation even begin, you can't see it in action.
As an addition, those lines you've shown which is working doesn't have fab.setVisibility(View.VISIBLE) called anywhere in it.
1st Approach:
Try Transition Listener.
getWindow().getSharedElementExitTransition().addListener(new Transition.TransitionListener() {
#Override
public void onTransitionStart(Transition transition) {
}
#Override
public void onTransitionEnd(Transition transition) {
}
#Override
public void onTransitionCancel(Transition transition) {
}
#Override
public void onTransitionPause(Transition transition) {
}
#Override
public void onTransitionResume(Transition transition) {
}
});
2nd Approach: Try setting start delay and listener to the reveal animation and when animation starts then set the view visible
if (Build.VERSION.SDK_INT >= 21) {
Animator anim = ViewAnimationUtils.createCircularReveal(viewRoot, cx, cy, 0, finalRadius);
anim.setStartDelay(300);
anim.setDuration(1000);
anim.setInterpolator(new DecelerateInterpolator());
anim.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
viewRoot.setVisibility(View.VISIBLE);
}
#Override
public void onAnimationEnd(Animator animation) {
}
#Override
public void onAnimationCancel(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
}
});
anim.start();
}
}
#Override
public void onAnimationCancel(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
}
});
anim.start();

Add delay before repeat animation with valueAnimator

I'm trying a simple example like having a TextView and translate it from 0% to 100% of the screen width
code is :
anim0 = ObjectAnimator.ofFloat(textViewId00, "translationX", -120f, 480f);
where 480f is the width of my screen.
What I want is the next N times ( n=5 for my example ) to add a delay before it starts.
I have tried to add the delay with setStartDelay() method on onAnimationRepeat but there is no effect.
My code is :
textViewId00 = (TextView) findViewById(R.id.textViewId00);
anim0 = ObjectAnimator.ofFloat(textViewId00, "translationX", -120f, 480f);
anim0.setDuration(2000);
anim0.setRepeatCount(5);
anim0.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
Log.i(TAG, "anim0 onAnimationStart ");
textViewId00.setVisibility(View.VISIBLE);
}
#Override
public void onAnimationEnd(Animator animation) {
Log.i(TAG, "anim0 onAnimationEND " );
}
#Override
public void onAnimationCancel(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
Log.i(TAG, "anim0 onAnimation REPEAT " );
anim0.setStartDelay(14000);
}
});
anim0.start();
The textView appears to the screen, moves until it disappears and then again from start without any delay.
I have just tried it using this code and it looks like it is doing what you want it to:
public void animateView() {
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
final int screenWidth = size.x;
final ObjectAnimator anim0 = ObjectAnimator.ofFloat(textviewId00, "translationX", -120f, screenWidth);
anim0.setDuration(2000);
anim0.addListener(new Animator.AnimatorListener() {
int count;
#Override
public void onAnimationStart(Animator animation) {
textViewId00.setVisibility(View.VISIBLE);
}
#Override
public void onAnimationEnd(Animator animation) {
if (++count < 5) {
anim0.setStartDelay(14000);
anim0.start();
}
}
#Override
public void onAnimationCancel(Animator animation) {}
#Override
public void onAnimationRepeat(Animator animation) {}
});
anim0.start();
}

Move an ImageView to different a position using animation in Android

I have several ImageViews in a RelativeLayout.
When the user taps any of the ImageViews, I want the ImageView to be moved to a specified location using a subtle animation.
Eg; I have initially set margins for LayoutParams associated with an ImageView as layoutparams1.setMargins(90,70,0,0); and I have then added it to the layout.
When the ImageView is tapped, I'd like its new location to be 200,200, done with animation.
So, is it possible? if yes, then how?
Note that I have both RelativeLayout and all of its child ImageViews created programmatically.
And I'm new to Android development so an elaborative answer is expected.
TranslateAnimation animation = new TranslateAnimation(0, 50, 0, 100);
animation.setDuration(1000);
animation.setFillAfter(false);
animation.setAnimationListener(new MyAnimationListener());
imageView.startAnimation(animation);
UPDATE :
The problem is that the View is actually still in it's old position. So we have to move it when the animation is finished. To detect when the animation is finished we have to create our own animationListener (inside our activity class):
private class MyAnimationListener implements AnimationListener{
#Override
public void onAnimationEnd(Animation animation) {
imageView.clearAnimation();
LayoutParams lp = new LayoutParams(imageView.getWidth(), imageView.getHeight());
lp.setMargins(50, 100, 0, 0);
imageView.setLayoutParams(lp);
}
#Override
public void onAnimationRepeat(Animation animation) {
}
#Override
public void onAnimationStart(Animation animation) {
}
}
So the onClickEvent will get fired again at it's new place.
The animation will now move it even more down, so you might want to save the x and y in a variable, so that in the onAnimationEnd() you move it not to a fix location.
It is better to use ObjectAnimator which actually moves the ImageView to the new position.
E.g.:
ImageView splash;
#Override
public boolean onTouchEvent(MotionEvent event) {
float tx = event.getX();
float ty = event.getY();
int action = event.getAction();
switch(action) {
case MotionEvent.ACTION_DOWN:
tx = event.getX();
ty = event.getY();
// findViewById(R.id.character).setX(tx-45);
// findViewById(R.id.character).setY(ty-134);
ObjectAnimator animX = ObjectAnimator.ofFloat(splash, "x", tx-45);
ObjectAnimator animY = ObjectAnimator.ofFloat(splash, "y", ty-134);
AnimatorSet animSetXY = new AnimatorSet();
animSetXY.playTogether(animX, animY);
animSetXY.start();
break;
default:
}
return true;
}
you can use this code
imageView.animate().x(80).y(212).setDuration(300);
or
for soft animation you can use this library
https://github.com/wirecube/android_additive_animations
In below code I am adding a image view in center on frame layout dynamically. After add I am increase scaling and set alpha to give zoom effect and after complete animation I am just translate my image view one position to another position.
Add image view on framelayout
imgHeart = new ImageView(getBaseContext());
imgHeart.setId(R.id.heartImage);
imgHeart.setImageResource(R.drawable.material_heart_fill_icon);
imgHeart.setLayoutParams(new FrameLayout.LayoutParams(50, 50, Gravity.CENTER));
mainFrameLaout.addView(imgHeart);
Add animation on image view
imgHeart.animate()
.scaleXBy(6)
.scaleYBy(6)
.setDuration(700)
.alpha(2)
.setListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
}
#Override
public void onAnimationEnd(Animator animation) {
imgHeart.animate()
.scaleXBy(-6f).scaleYBy(-6f)
.alpha(.1f)
.translationX((heigthAndWidth[0] / 2) - minusWidth)
.translationY(-((heigthAndWidth[1] / 2) - minusHeight))
.setDuration(1000)
.setListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
}
#Override
public void onAnimationEnd(Animator animation) {
// remove image view from framlayout
}
#Override
public void onAnimationCancel(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
}
}).start();
}
#Override
public void onAnimationCancel(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
}
}).start();
you can use this code :)
private void animeView(View imageView){
Handler handler = new Handler();
final int[] deltaX = {50};
final int[] deltaRotation = {45};
handler.postDelayed(new Runnable() {
#Override
public void run() {
imageView.animate().translationX(deltaX[0])
.rotation(deltaRotation[0]).setDuration(1000) ;
deltaX[0] *=-1 ;
deltaRotation[0] *=-1 ;
handler.postDelayed(this , 1000);
}
},1000);
}

Categories

Resources