我正在CircularReveal创建动画,使方形专辑艺术成为圆形.以下是一个简短的片段.
int cx = mImageView.getMeasuredWidth() / 2;
int cy = mImageView.getMeasuredHeight() / 2;
// get the initial radius for the clipping circle
int initialRadius = mImageView.getWidth() / 2;
// create the animation (the final radius is zero)
Animator anim = ViewAnimationUtils.createCircularReveal(mImageView, cx, cy, mImageView.getWidth(), initialRadius);
anim.setDuration(500);
anim.start();
Run Code Online (Sandbox Code Playgroud)
问题是,在动画之后,图像不会保持圆形.我正在寻找类似Animation.fillAfter(boolean fillAfter)电话的东西,但动画师没有这个选项.
以下是当前(故障)行为.
有什么建议可以在动画后将图像修复为圆圈吗?
Sae*_* Oh 14
我通过CircularRevealView使用GradientDrawable我的自定义完全将其替换为自定义蒙版来解决这个问题CardView.
我的xml(tmp_activity.xml)
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="@color/background_button"
tools:context=".TempActivity_">
<com.myapp.customviews.AnimatableCardView
android:id="@+id/base_view"
android:layout_marginLeft="@dimen/margin_medium"
android:layout_centerVertical="true"
android:layout_width="@dimen/album_art_small"
android:layout_height="@dimen/album_art_small"
app:cardElevation="0dp">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
android:src="@drawable/charlie"
android:id="@+id/imageView2"/>
</com.myapp.customviews.AnimatableCardView>
</RelativeLayout>
Run Code Online (Sandbox Code Playgroud)
我的活动(注意我使用Android Annotations,而不是findViewById(..))
@EActivity(R.layout.tmp_activity)
public class TempActivity extends BaseActivity {
@ViewById(R.id.base_view)
ViewGroup mParent;
@ViewById(R.id.imageView2)
ImageView mImageView;
GradientDrawable gradientDrawable;
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
private volatile boolean isCircle = false;
@Override
protected void onViewsCreated() {
super.onViewsCreated();
gradientDrawable = new GradientDrawable();
gradientDrawable.setCornerRadius(30.0f);
gradientDrawable.setShape(GradientDrawable.RECTANGLE);
mParent.setBackground(gradientDrawable);
mImageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View v) {
if (isCircle) {
makeSquare();
}
else {
makeCircle();
}
isCircle = !isCircle;
}
});
}
private void makeCircle() {
ObjectAnimator cornerAnimation =
ObjectAnimator.ofFloat(gradientDrawable, "cornerRadius", 30f, 200.0f);
Animator shiftAnimation = AnimatorInflater.loadAnimator(this, R.animator.slide_right_down);
shiftAnimation.setTarget(mParent);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.setDuration(500);
animatorSet.playTogether(cornerAnimation, shiftAnimation);
animatorSet.start();
}
private void makeSquare() {
ObjectAnimator cornerAnimation =
ObjectAnimator.ofFloat(gradientDrawable, "cornerRadius", 200.0f, 30f);
Animator shiftAnimation = AnimatorInflater.loadAnimator(this, R.animator.slide_left_up);
shiftAnimation.setTarget(mParent);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.setDuration(500);
animatorSet.playTogether(cornerAnimation, shiftAnimation);
animatorSet.start();
}
}
Run Code Online (Sandbox Code Playgroud)
我的自定义CardView(AnimatableCardView)
public class AnimatableCardView extends CardView {
private float xFraction = 0;
private float yFraction = 0;
private ViewTreeObserver.OnPreDrawListener preDrawListener = null;
public AnimatableCardView(Context context) {
super(context);
}
public AnimatableCardView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public AnimatableCardView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
// Note that fraction "0.0" is the starting point of the view. This includes margins.
// If this view was placed in (200,300), moveTo="0.1" for xFraction will give you (220,300)
public void setXFraction(float fraction) {
this.xFraction = fraction;
if (((ViewGroup) getParent()).getWidth() == 0) {
if (preDrawListener == null) {
preDrawListener = new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
getViewTreeObserver().removeOnPreDrawListener(preDrawListener);
setXFraction(xFraction);
return true;
}
};
getViewTreeObserver().addOnPreDrawListener(preDrawListener);
}
return;
}
float translationX = Math.max(0, (((ViewGroup) getParent()).getWidth()) * fraction - (getWidth() * getScaleX() / 2));
setTranslationX(translationX);
}
public float getXFraction() {
return this.xFraction;
}
public void setYFraction(float fraction) {
this.yFraction = fraction;
if (((ViewGroup) getParent()).getHeight() == 0) {
if (preDrawListener == null) {
preDrawListener = new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
getViewTreeObserver().removeOnPreDrawListener(preDrawListener);
setYFraction(yFraction);
return true;
}
};
getViewTreeObserver().addOnPreDrawListener(preDrawListener);
}
return;
}
float translationY = Math.max(0, (((ViewGroup) getParent()).getHeight()) * fraction - (getHeight() * getScaleY() / 2));
setTranslationY(translationY);
}
public float getYFraction() {
return this.yFraction;
}
}
Run Code Online (Sandbox Code Playgroud)
slide_right_down.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:ordering="together">
<objectAnimator
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:propertyName="xFraction"
android:duration="@android:integer/config_mediumAnimTime"
android:valueFrom="0.0"
android:valueTo="0.5"
android:valueType="floatType"/>
<objectAnimator
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:propertyName="yFraction"
android:duration="@android:integer/config_mediumAnimTime"
android:valueFrom="0.0"
android:valueTo="0.1"
android:valueType="floatType"/>
<objectAnimator
android:duration="@android:integer/config_mediumAnimTime"
android:propertyName="scaleX"
android:valueFrom="1.0"
android:valueTo="1.5"/>
<objectAnimator
android:duration="@android:integer/config_mediumAnimTime"
android:propertyName="scaleY"
android:valueFrom="1.0"
android:valueTo="1.5"/>
</set>
Run Code Online (Sandbox Code Playgroud)
slide_left_up.xml
<?xml version="1.0" encoding="utf-8"?>
<set android:ordering="together"
xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:propertyName="xFraction"
android:duration="@android:integer/config_mediumAnimTime"
android:valueFrom="0.5"
android:valueTo="0.0"
android:valueType="floatType"/>
<objectAnimator
android:propertyName="yFraction"
android:duration="@android:integer/config_mediumAnimTime"
android:valueFrom="0.1"
android:valueTo="0.0"
android:valueType="floatType"/>
<objectAnimator
android:duration="@android:integer/config_mediumAnimTime"
android:propertyName="scaleX"
android:valueFrom="1.5"
android:valueTo="1.0"/>
<objectAnimator
android:duration="@android:integer/config_mediumAnimTime"
android:propertyName="scaleY"
android:valueFrom="1.5"
android:valueTo="1.0"/>
</set>
Run Code Online (Sandbox Code Playgroud)
结果就是这样(设备的速度更快,更顺畅)
另一种方法是使用 MotionLayout 和 ImageFilterView。ConstraintLayout 2.0 版中引入的 ImageFilterView 允许对图像进行操作。它可以做一些令人惊奇的事情,例如交叉淡入淡出两个图像,但它也可以修改给定图像的半径。我的示例没有接受的答案发布的小反弹,但使用关键帧添加很容易。
这是我的解决方案:视频
这是实现它所需的文件
首先,您的活动/片段应如下所示(注意,如果您想将其合并到现有布局中,这也可以是子视图
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.motion.widget.MotionLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".MainActivity"
app:layoutDescription="@xml/motion_scene">
<androidx.constraintlayout.utils.widget.ImageFilterView
android:id="@+id/puthPic"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="centerCrop"
android:src="@drawable/puth"/>
</androidx.constraintlayout.motion.widget.MotionLayout>
Run Code Online (Sandbox Code Playgroud)
请注意,MotionLayout 有一个名为 app:layoutDescription 的字段,该字段指向@xml/motion_scene...这就是motion_scene.xml 布局的样子
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:motion="http://schemas.android.com/apk/res-auto">
<Transition
motion:constraintSetEnd="@+id/end"
motion:constraintSetStart="@+id/start"
motion:duration="500"
motion:motionInterpolator="easeInOut">
<OnClick
motion:clickAction="toggle"
motion:targetId="@+id/puthPic" />
</Transition>
<ConstraintSet android:id="@+id/start">
<Constraint android:id="@id/puthPic">
<Layout
android:layout_width="128dp"
android:layout_height="128dp"
android:layout_marginStart="16dp"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent" />
<CustomAttribute
motion:attributeName="roundPercent"
motion:customFloatValue="1" />
</Constraint>
</ConstraintSet>
<ConstraintSet android:id="@+id/end">
<Constraint android:id="@id/puthPic">
<Layout
android:layout_width="128dp"
android:layout_height="128dp"
android:layout_marginEnd="16dp"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintTop_toTopOf="parent" />
<CustomAttribute
motion:attributeName="roundPercent"
motion:customFloatValue="0.000001" />
</Constraint>
</ConstraintSet>
</MotionScene>
Run Code Online (Sandbox Code Playgroud)
只需要少量的代码,motionLayout 就会在位置和圆之间进行插值,为您生成正方形!
您会注意到我将motion:customFloatValue="0.000001"percentRound 设置为结束场景值。这是因为存在一个现有错误,如果将percentRound 设置为0.0,该错误会导致图像保持矩形。我已经提交了这个错误,如果您愿意,您可以在此处查看更多相关信息。
现在您就拥有了在方形和圆形视图之间轻松制作动画的另一种方式!
| 归档时间: |
|
| 查看次数: |
3121 次 |
| 最近记录: |