In my Android app I want to hide/show a Toolbar in an animation and adjust the FrameLayout below it so that it always fills up the whole screen. I do that by animating the top margin of the FrameLayout according to the display status of the Toolbar:
public void toggleToolbars(final boolean show) {
mToolbarHidden = !show;
final Toolbar tt = getBaseActivity().getToolbar();
final FrameLayout cv = getBaseActivity().getContentView();
int translation = show ? 0 : -tt.getHeight();
ValueAnimator animator = ValueAnimator.ofFloat(ViewHelper.getTranslationY(tt), translation).setDuration(200);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
float translationY = (float) animation.getAnimatedValue();
ViewHelper.setTranslationY(tt, translationY);
FrameLayout.LayoutParams clp = (FrameLayout.LayoutParams) cv.getLayoutParams();
clp.topMargin = tt.getHeight() + (int) translationY;
cv.setLayoutParams(clp);
}
});
animator.start();
}
This works fine, except for a flickering in the animation. I assume that using setLayoutParams is a costly method. requestLayout() is equally slow. How can I make this animation smoother? Can I reduce the frame rate somehow?
Note, that for certain reasons I cannot use setTranslationY and the built-in animations of CoordinatorLayout.
Related
I have a recyclerview in my app, and each row contains a button which shows a text in the same cell, under the button. I have used ChangeBounds transition to make the text appear with a smooth animation, increasing the row height until the text is completely shown. So when a button is clicked, I do:
TransitionManager.beginDelayedTransition(row, transition)
holder.hiddenText.setVisibility(View.VISIBLE)
It works well, but whith a problem. The hidden text appears with an animation which increases its height, as expected. But the row height is not animated, and it jumps from the original height until the final height without any animation.
Is there any way to achieve a height transition over the row, to increase at the same time as the text?
If you want animation to take effect for row also, then you need to perform beginDelayedTransition() on a one layer higher of the row, which in your case maybe is the actual RecyclerView.
Try this on your row's layout
public static void expand(final View v) {
v.measure(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
final int targetHeight = v.getMeasuredHeight();
// Older versions of android (pre API 21) cancel animations for views with a height of 0.
v.getLayoutParams().height = 1;
v.setVisibility(View.VISIBLE);
Animation a = new Animation()
{
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
v.getLayoutParams().height = interpolatedTime == 1
? LayoutParams.WRAP_CONTENT
: (int)(targetHeight * interpolatedTime);
v.requestLayout();
}
#Override
public boolean willChangeBounds() {
return true;
}
};
// 1dp/ms
a.setDuration((int)(targetHeight / v.getContext().getResources().getDisplayMetrics().density));
v.startAnimation(a);
}
Linear or Relative layout of row's will animate and expand. Hope this solves your problem
We need to have an animation to push the title bar view out of the screen and pull it into the screen. The title bar locates on top of the screen.
To do this specific animation will cost a lot for the screen that the animation is not smooth. I implement is in this way:
ValueAnimator animDown = ValueAnimator.ofFloat(1f, 0f);
animDown.setDuration(300);
params = (RelativeLayout.LayoutParams) titleView.getLayoutParams();
animDown.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
float currentValue = (float) animation.getAnimatedValue();
newHeight = -(int) (titleView.getHeight() * currentValue);
if (newHeight != lastHeight) {
params.setMargins(0, newHeight, 0, 0);
titleView.requestLayout();
}
lastHeight = newHeight;
}
});
this works fine in some places but not here, for I found that the callback method onAnimationUpdate is called very few times (say 6-8 times) during the animation, which means one frame update cost over 40ms, which looks too laggy.
My question is: is there a way to increase the frequency of the callback method onAnimationUpdate, or is there any other way to do this animation more smoothly?
Previously we are using other animations such as fade out and it works well, but push out animation here cost too much while the grid view list below the title view also is quite heavy.
I want to change the size of the itemView of RecyclerView in the 'animateMoveImpl()' method for my ItemAnimator, but it did not work.
I have tried the scale animation, it works fine, but not enough.
What I want to achieve is to change the 'width' property, so the image shown in the itemView will adapt to the change. The scale animation just make the image stretched.
Is it possible to animate the width change of itemView in ItemAnimator?
Thanks~
Update:
The code is like follows.
ValueAnimator anim = ValueAnimator.ofFloat(1f, 0.5f);
anim.setDuration(1000);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
float tmp = DEFAULT_WIDTH * (float)animation.getAnimatedValue();
animButton.setWidth((int)tmp);
animButton.requestLayout();
}
});
anim.start();
Note that it works for normal view. But it does not work int the 'animateMoveImpl()' for ItemAnimator.
Is there any way to animate a cropping of an ImageView?
Say for example, the ImageView is 720 x 480. I want to chop off the bottom rows of pixels with an animation until the ImageView is completely gone. I have only been able to move the image up when the onclicklistener is enabled, and make it transparent, which is ok, but not what the designer asked for.
ValueAnimator anim = ValueAnimator.ofInt(myImageView.getMeasuredHeight(), 0);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
int val = (Integer) valueAnimator.getAnimatedValue();
ViewGroup.LayoutParams layoutParams = myImageView.getLayoutParams();
layoutParams.height = val;
myImageView.setLayoutParams(layoutParams);
}
});
anim.setDuration(1000);
anim.start();
I got code from here and just changed it to height: ObjectAnimator animate LinearLayout width
Assuming you only want to chop off the height, using ObjectAnimator will work out to create such a custom cropped-height animation,
First of all you need to specify getHeight() and setHeight() methods and then create a custom animation with ObjectAnimator.
public float getHeight() { ... }
public void setHeight(float h) { ... }
ObjectAnimator heightAnim= ObjectAnimator.ofFloat(yourImageView, "height", heightBegin, heightEnd);
I have a LinearLayout that I use as a container for some buttons and textview's that I would like to animate the height of to give an impression of the layout sliding down when the user presses a "show" button.
I have set the LinearLayout to layout_height="0dp" and visibility="gone" in my xml. I then wish to set it to be visible and whatever height is need to wrap the content. At the moment I'm having issues even animating it at all, nevermind the wrap content height.
Here's my method for animating:
private void toggle(final LinearLayout v) {
v.setVisibility(View.VISIBLE);
ValueAnimator va = ValueAnimator.ofInt(0, 300);
va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
public void onAnimationUpdate(ValueAnimator animation) {
Integer value = (Integer) animation.getAnimatedValue();
v.getLayoutParams().height = value.intValue();
v.invalidate();
}
});
va.start();
}
Perhaps the problem is how I am setting the height of the LinearLayout? Or am I misunderstanding the function of the ValueAnimator? I've looked around at the blog post's by Chet Haase but they do not contain any specific height animation examples. Neither have I been able to find and good examples of how to work with animations of height using API's from 3.0+. Would love some help on this, thanks!
Looking at this blog post: http://tech.chitgoks.com/2011/10/29/android-animation-to-expand-collapse-view-its-children/ I found that I shouldn't use view.invalidate() to have the layout redrawn. I should use view.requestLayout().
Thus the code becomes something like this:
ValueAnimator va = ValueAnimator.ofInt(0, height);
va.setDuration(700);
va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
public void onAnimationUpdate(ValueAnimator animation) {
Integer value = (Integer) animation.getAnimatedValue();
v.getLayoutParams().height = value.intValue();
v.requestLayout();
}
});
I just wanted to add a note on how to get the height of the LinearLayout as well to make the animation dynamic. To get the height all the views need to be drawn first. Therfor we have to listen for an event that tells us that the drawing is done. This can be done from the onResume() method like this (note that in my xml I have declared the container to wrap_content for height and it is also visible, since I want to hide it from the start I do that efter measuring it):
#Override
public void onResume() {
super.onResume();
final ViewTreeObserver vto = filterContainer.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
height = filterContainer.getHeight();
filterContainer.setVisibility(View.GONE);
filterContainer.getLayoutParams().height = 0;
filterContainer.requestLayout();
ViewTreeObserver obs = filterContainer.getViewTreeObserver();
obs.removeGlobalOnLayoutListener(this);
}
});
}