visão global
Uma animação que vejo muito é o slide para abrir. Normalmente, são os layouts reais de uma visualização que está sendo alterada. No entanto, se você apenas alterar a altura, ele abrirá rapidamente. Então, vou mostrar duas maneiras pelas quais você pode realmente fazer essa animação.
ValueAnimation
A primeira maneira de fazer isso é usando um ValueAnimation
(que pode ser usado em um AnimatorSet
). Esta animação vai embora e muda o valor de uma propriedade definida ao longo de uma parábola (ou qualquer equação de linha que você definiu especificamente no Interpolador). Em seguida, ele vai para cada ponto e permite criar uma equação com base na posição da animação nessa linha.
// view we want to animate
final View messageView = view.findViewById(R.id.message_section);
// set the values we want to animate between and how long it takes
// to run
ValueAnimator slideAnimator = ValueAnimator
.ofInt(currentHeight, newHeight)
.setDuration(300);
// we want to manually handle how each tick is handled so add a
// listener
slideAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
// get the value the interpolator is at
Integer value = (Integer) animation.getAnimatedValue();
// I'm going to set the layout's height 1:1 to the tick
messageView.getLayoutParams().height = value.intValue();
// force all layouts to see which ones are affected by
// this layouts height change
messageView.requestLayout();
}
});
// create a new animationset
AnimatorSet set = new AnimatorSet();
// since this is the only animation we are going to run we just use
// play
set.play(slideAnimator);
// this is how you set the parabola which controls acceleration
set.setInterpolator(new AccelerateDecelerateInterpolator());
// start the animation
set.start();
Animação personalizada
Uma segunda solução mais extrema, que nem sempre funciona da maneira que você deseja, é criar uma classe personalizada que estende Animation
. Isso é muito mais flexível e funciona quase exatamente da mesma forma que o anterior ValueAnimator
. Você pode fazer o construtor assumir a nova altura e a antiga. Isso também usa o interpolador para que você ainda possa definir uma equação personalizada. Aqui está um exemplo básico:
public class SlideAnimation extends Animation {
int mFromHeight;
int mToHeight;
View mView;
public SlideAnimation(View view, int fromHeight, int toHeight) {
this.mView = view;
this.mFromHeight = fromHeight;
this.mToHeight = toHeight;
}
@Override
protected void applyTransformation(float interpolatedTime, Transformation transformation) {
int newHeight;
if (mView.getHeight() != mToHeight) {
newHeight = (int) (mFromHeight + ((mToHeight - mFromHeight) * interpolatedTime));
mView.getLayoutParams().height = newHeight;
mView.requestLayout();
}
}
@Override
public void initialize(int width, int height, int parentWidth, int parentHeight) {
super.initialize(width, height, parentWidth, parentHeight);
}
@Override
public boolean willChangeBounds() {
return true;
}
}
O texto acima é quase exatamente o mesmo, mas você terá que usá-lo em algum lugar, de modo que se pareça com isto:
View messageView = view.findViewById(R.id.message_section);
Animation animation = new SlideAnimation(messageView, currentHeight, newHeight);
// this interpolator only speeds up as it keeps going
animation.setInterpolator(new AccelerateInterpolator());
animation.setDuration(300);
messageView.setAnimation(animation);
messageView.startAnimation(animation);
Conclusão
Ambos proporcionarão o mesmo tipo de resultado e podem ser aproveitados. Porém, tenha cuidado, isso nem sempre funciona em todos os lugares. Quando fiz essa classe de animação personalizada, ela não funcionou quando a usei em uma gaveta, mas ValueAnimator
funcionou. Aqui está um gif de como seria. (tenha em mente que o GIF faz com que pareça instável quando na verdade não é).
</p>