假设我有一个垂直线性布局:
[v1]
[v2]
默认情况下,v1已经可见= GONE。我想用一个展开动画显示v1,同时下推v2。
我是这样做的:
Animation a = new Animation()
{
int initialHeight;
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
final int newHeight = (int)(initialHeight * interpolatedTime);
v.getLayoutParams().height = newHeight;
v.requestLayout();
}
@Override
public void initialize(int width, int height, int parentWidth, int parentHeight) {
super.initialize(width, height, parentWidth, parentHeight);
initialHeight = height;
}
@Override
public boolean willChangeBounds() {
return true;
}
};
但是用这个解决方案,当动画开始时我有一个眨眼。我认为这是由于v1在应用动画之前显示全尺寸。
用javascript,这是一行jQuery!android有什么简单的方法吗?
我看到这个问题很受欢迎,所以我发布了我的实际解决方案。主要的优点是你不需要知道扩展的高度来应用动画,一旦视图被扩展,它会在内容改变时适应高度。这对我来说很有效。
public static void expand(final View v) {
int matchParentMeasureSpec = View.MeasureSpec.makeMeasureSpec(((View) v.getParent()).getWidth(), View.MeasureSpec.EXACTLY);
int wrapContentMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
v.measure(matchParentMeasureSpec, wrapContentMeasureSpec);
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;
}
};
// Expansion speed of 1dp/ms
a.setDuration((int)(targetHeight / v.getContext().getResources().getDisplayMetrics().density));
v.startAnimation(a);
}
public static void collapse(final View v) {
final int initialHeight = v.getMeasuredHeight();
Animation a = new Animation()
{
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
if(interpolatedTime == 1){
v.setVisibility(View.GONE);
}else{
v.getLayoutParams().height = initialHeight - (int)(initialHeight * interpolatedTime);
v.requestLayout();
}
}
@Override
public boolean willChangeBounds() {
return true;
}
};
// Collapse speed of 1dp/ms
a.setDuration((int)(initialHeight / v.getContext().getResources().getDisplayMetrics().density));
v.startAnimation(a);
}
正如@Jefferson在评论中提到的,你可以通过改变动画的持续时间(以及速度)来获得更流畅的动画。目前,它已设置为1dp/ms的速度
我创建的版本中,你不需要指定布局高度,因此它更容易和更干净的使用。解决方案是在动画的第一帧中获取高度(至少在我的测试中是可用的)。通过这种方式,您可以为视图提供任意高度和底边距。
在构造函数中还有一个小hack -底部边距被设置为-10000,以便视图在转换之前保持隐藏(防止闪烁)。
public class ExpandAnimation extends Animation {
private View mAnimatedView;
private ViewGroup.MarginLayoutParams mViewLayoutParams;
private int mMarginStart, mMarginEnd;
public ExpandAnimation(View view) {
mAnimatedView = view;
mViewLayoutParams = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
mMarginEnd = mViewLayoutParams.bottomMargin;
mMarginStart = -10000; //hide before viewing by settings very high negative bottom margin (hack, but works nicely)
mViewLayoutParams.bottomMargin = mMarginStart;
mAnimatedView.setLayoutParams(mViewLayoutParams);
}
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
super.applyTransformation(interpolatedTime, t);
//view height is already known when the animation starts
if(interpolatedTime==0){
mMarginStart = -mAnimatedView.getHeight();
}
mViewLayoutParams.bottomMargin = (int)((mMarginEnd-mMarginStart) * interpolatedTime)+mMarginStart;
mAnimatedView.setLayoutParams(mViewLayoutParams);
}
}
我采用了@LenaYan的解决方案,但它并没有正常工作
对我来说(因为它在折叠和/或扩展之前将视图转换为0高度视图)并做了一些更改。
现在它工作得很好,通过获取视图之前的高度并开始扩展这个大小。坍缩也是一样的。
你可以简单地复制和粘贴下面的代码:
public static void expand(final View v, int duration, int targetHeight) {
int prevHeight = v.getHeight();
v.setVisibility(View.VISIBLE);
ValueAnimator valueAnimator = ValueAnimator.ofInt(prevHeight, targetHeight);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
v.getLayoutParams().height = (int) animation.getAnimatedValue();
v.requestLayout();
}
});
valueAnimator.setInterpolator(new DecelerateInterpolator());
valueAnimator.setDuration(duration);
valueAnimator.start();
}
public static void collapse(final View v, int duration, int targetHeight) {
int prevHeight = v.getHeight();
ValueAnimator valueAnimator = ValueAnimator.ofInt(prevHeight, targetHeight);
valueAnimator.setInterpolator(new DecelerateInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
v.getLayoutParams().height = (int) animation.getAnimatedValue();
v.requestLayout();
}
});
valueAnimator.setInterpolator(new DecelerateInterpolator());
valueAnimator.setDuration(duration);
valueAnimator.start();
}
用法:
//Expanding the View
expand(yourView, 2000, 200);
// Collapsing the View
collapse(yourView, 2000, 100);
很容易!
感谢LenaYan提供的初始代码!