So I have a wifi signal strength scale looking like this:
Whenever the signal gets better or worse I set the y-coordinate of the scale like this:
View dBmLine = scale.findViewById(Math.abs(dBm));
float dBmLineMiddle = dBmLine.getY() + dBmLine.getHeight() / 2;
float newY = arrowMiddle - dBmLineMiddle;
scale.setY(newY);
This looks very clumsy and I want to add a smooth animation for the scale's oldY to newY. Understanding very little about animations, I tried the following:
TranslateAnimation translateAnimation = new TranslateAnimation(Animation.ABSOLUTE, 0,
Animation.ABSOLUTE, 0,
Animation.ABSOLUTE, scale.getY(),
Animation.ABSOLUTE, newY);
scale.startAnimation(translateAnimation);
But the scale didn't move, it only flickers.
scale.animate().setDuration(50).translationY(newY);
50 is millis, 1000 = 1 second.
Also, if you want to add a listener on that animation you could use :
scale.animate().setDuration(50).translationY(300).setListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animator) {
}
#Override
public void onAnimationEnd(Animator animator) {
}
#Override
public void onAnimationCancel(Animator animator) {
}
#Override
public void onAnimationRepeat(Animator animator) {
}
});
Related
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
I am trying to implement something like:
motion trail animation
motion blur animation
ghost animation
(i do not know correct name of "effect") for repeatedly change view position.
Function, which is called repeatedly according accelerometer changes:
public void setXY(float x, float y) {
if(view != null) {
overloadPoint.setX(pointX);
overloadPoint.setY(pointY);
}
}
My goal:
For change X,Y animation show path (line, curve) between old and new view position.
OR alternative goal:
Between old and new view position, i would like to freeze old position and apply for example alpha effect to view in old position from 1.0f to 0.0f, duration:100ms. So when method is called for example every 50ms, i will see two views. Both views will have fade out effect (alpha 1.0f -> 0.0f), but older will have less alpha.
For: API >= 21
I tried:
public void setXY(float x, float y){
final View view = new View(this);
view.setLayoutParams(new LinearLayout.LayoutParams(
25, //TODO
25)); //TODO
view.setBackgroundResource(R.drawable.background_point);
relativeLayout.addView(view);
view.setX(x);
view.setY(y);
//Variant 1:
view.animate()
.alpha(0f)
.setDuration(750)
.setInterpolator(new DecelerateInterpolator())
.withLayer()
.setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
relativeLayout.removeView(view);
}
})
.start();
//Variant 2:
/*AlphaAnimation anim1 = new AlphaAnimation(1f, 0f);
anim1.setDuration(750);
//anim1.setFillAfter(true);
anim1.setAnimationListener(new Animation.AnimationListener() {
public void onAnimationStart(Animation anim) {};
public void onAnimationRepeat(Animation anim){};
public void onAnimationEnd(Animation anim) {
relativeLayout.removeView(view);
};
});
view.startAnimation(anim1);*/
//Variant 3:
/*view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
ObjectAnimator animator = ObjectAnimator.ofFloat(view, View.ALPHA, 0f);
// Add a listener that does cleanup
animator.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
relativeLayout.removeView(view);
view.setLayerType(View.LAYER_TYPE_NONE, null);
}
});
animator.start();*/
}
But i think, that these are not good solutions.. repeatedly create and remove Views. Better will be effect with one View.
Thank you.
I want to vibrate a view with scaleX and scaleY, and I am doing it with this code, but the problem is that sometimes the view is not correctly reset, and it shows with the scale applied...
I want that when the animation ends, the view must be seen with its original status always
this is the code:
ObjectAnimator scaleX = ObjectAnimator.ofFloat(view, "scaleX", 1f, 0.9f);
scaleX.setDuration(50);
scaleX.setRepeatCount(5);
scaleX.setRepeatMode(Animation.REVERSE);
ObjectAnimator scaleY = ObjectAnimator.ofFloat(view, "scaleY", 1f, 0.9f);
scaleY.setDuration(50);
scaleY.setRepeatCount(5);
scaleY.setRepeatMode(Animation.REVERSE);
set.play(scaleX).with(scaleY);
set.start();
Thanks
For ValueAnimator and ObjectAnimator can be like this a try:
animator.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
animation.removeListener(this);
animation.setDuration(0);
((ValueAnimator) animation).reverse();
}
});
UPDATE
On Android 7 it doesn't work.
Best way use the interpolator.
public class ReverseInterpolator implements Interpolator {
private final Interpolator delegate;
public ReverseInterpolator(Interpolator delegate){
this.delegate = delegate;
}
public ReverseInterpolator(){
this(new LinearInterpolator());
}
#Override
public float getInterpolation(float input) {
return 1 - delegate.getInterpolation(input);
}
}
In your code
animator.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
animation.removeListener(this);
animation.setDuration(0);
animation.setInterpolator(new ReverseInterpolator());
animation.start();
}
});
According to the docs(Property Animation):
The property animation system can animate Views on the screen by changing the actual properties in the View objects. In addition, Views also automatically call the invalidate() method to refresh the screen whenever its properties are changed.
so you can use AnimatorListener to listen the animation event, then just reset the view property you animate. let's say cancel event and scaleX property:
scaleAnimator.setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationCancel(Animator animation) {
scaleView.setScaleX(0)
}
});
Hope this can help a bit.
You can add an AnimatorListener, to be notified when the animation ends:
scaleY.addListener(new AnimatorListener() {
#Override
public void onAnimationEnd(Animator animation) {
// TODO Restore view
}
#Override
public void onAnimationStart(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
}
#Override
public void onAnimationCancel(Animator animation) {
}
});
I'm implementing a slot machine in Android. The reels are ScrollViews with LinearLayouts as children, and the individual tiles as ImageViews vertically oriented inside the LinearLayout. I'm using an ObjectAnimator to scroll to the end of the ScrollView, using ValueAnimator.RESTART and ValueAnimator.INFINITE. The reel scrolling is nice and smooth, however when it comes time to repeat, it pauses for a second, which ruins the effect. Here's the code I'm using:
public void spinReel(SlotReel reel) {
final int reelSize = this.context.getPixelsInDPs(64);
final SlotMachineView me = this;
final SlotReel myReel = reel;
ImageView[] tiles = reel.getTiles();
int delta = tiles.length - reel.currentTileNumber();
ObjectAnimator animator = ObjectAnimator.ofInt(reel, "scrollY", tiles.length * reelSize );
animator.setInterpolator(new LinearInterpolator());
animator.setDuration(delta * 75);
animator.setStartDelay(0);
animator.setRepeatMode(ValueAnimator.RESTART);
animator.setRepeatCount(ValueAnimator.INFINITE);
animator.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animator) {
}
#Override
public void onAnimationEnd(Animator animator) {
}
#Override
public void onAnimationCancel(Animator animator) {
}
#Override
public void onAnimationRepeat(Animator animator) {
myReel.scrollTo(0, reelSize * 3);
}
});
animator.start();
}
Note that the jerkiness occurs whether or not I put the scrollTo in the Repeat callback.
Example video here:
You should try:
setRepeatMode(ValueAnimator.INFINITE);
look here
Android ValueAnimator pauses during repeat
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);
}