假设我有一个垂直线性布局:
[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有什么简单的方法吗?
这是我的解决方案,我的ImageView从100%增长到200%,并返回到原来的大小,使用res/anim/文件夹中的两个动画文件
anim_grow.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_interpolator">
<scale
android:fromXScale="1.0"
android:toXScale="2.0"
android:fromYScale="1.0"
android:toYScale="2.0"
android:duration="3000"
android:pivotX="50%"
android:pivotY="50%"
android:startOffset="2000" />
</set>
anim_shrink.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_interpolator">
<scale
android:fromXScale="2.0"
android:toXScale="1.0"
android:fromYScale="2.0"
android:toYScale="1.0"
android:duration="3000"
android:pivotX="50%"
android:pivotY="50%"
android:startOffset="2000" />
</set>
发送一个ImageView到setAnimationGrowShrink()方法
ImageView img1 = (ImageView)findViewById(R.id.image1);
setAnimationGrowShrink(img1);
setAnimationGrowShrink()方法:
private void setAnimationGrowShrink(final ImageView imgV){
final Animation animationEnlarge = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.anim_grow);
final Animation animationShrink = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.anim_shrink);
imgV.startAnimation(animationEnlarge);
animationEnlarge.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {}
@Override
public void onAnimationRepeat(Animation animation) {}
@Override
public void onAnimationEnd(Animation animation) {
imgV.startAnimation(animationShrink);
}
});
animationShrink.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {}
@Override
public void onAnimationRepeat(Animation animation) {}
@Override
public void onAnimationEnd(Animation animation) {
imgV.startAnimation(animationEnlarge);
}
});
}
加上Tom Esterez的精彩回答和Erik B的精彩更新,我想我应该发布我自己的观点,将扩展和收缩方法压缩为一个。通过这种方式,你可以有这样一个动作……
button.setOnClickListener(v -> expandCollapse(view));
... 它调用下面的方法,并让它在每次onClick()之后弄清楚要做什么…
public static void expandCollapse(View view) {
boolean expand = view.getVisibility() == View.GONE;
Interpolator easeInOutQuart = PathInterpolatorCompat.create(0.77f, 0f, 0.175f, 1f);
view.measure(
View.MeasureSpec.makeMeasureSpec(((View) view.getParent()).getWidth(), View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
);
int height = view.getMeasuredHeight();
int duration = (int) (height/view.getContext().getResources().getDisplayMetrics().density);
Animation animation = new Animation() {
@Override protected void applyTransformation(float interpolatedTime, Transformation t) {
if (expand) {
view.getLayoutParams().height = 1;
view.setVisibility(View.VISIBLE);
if (interpolatedTime == 1) {
view.getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT;
} else {
view.getLayoutParams().height = (int) (height * interpolatedTime);
}
view.requestLayout();
} else {
if (interpolatedTime == 1) {
view.setVisibility(View.GONE);
} else {
view.getLayoutParams().height = height - (int) (height * interpolatedTime);
view.requestLayout();
}
}
}
@Override public boolean willChangeBounds() {
return true;
}
};
animation.setInterpolator(easeInOutQuart);
animation.setDuration(duration);
view.startAnimation(animation);
}
@Tom Esterez的回答,但更新为正确使用view.measure()每个Android getMeasuredHeight返回错误的值!
// http://easings.net/
Interpolator easeInOutQuart = PathInterpolatorCompat.create(0.77f, 0f, 0.175f, 1f);
public static Animation expand(final View view) {
int matchParentMeasureSpec = View.MeasureSpec.makeMeasureSpec(((View) view.getParent()).getWidth(), View.MeasureSpec.EXACTLY);
int wrapContentMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
view.measure(matchParentMeasureSpec, wrapContentMeasureSpec);
final int targetHeight = view.getMeasuredHeight();
// Older versions of android (pre API 21) cancel animations for views with a height of 0 so use 1 instead.
view.getLayoutParams().height = 1;
view.setVisibility(View.VISIBLE);
Animation animation = new Animation() {
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
view.getLayoutParams().height = interpolatedTime == 1
? ViewGroup.LayoutParams.WRAP_CONTENT
: (int) (targetHeight * interpolatedTime);
view.requestLayout();
}
@Override
public boolean willChangeBounds() {
return true;
}
};
animation.setInterpolator(easeInOutQuart);
animation.setDuration(computeDurationFromHeight(view));
view.startAnimation(animation);
return animation;
}
public static Animation collapse(final View view) {
final int initialHeight = view.getMeasuredHeight();
Animation a = new Animation() {
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
if (interpolatedTime == 1) {
view.setVisibility(View.GONE);
} else {
view.getLayoutParams().height = initialHeight - (int) (initialHeight * interpolatedTime);
view.requestLayout();
}
}
@Override
public boolean willChangeBounds() {
return true;
}
};
a.setInterpolator(easeInOutQuart);
int durationMillis = computeDurationFromHeight(view);
a.setDuration(durationMillis);
view.startAnimation(a);
return a;
}
private static int computeDurationFromHeight(View view) {
// 1dp/ms * multiplier
return (int) (view.getMeasuredHeight() / view.getContext().getResources().getDisplayMetrics().density);
}
我看到这个问题很受欢迎,所以我发布了我的实际解决方案。主要的优点是你不需要知道扩展的高度来应用动画,一旦视图被扩展,它会在内容改变时适应高度。这对我来说很有效。
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的速度
这是我的解决方案,我的ImageView从100%增长到200%,并返回到原来的大小,使用res/anim/文件夹中的两个动画文件
anim_grow.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_interpolator">
<scale
android:fromXScale="1.0"
android:toXScale="2.0"
android:fromYScale="1.0"
android:toYScale="2.0"
android:duration="3000"
android:pivotX="50%"
android:pivotY="50%"
android:startOffset="2000" />
</set>
anim_shrink.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_interpolator">
<scale
android:fromXScale="2.0"
android:toXScale="1.0"
android:fromYScale="2.0"
android:toYScale="1.0"
android:duration="3000"
android:pivotX="50%"
android:pivotY="50%"
android:startOffset="2000" />
</set>
发送一个ImageView到setAnimationGrowShrink()方法
ImageView img1 = (ImageView)findViewById(R.id.image1);
setAnimationGrowShrink(img1);
setAnimationGrowShrink()方法:
private void setAnimationGrowShrink(final ImageView imgV){
final Animation animationEnlarge = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.anim_grow);
final Animation animationShrink = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.anim_shrink);
imgV.startAnimation(animationEnlarge);
animationEnlarge.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {}
@Override
public void onAnimationRepeat(Animation animation) {}
@Override
public void onAnimationEnd(Animation animation) {
imgV.startAnimation(animationShrink);
}
});
animationShrink.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {}
@Override
public void onAnimationRepeat(Animation animation) {}
@Override
public void onAnimationEnd(Animation animation) {
imgV.startAnimation(animationEnlarge);
}
});
}