I'm creating an animation for rail items for Android TV. I combined several animations using Value Animator but animations are really slow and there are a lot of frames skipped. It turns out the even if I play just one animation using Value Animator it causes this type of behavior. And I need to use five animations together. Here's my code:
public void setFocus(boolean hasFocus) {
//If card has focus
if (hasFocus) {
animWidth = ValueAnimator.ofInt(rlMain.getMeasuredWidth(), (int)
Utils.convertDpToPixel(215));
animWidth.addUpdateListener(new
ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
int val = (Integer) valueAnimator.getAnimatedValue();
ViewGroup.LayoutParams layoutParams =
rlMain.getLayoutParams();
layoutParams.width = val;
rlMain.setLayoutParams(layoutParams);
}
});
animHeight = ValueAnimator.ofInt(rlMain.getMeasuredHeight(), (int)
Utils.convertDpToPixel(328));
animHeight.addUpdateListener(new
ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
int val = (Integer) valueAnimator.getAnimatedValue();
ViewGroup.LayoutParams layoutParams =
rlMain.getLayoutParams();
layoutParams.height = val;
rlMain.setLayoutParams(layoutParams);
}
});
animTopMargin = ValueAnimator.ofInt((int) Utils.convertDpToPixel(42),
(int) Utils.convertDpToPixel(12));
animTopMargin.addUpdateListener(new
ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams)
rlMain.getLayoutParams();
lp.setMargins(0, (Integer) animation.getAnimatedValue(),
(int) Utils.convertDpToPixel(12), 0);
rlMain.setLayoutParams(lp);
}
});
animTranslationX = ValueAnimator.ofFloat(rlContent.getX(),
rlContent.getX() + 15);
animTranslationX.addUpdateListener(new
ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
float xAnimatedValue = (float) animation.getAnimatedValue();
rlContent.setX(xAnimatedValue);
}
});
animTranslationY = ValueAnimator.ofFloat(rlContent.getY(),
rlContent.getY() - 17);
animTranslationY.addUpdateListener(new
ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
float yAnimatedValue = (float) animation.getAnimatedValue();
rlContent.setY(yAnimatedValue);
}
});
animatorSet = new AnimatorSet();
animatorSet.playTogether(animWidth, animHeight, animTopMargin,
animTranslationX, animTranslationY);
animatorSet.setDuration(1000);
animatorSet.start();
//Focus shadow visible
rlFocus.setVisibility(View.VISIBLE);
animWidth = null;
animHeight = null;
animTopMargin = null;
animTranslationX = null;
animTranslationY = null;
animatorSet = null;
} else {
animWidth = ValueAnimator.ofInt(rlMain.getMeasuredWidth(), (int)
Utils.convertDpToPixel(185));
animWidth.addUpdateListener(new
ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
int val = (Integer) valueAnimator.getAnimatedValue();
ViewGroup.LayoutParams layoutParams =
rlMain.getLayoutParams();
layoutParams.width = val;
rlMain.setLayoutParams(layoutParams);
}
});
animHeight = ValueAnimator.ofInt(rlMain.getMeasuredHeight(), (int)
Utils.convertDpToPixel(278));
animHeight.addUpdateListener(new
ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
int val = (Integer) valueAnimator.getAnimatedValue();
ViewGroup.LayoutParams layoutParams =
rlMain.getLayoutParams();
layoutParams.height = val;
rlMain.setLayoutParams(layoutParams);
}
});
animTopMargin = ValueAnimator.ofInt((int) Utils.convertDpToPixel(12),
(int) Utils.convertDpToPixel(42));
animTopMargin.addUpdateListener(new
ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams)
rlMain.getLayoutParams();
lp.setMargins(0, (Integer) animation.getAnimatedValue(),
(int) Utils.convertDpToPixel(12), 0);
rlMain.setLayoutParams(lp);
}
});
animTranslationX = ValueAnimator.ofFloat(rlContent.getX(),
rlContent.getX() - 15);
animTranslationX.addUpdateListener(new
ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
float xAnimatedValue = (float) animation.getAnimatedValue();
rlContent.setX(xAnimatedValue);
}
});
animTranslationY = ValueAnimator.ofFloat(rlContent.getY(),
rlContent.getY() + 17);
animTranslationY.addUpdateListener(new
ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
float yAnimatedValue = (float) animation.getAnimatedValue();
rlContent.setY(yAnimatedValue);
}
});
animatorSet = new AnimatorSet();
animatorSet.playTogether(animWidth, animHeight, animTopMargin,
animTranslationX, animTranslationY);
animatorSet.setDuration(1000);
animatorSet.start();
//Set focus shadow invisible with delay
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
rlFocus.setVisibility(View.INVISIBLE);
}
}, 1010);
animWidth = null;
animHeight = null;
animTopMargin = null;
animTranslationX = null;
animTranslationY = null;
animatorSet = null;
}
}
Is there any way to make those animations smooth? Any help would be highly appreciated :)
Related
I am trying to take a CardView (in a RecycleView) from actual width to 0. I am a newbie in android and in android animations. Could you say me what I am doing wrong?
This is my code:
final View v = cardViewHolder.cv;
int actualWidth = v.getMeasuredWidth();
ValueAnimator anim = ValueAnimator.ofInt(actualWidth, 0);
anim.setRepeatMode(ValueAnimator.REVERSE);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
int val = (Integer) valueAnimator.getAnimatedValue();
ViewGroup.LayoutParams layoutParams = v.getLayoutParams();
layoutParams.width = val;
v.setLayoutParams(layoutParams);
}
});
anim.setDuration(R.integer.card_flip_time_full);
anim.start();
With a breakpoint I see that val is always 728 (the width) and never changes. What is my fail?
I solved it:
final View v = cardViewHolder.cv;
int actualWidth = v.getMeasuredWidth();
ValueAnimator anim = ValueAnimator.ofInt(actualWidth, 0);
anim.setRepeatMode(ValueAnimator.REVERSE);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
// This needs to be declared as Integer instead of int
v.requestLayout(); // #mhenryk advice
Integer val = (Integer) valueAnimator.getAnimatedValue();
int value = val.intValue(); // Then get the int value
ViewGroup.LayoutParams layoutParams = v.getLayoutParams();
layoutParams.width = value;
v.setLayoutParams(layoutParams);
}
});
anim.setDuration(R.integer.card_flip_time_full);
anim.start();
I'm trying to make TextView Zoom in - Zoom out continuously in my app for that, I tried the following code but it works only once and I want it for infinite time. My code is---
private void setTvZoomInOutAnimation(final TextView textView)
{
// TODO Auto-generated method stub
final float startSize = 20;
final float endSize = 13;
final int animationDuration = 900; // Animation duration in ms
ValueAnimator animator = ValueAnimator.ofFloat(startSize, endSize);
animator.setDuration(animationDuration);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
{
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator)
{
float animatedValue = (Float) valueAnimator.getAnimatedValue();
textView.setTextSize(animatedValue);
}
});
animator.start();
}
Please help.
Try following code, you have missed the following line--
//animator.setRepeatCount(ValueAnimator.INFINITE); // Use this line for infinite animationsanimator.setRepeatCount(2); // Use this for fix amount of time
private void setTvZoomInOutAnimation(final TextView textView)
{
// TODO Auto-generated method stub
final float startSize = 20;
final float endSize = 13;
final int animationDuration = 900; // Animation duration in ms
ValueAnimator animator = ValueAnimator.ofFloat(startSize, endSize);
animator.setDuration(animationDuration);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
{
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator)
{
float animatedValue = (Float) valueAnimator.getAnimatedValue();
textView.setTextSize(animatedValue);
}
});
//animator.setRepeatCount(ValueAnimator.INFINITE); // Use this line for infinite animations
animator.setRepeatCount(2);
animator.start();
}
Hope it will help..
I tried to solve your problem. I hope, it may work for you. public class MainActivity extends Activity {
TextView scaleText;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
scaleText = (TextView) findViewById(R.id.txtView);
setTvZoomInOutAnimation(scaleText);
}
private void setTvZoomInOutAnimation(final TextView textView) {
final float startSize = 20;
final float endSize = 13;
final int animationDuration = 900;
ValueAnimator animator = ValueAnimator.ofFloat(startSize, endSize);
animator.setDuration(animationDuration);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
{
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator)
{
float animatedValue = (Float) valueAnimator.getAnimatedValue();
textView.setTextSize(animatedValue);
}
});
animator.start();
}
}
I need to expand and collapse CardView size in RecyclerView at run time.
I use RecyclerView to display a list and CardView as RecyclerView Item.
As I am new to this concept please help me.
I have expand on run time. like this,
Setting my view on onCreateView()
descriptionCardView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver
.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
detailProductDescription.getViewTreeObserver().removeOnPreDrawListener(this);
// save the full height
descriptionViewFullHeight = detailProductDescription.getHeight();
// initially changing the height to min height
ViewGroup.LayoutParams layoutParams = descriptionCardView.getLayoutParams();
layoutParams.height = (int) getActivity().getResources().getDimension(R.dimen
.product_description_min_height);
descriptionCardView.setLayoutParams(layoutParams);
return true;
}
});
and onClickingcardview
#OnClick(R.id.detail_product_description)
void onProductDescriptionClicked(View view) {
toggleProductDescriptionHeight();
}
i am setting CardView Height to expand and collapse.
private int descriptionViewFullHeight;
private void toggleProductDescriptionHeight() {
int descriptionViewMinHeight = (int) getActivity().getResources().getDimension(R.dimen
.product_description_min_height);
if (descriptionCardView.getHeight() == descriptionViewMinHeight) {
// expand
ValueAnimator anim = ValueAnimator.ofInt(descriptionCardView.getMeasuredHeightAndState(),
descriptionViewFullHeight);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
int val = (Integer) valueAnimator.getAnimatedValue();
ViewGroup.LayoutParams layoutParams = descriptionCardView.getLayoutParams();
layoutParams.height = val;
descriptionCardView.setLayoutParams(layoutParams);
}
});
anim.start();
} else {
// collapse
ValueAnimator anim = ValueAnimator.ofInt(descriptionCardView.getMeasuredHeightAndState(),
descriptionViewMinHeight);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
int val = (Integer) valueAnimator.getAnimatedValue();
ViewGroup.LayoutParams layoutParams = descriptionCardView.getLayoutParams();
layoutParams.height = val;
descriptionCardView.setLayoutParams(layoutParams);
}
});
anim.start();
}
}
I am trying to move a view on the screen to a random point by clicking it, then have it stay there and move again by click, however, the view only does the correct movement when starting at 0,0 coordinates, once changed, it is animating from random position to random position and finishing on a third random position.
here is my snippet, can some one please run this and see if it works properly? and if not, what am i missing?
public class MainActivity extends ActionBarActivity {
ImageView image;
Rect rect;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DisplayMetrics displaymetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
final int height = displaymetrics.heightPixels;
final int width = displaymetrics.widthPixels;
image = (ImageView) findViewById(R.id.image);
findViewById(R.id.image).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
final int newLeft = ((int)Math.round(Math.random()*width))/2;
final int newTop = ((int)Math.round(Math.random()*height))/2;;
final int newRight = ((int)Math.round(Math.random()*width))/2;;
final int newBottom = ((int)Math.round(Math.random()*height))/2;;
rect = new Rect(newLeft, newTop, newRight, newBottom);
doSomeAnimation(rect);
}
});
}
public void doSomeAnimation(final Rect rect) {
final FrameLayout.LayoutParams imageParasms = (FrameLayout.LayoutParams) image.getLayoutParams();
TranslateAnimation animation = new TranslateAnimation(
imageParasms.leftMargin, rect.left, imageParasms.topMargin, rect.top);
animation.setDuration(1000);
animation.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
FrameLayout.LayoutParams imageParasms = (FrameLayout.LayoutParams) image.getLayoutParams();
imageParasms.width = rect.width();
imageParasms.height = rect.height();
imageParasms.leftMargin = rect.left;
imageParasms.topMargin = rect.top;
image.setLayoutParams(imageParasms);
image.requestLayout();
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
image.startAnimation(animation);
}
It's better to use ValueAnimator, because TranslateAnimation uses matrix, and its very hard do deal with previous matrix values, I look source codes and understand that its better to use ValueAnimator, becauses have more control on how values are changing, I implemented it in different way, check this
public class MainActivity extends FragmentActivity {
ImageView image;
Random rnd = new Random();
int leftMargin;
int topMargin;
boolean xRunning;
boolean yRunning;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DisplayMetrics displaymetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
final int height = displaymetrics.heightPixels;
final int width = displaymetrics.widthPixels;
image = (ImageView) findViewById(R.id.image);
findViewById(R.id.image).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int newLeft = rnd.nextInt(height);
int newTop = rnd.nextInt(width);
Point pt = new Point(newLeft, newTop);
doSomeAnimation(pt);
}
});
//This Handler is used for optimization, for setting a layout in one place, instead of calling
//it in every onAnimationUpdate method
image.post(new Runnable() {
#Override
public void run() {
if(xRunning && yRunning) {
FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) image.getLayoutParams();
params.leftMargin = leftMargin;
params.topMargin = topMargin;
image.setLayoutParams(params);
}
image.postDelayed(this, 30);
}
});
}
public void doSomeAnimation(final Point pt) {
FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) image.getLayoutParams();
ValueAnimator xAnim = ValueAnimator.ofFloat(pxFromDp(this, params.leftMargin), pt.x);
xAnim.setDuration(1000);
xAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
leftMargin = (int) dpFromPx(MainActivity.this, (float) animation.getAnimatedValue());
}
});
xAnim.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
}
#Override
public void onAnimationEnd(Animator animation) {
xRunning = false;
}
#Override
public void onAnimationCancel(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
}
});
xAnim.start();
xRunning = true;
ValueAnimator yAnim = ValueAnimator.ofFloat(pxFromDp(this, params.topMargin), pt.y);
yAnim.setDuration(1000);
yAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
topMargin = (int) dpFromPx(MainActivity.this, (float) animation.getAnimatedValue());
}
});
yAnim.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
}
#Override
public void onAnimationEnd(Animator animation) {
yRunning = false;
}
#Override
public void onAnimationCancel(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
}
});
yAnim.start();
yRunning = true;
}
public static float dpFromPx(final Context context, final float px) {
return px / context.getResources().getDisplayMetrics().density;
}
public static float pxFromDp(final Context context, final float dp) {
return dp * context.getResources().getDisplayMetrics().density;
}
}
I have a view (customView) added to the WindowManager.
WindowManager mWm = (WindowManager)activity.getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
WindowManager.LayoutParams(WindowManager.LayoutParams.FILL_PARENT, 0, PixelFormat.TRANSPARENT);
mWl.dimAmount = 0.0f;
mWm.addView(customView, mWl);
Inside the custom view, I will call a translate animation when close button is pressed.
//// This is the handler for the animation ////
final Handler translateHandler = new Handler();
final Runnable mtranslateUp = new Runnable() {
public void run() {
Log.v("TEST","mtranslateUp Runnable");
startAnimation(translateUp);
}
};
//// This is the listener for the close button////
View.OnClickListener closeButtonListener = new View.OnClickListener() {
public void onClick(View v) {
translateHandler.post(mtranslateUp);
}
};
//// This is the translate up animation ////
translateUp = new TranslateAnimation(0,0,0,-200);
translateUp.setFillAfter(true);
translateUp.setDuration(1000);
translateUp.setAnimationListener(new AnimationListener(){
#Override
public void onAnimationEnd(Animation animation) {
Log.v("TEST","translateUp onAnimationEnd");
}
#Override
public void onAnimationRepeat(Animation animation) {
}
#Override
public void onAnimationStart(Animation animation) {
Log.v("TEST","translateUp onAnimationStart");
}}
);
If the customView is added to an activity, these code works fine!
When the customView is added to a WindowManager, the Log inside the onAnimationStart didn't show but the Log inside the Runnable can be shown.
Can anybody tells how to do animation on a view that is added to the WindowManager?
You should animate the view LayoutParameters. For example I use a method to update the view layout:
public void updateViewLayout(View view, Integer x, Integer y, Integer w, Integer h){
if (view!=null) {
WindowManager.LayoutParams lp = (WindowManager.LayoutParams) view.getLayoutParams();
if(x != null)lp.x=x;
if(y != null)lp.y=y;
if(w != null && w>0)lp.width=w;
if(h != null && h>0)lp.height=h;
mWindowService.updateViewLayout(view, lp);
}
}
Obviously mWindowService is context.getSystemService(Context.WINDOW_SERVICE).
I trigger this method in the animation:
public static void overlayAnimation(final View view2animate, int viewX, int endX) {
ValueAnimator translateLeft = ValueAnimator.ofInt(viewX, endX);
translateLeft.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
int val = (Integer) valueAnimator.getAnimatedValue();
updateViewLayout(view2animate, val, null, null, null);
}
});
translateLeft.setDuration(ANIMATION_DURATION);
translateLeft.start();
}
I was facing similar problem with a View attached to WindowManager.Try adding ViewGroup to WindoManager than View directly. It should work.
windowManager need a animation by android system. so the custom animation will not work
I had a problem.
When i use updateViewLayout in onAnimationUpdate, and i set the LayoutParams's width, the animation has dropped frames.
But i set the LayoutParams's x or y, the animation is ok.
like the below code:
mViewWidth = 800;
mViewHeight = 800;
final int oldX = mFloatWindowParams.x;
final int oldWidth = mFloatWindowParams.width;
final int oldHeight = mFloatWindowParams.height;
final int deltaWidth = mViewWidth - oldWidth;
final int deltaHeight = mViewHeight - oldHeight;
final boolean isWidthLarger = deltaWidth > deltaHeight;
int first = isWidthLarger ? oldWidth : oldHeight;
int end = isWidthLarger ? mViewWidth : mViewHeight;
ValueAnimator va = ValueAnimator.ofInt(first, end);
va.setDuration(1000);
va.setInterpolator(new LinearInterpolator());
va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
public void onAnimationUpdate(ValueAnimator animation) {
int value = (Integer) animation.getAnimatedValue();
float fraction = animation.getAnimatedFraction();
Log.i("onAnimationUpdate", value + "");
if (isWidthLarger) {
mFloatWindowParams.width = value;
mFloatWindowParams.height = oldHeight + (int) (deltaHeight * fraction);
} else {
mFloatWindowParams.width = oldWidth + (int) (deltaWidth * fraction);
mFloatWindowParams.height = value;
}
mFloatWindowParams.x = oldX - (int) (deltaWidth * fraction);
mWindowManager.updateViewLayout(mRootView, mFloatWindowParams);
}
});
va.start();