When I click the image, I want there to be a smooth object animator animation. Right now it hops to the coordinates, then it animates. Any suggestions? Here's the code:
testImage = (ImageView) findViewById(R.id.testImage);
testImage.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (depends) {
anim = ObjectAnimator.ofFloat(testImage, "translationY", 0.f, +90);
anim.setDuration(1000);
anim.start();
depends = false;
} else {
depends = true;
anim = ObjectAnimator.ofFloat(testImage, "translationY", 0.f, -90);
anim.setDuration(1000);
anim.start();
}
}
});
Don't give him a start value, pass only the target value. It will use getTranslationY() to get the start value.
anim = ObjectAnimator.ofFloat(testImage, "translationY", depends ? +90 : -90);
anim.setDuration(1000);
anim.start();
depends = !depends;
Related
I know how it can be applied to the toolbar w.r.t. any scrollView in Coordinator layout.
I wanna do the same thing with the button w.r.t. RecycleView.
Just like the bottomNav in the app Pinterest.
Thanks!
A simple way that comes to mind is to use the TranslateAnimation provided by Android and to check if the RecyclerView is being scrolled. Here is what you need to do
Add a scroll listener to the RecyclerView and check if the scrolling direction is downward or upward
YourRecyclerView.addScrollListener(new ScrollListener() {
someScrollListenerMethod() {
if (scrolling up) {
showButton();
} else {
hideButton();
}
}
);
Create an animation for sliding the button up and down.
slideDownAnimation = TranslateAnimation(0f, 0f, 0f, ScreenHeight)
slideDownAnimation.duration = 1000f //1 second
slideUpAnimation = TranslateAnimation(0f, 0f, ScreenHeight, 0f)
slideUpAnimation.duration = 1000f //1 second
Create the show and hide button methods which will show and hide the button
private void showButton() {
yourButton.visibility = View.VISIBLE;
yourButton.startAnimation(slideUpAnimation);
}
private void hideButton() {
yourButton.visibility = View.INVISIBLE;
yourButton.startAnimation(slideDownAnimation);
}
Just a note, the code shared in step 1 is not the actual library code (I could not remember the exact code) but you can easily find it out.
Here's the applied code as explained by Bilal. Just in case anybody need it,
private void buttonSlideAnimation() {
addButton = findViewById(R.id.bottom_add_button);
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int height = displayMetrics.heightPixels;
final TranslateAnimation slideDownAnimation = new TranslateAnimation(0f, 0f, 0f, height);
final TranslateAnimation slideUpAnimation = new TranslateAnimation(0f, 0f, height, 0f);
slideDownAnimation.setDuration(1000);
slideUpAnimation.setDuration(1000);
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(#NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
#Override
public void onScrolled(#NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if (dy>0){
addButton.setVisibility(View.INVISIBLE);
addButton.startAnimation(slideDownAnimation);
} else {
addButton.setVisibility(View.VISIBLE);
addButton.startAnimation(slideUpAnimation);
}
}
});
}
I am trying to mimic animation and the color change for the following floating action button.
The way the floating action button works is white is off and blue is on.
However, I have been unsuccessful with the animation and changing the color.
These have been my attempts at doing this, as you can see I have commented out all the different ways I have tried to do this.
This is my code:
#SuppressWarnings("unused")
#OnClick(R.id.fabMovieFavourite)
public void addMovieFavourite(View view) {
/* final Animator animator = AnimatorInflater.loadAnimator(getActivity(), R.animator.add_favourite_movie);
animator.setTarget(view);)
animator.start();
*/
/*
AnimatorSet animatorSet = new AnimatorSet();
PropertyValuesHolder propertyValuesHolderX = PropertyValuesHolder.ofFloat(View.SCALE_X, 1.1f);
PropertyValuesHolder propertyValuesHolderY = PropertyValuesHolder.ofFloat(View.SCALE_Y, 1.1f);
ObjectAnimator objectAnimator = ObjectAnimator.ofPropertyValuesHolder(view, propertyValuesHolderX, propertyValuesHolderY);
objectAnimator.setDuration(300);
objectAnimator.setInterpolator(new OvershootInterpolator(10f));
*/
/*
objectAnimator.setRepeatCount(1);
objectAnimator.setRepeatMode(ObjectAnimator.REVERSE);
*/
/*
PropertyValuesHolder propertyValuesHolderX2 = PropertyValuesHolder.ofFloat(View.SCALE_X, 0.9f);
PropertyValuesHolder propertyValuesHolderY2 = PropertyValuesHolder.ofFloat(View.SCALE_Y, 0.9f);
ObjectAnimator objectAnimator2 = ObjectAnimator.ofPropertyValuesHolder(view, propertyValuesHolderX2, propertyValuesHolderY2);
objectAnimator.setDuration(300);
objectAnimator2.setInterpolator(new OvershootInterpolator(10f));
animatorSet.playSequentially(objectAnimator, objectAnimator2);
objectAnimator.start();
*/
// view.BackgroundTintList(ContextCompat.getColorStateList(getContext(), R.color.primary));
//view.setBackgroundColor(ContextCompat.getColor(getActivity(), R.color.primary));
if(Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
Timber.d("start translationZ");
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(view, View.TRANSLATION_Z, 12f);
objectAnimator.setDuration(300);
objectAnimator.setInterpolator(new OvershootInterpolator(10f));
objectAnimator.setTarget(view);
objectAnimator.start();
}
}
Many thanks for any suggestions.
There're two phases in this animation. First one scales X and Y axis, and second one downscales it. So, we can divide them into two AnimatorSets and play them sequentially.
The key point of the animation is to find appropriate interpolator for the second AnimatorSet, because it's not standard one.
See, we want fab to overshoot, then undershoot and then finally settle up to the specified value in the animator.
Luckily, there's very handy PathInterpolator, which will create an interpolator for us with provided Path.
Path path = new Path();
path.moveTo(0.0f, 0.0f);
path.lineTo(0.5f, 1.3f);
path.lineTo(0.75f, 0.8f);
path.lineTo(1.0f, 1.0f);
PathInterpolator pathInterpolator = new PathInterpolator(path);
So, let's create the first animation:
final float from = 1.0f;
final float to = 1.3f;
ObjectAnimator scaleX = ObjectAnimator.ofFloat(fab, View.SCALE_X, from, to);
ObjectAnimator scaleY = ObjectAnimator.ofFloat(fab, View.SCALE_Y, from, to);
ObjectAnimator translationZ = ObjectAnimator.ofFloat(fab, View.TRANSLATION_Z, from, to);
AnimatorSet set1 = new AnimatorSet();
set1.playTogether(scaleX, scaleY, translationZ);
set1.setDuration(100);
set1.setInterpolator(new AccelerateInterpolator());
set1.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
fab.setImageResource(isActive ? R.drawable.heart_active : R.drawable.heart_passive);
fab.setBackgroundTintList(ColorStateList.valueOf(isActive ? colorActive : colorPassive));
isActive = !isActive;
}
});
We are scaling both x, y. Also, we are changing z translation to have appropriate shadow effect. When animation ends, we want to change fab state (color of heart and fab background).
Now let's create the animation to settle back:
ObjectAnimator scaleXBack = ObjectAnimator.ofFloat(fab, View.SCALE_X, to, from);
ObjectAnimator scaleYBack = ObjectAnimator.ofFloat(fab, View.SCALE_Y, to, from);
ObjectAnimator translationZBack = ObjectAnimator.ofFloat(fab, View.TRANSLATION_Z, to, from);
AnimatorSet set2 = new AnimatorSet();
set2.playTogether(scaleXBack, scaleYBack, translationZBack);
set2.setDuration(300);
set2.setInterpolator(pathInterpolator);
See here, we used pathInterpolator that we created earlier.
We want to play those two AnimatorSets sequentially:
final AnimatorSet set = new AnimatorSet();
set.playSequentially(set1, set2);
set.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
fab.setClickable(true);
}
#Override
public void onAnimationStart(Animator animation) {
fab.setClickable(false);
}
});
Also, we want to disable clicks on fab whilst animating it. So we are turning it on/off depending on animation state.
Finally, we launch the animation when a click happens:
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
set.start();
}
});
Result:
Source code at github
I am trying to mimic animation and the color change for the following floating action button.
The way the floating action button works is white is off and blue is on.
However, I have been unsuccessful with the animation and changing the color.
These have been my attempts at doing this, as you can see I have commented out all the different ways I have tried to do this.
This is my code:
#SuppressWarnings("unused")
#OnClick(R.id.fabMovieFavourite)
public void addMovieFavourite(View view) {
/* final Animator animator = AnimatorInflater.loadAnimator(getActivity(), R.animator.add_favourite_movie);
animator.setTarget(view);)
animator.start();
*/
/*
AnimatorSet animatorSet = new AnimatorSet();
PropertyValuesHolder propertyValuesHolderX = PropertyValuesHolder.ofFloat(View.SCALE_X, 1.1f);
PropertyValuesHolder propertyValuesHolderY = PropertyValuesHolder.ofFloat(View.SCALE_Y, 1.1f);
ObjectAnimator objectAnimator = ObjectAnimator.ofPropertyValuesHolder(view, propertyValuesHolderX, propertyValuesHolderY);
objectAnimator.setDuration(300);
objectAnimator.setInterpolator(new OvershootInterpolator(10f));
*/
/*
objectAnimator.setRepeatCount(1);
objectAnimator.setRepeatMode(ObjectAnimator.REVERSE);
*/
/*
PropertyValuesHolder propertyValuesHolderX2 = PropertyValuesHolder.ofFloat(View.SCALE_X, 0.9f);
PropertyValuesHolder propertyValuesHolderY2 = PropertyValuesHolder.ofFloat(View.SCALE_Y, 0.9f);
ObjectAnimator objectAnimator2 = ObjectAnimator.ofPropertyValuesHolder(view, propertyValuesHolderX2, propertyValuesHolderY2);
objectAnimator.setDuration(300);
objectAnimator2.setInterpolator(new OvershootInterpolator(10f));
animatorSet.playSequentially(objectAnimator, objectAnimator2);
objectAnimator.start();
*/
// view.BackgroundTintList(ContextCompat.getColorStateList(getContext(), R.color.primary));
//view.setBackgroundColor(ContextCompat.getColor(getActivity(), R.color.primary));
if(Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
Timber.d("start translationZ");
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(view, View.TRANSLATION_Z, 12f);
objectAnimator.setDuration(300);
objectAnimator.setInterpolator(new OvershootInterpolator(10f));
objectAnimator.setTarget(view);
objectAnimator.start();
}
}
Many thanks for any suggestions.
There're two phases in this animation. First one scales X and Y axis, and second one downscales it. So, we can divide them into two AnimatorSets and play them sequentially.
The key point of the animation is to find appropriate interpolator for the second AnimatorSet, because it's not standard one.
See, we want fab to overshoot, then undershoot and then finally settle up to the specified value in the animator.
Luckily, there's very handy PathInterpolator, which will create an interpolator for us with provided Path.
Path path = new Path();
path.moveTo(0.0f, 0.0f);
path.lineTo(0.5f, 1.3f);
path.lineTo(0.75f, 0.8f);
path.lineTo(1.0f, 1.0f);
PathInterpolator pathInterpolator = new PathInterpolator(path);
So, let's create the first animation:
final float from = 1.0f;
final float to = 1.3f;
ObjectAnimator scaleX = ObjectAnimator.ofFloat(fab, View.SCALE_X, from, to);
ObjectAnimator scaleY = ObjectAnimator.ofFloat(fab, View.SCALE_Y, from, to);
ObjectAnimator translationZ = ObjectAnimator.ofFloat(fab, View.TRANSLATION_Z, from, to);
AnimatorSet set1 = new AnimatorSet();
set1.playTogether(scaleX, scaleY, translationZ);
set1.setDuration(100);
set1.setInterpolator(new AccelerateInterpolator());
set1.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
fab.setImageResource(isActive ? R.drawable.heart_active : R.drawable.heart_passive);
fab.setBackgroundTintList(ColorStateList.valueOf(isActive ? colorActive : colorPassive));
isActive = !isActive;
}
});
We are scaling both x, y. Also, we are changing z translation to have appropriate shadow effect. When animation ends, we want to change fab state (color of heart and fab background).
Now let's create the animation to settle back:
ObjectAnimator scaleXBack = ObjectAnimator.ofFloat(fab, View.SCALE_X, to, from);
ObjectAnimator scaleYBack = ObjectAnimator.ofFloat(fab, View.SCALE_Y, to, from);
ObjectAnimator translationZBack = ObjectAnimator.ofFloat(fab, View.TRANSLATION_Z, to, from);
AnimatorSet set2 = new AnimatorSet();
set2.playTogether(scaleXBack, scaleYBack, translationZBack);
set2.setDuration(300);
set2.setInterpolator(pathInterpolator);
See here, we used pathInterpolator that we created earlier.
We want to play those two AnimatorSets sequentially:
final AnimatorSet set = new AnimatorSet();
set.playSequentially(set1, set2);
set.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
fab.setClickable(true);
}
#Override
public void onAnimationStart(Animator animation) {
fab.setClickable(false);
}
});
Also, we want to disable clicks on fab whilst animating it. So we are turning it on/off depending on animation state.
Finally, we launch the animation when a click happens:
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
set.start();
}
});
Result:
Source code at github
I have this code and I want to rotate and scale an ImageView at the same time:
public class LayoutPunteggio extends RelativeLayout {
TextView ok;
LayoutInflater inflater;
RotateAnimation rotateAnimation1;
public LayoutPunteggio(Context context) {
super(context);
inflater = LayoutInflater.from(context);
init();
}
public void init() {
mano = new ImageView(getContext());
mano.setImageResource(R.drawable.mano);
mano.setX(100);
mano.setY(100);
addView(mano);
startScale(mano);
rotate();
}
public void rotate() {
rotateAnimation1.setInterpolator(new LinearInterpolator());
rotateAnimation1.setDuration(1000);
rotateAnimation1.setRepeatCount(-1);
mano.startAnimation(rotateAnimation1);
}
public void startScale(View view){
ScaleAnimation animation;
animation=new ScaleAnimation(1,2,1,2,1000, 1000);
animation.setDuration(1000);
view.startAnimation(animation);
}
}
I tried to apply the method rotate() then startScale(), but this doesn't work for both.
Does anyone have a solution?
You can use a library called NineOldAndroids.
There you have playTogether function of the AnimatorSet.
AnimatorSet animation = new AnimatorSet();
animation.playTogether(
ObjectAnimator.ofFloat(yourImageView, "rotation", 0, 360),
ObjectAnimator.ofFloat(yourImageView, "scaleX", 1, 2f),
ObjectAnimator.ofFloat(yourImageView, "scaleY", 1, 2f)
);
animation.setDuratio(1000);
animation.start();
You can also add a listener
animation.addListener(new AnimationListener(){
onAnimationStart....
onAnimationRepeat...
onAnimationEnd...
onAnimationCancel...
});
You can use this library: https://github.com/Yalantis/uCrop
Just pick the image or code the image path(if you don't want the user to change the image).
I guess you should use AnimationSet:
AnimationSet as = new AnimationSet(true);
// config rotation animation
RotateAnimation ra = new RotateAnimation(...);
ra.setDuration(1000);
...
// config scale animation
ScaleAnimation sa = new ScaleAnimation(...);
sa.setDuration(1000);
...
// Add animations
as.addAnimation(ra);
as.addAnimation(sa);
as.start();
Starting from Honeycomb animations are lot easier to implement, source: ViewPropertyAnimator
For instance changing coordinates of view:
ObjectAnimator animX = ObjectAnimator.ofFloat(myView, "x", 50f);
ObjectAnimator animY = ObjectAnimator.ofFloat(myView, "y", 100f);
AnimatorSet animSetXY = new AnimatorSet();
animSetXY.playTogether(animX, animY);
animSetXY.start();
Here's my code so far. So when I click the image, it moves as expected. Cool. But when I click the image again, it does not move back to the original location. Can someone help? FYI, variable "depends" is at a global scope. Thanks!
depends = false;
image.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (depends){
TranslateAnimation noob =
new TranslateAnimation(0, 0, 0, +90);
noob.setDuration(1000);
noob.setFillAfter(true);
image.startAnimation(noob);
} else{
TranslateAnimation translateAnimation =
new TranslateAnimation(0, 0, 0, -90);
depends = true;
translateAnimation.setDuration(1000);
translateAnimation.setFillAfter(true);
image.startAnimation(translateAnimation);
}
}
});
This is because the old Animation API will only translate the Drawable of the View, but not the View itself (and its touch area). If you click where the original image "was" you should see it move back
Solution: use the new Animator API here and nineoldandrois for back compatibility
Just a shot in the dark. If this doesn't help I'll delete my answer.
if (depends){
TranslateAnimation noob = new TranslateAnimation(0, 0, 0, +90);
noob.setDuration(1000);
noob.setFillAfter(true);
image.startAnimation(noob);
depends = false; <-- ADD THIS
} else{
TranslateAnimation translateAnimation = new TranslateAnimation(0, 0, 0, -90);
depends = true;
translateAnimation.setDuration(1000);
translateAnimation.setFillAfter(true);
image.startAnimation(translateAnimation);
}