本文最后更新于 794 天前,其中的信息可能已经有所发展或是发生改变。
1. OverridePendingTransition
Activity过场动画,支持有限
2. ActivityOptions
可实现①效果
Flutter的hero动画 (ShareElement)
ActivityOptionsCompat.makeCustomAnimation()
ActivityOptionsCompat.makeClipRevealAnimation()
ActivityOptionsCompat.makeScaleUpAnimation()
// 下面的相关实现可以用在这里-Activity过渡恭喜某些元素或者单独View变换使用(TransitionManager)
ActivityOptionsCompat.makeSceneTransitionAnimation()
ActivityOptionsCompat.makeSceneTransitionAnimation()
ActivityOptionsCompat.makeThumbnailScaleUpAnimation()
扩展继承Transition 示例
2.1 页面跳转
- 打开开关 默认开启
> requestWindowFeature(Window.FEATURE_CONTENT_TRANSITIONS); - 除了共享元素外转场
>Window.setEnterTransition()
Window.setExitTransition()
Window.setSharedElementEnterTransition()
Window.setSharedElementExitTransition() - 共享元素转场
> 和Flutter Hero动画一样 需要相同的transitionName
ActivityA
private void gotoDetailActivity(Contacts contacts, final View avatarImg, final View nameTxt) {
Intent intent = new Intent(ContactActivity.this,DetailActivity.class);
Pair<View,String> pair1 = new Pair<>((View)avatarImg,ViewCompat.getTransitionName(avatarImg));
Pair<View,String> pair2 = new Pair<>((View)nameTxt,ViewCompat.getTransitionName(nameTxt));
/**
*4、生成带有共享元素的Bundle,这样系统才会知道这几个元素需要做动画
*/
ActivityOptionsCompat activityOptionsCompat = ActivityOptionsCompat.makeSceneTransitionAnimation(ContactActivity.this, pair1, pair2);
ActivityCompat.startActivity(ContactActivity.this,intent,activityOptionsCompat.toBundle());
}
ActivityB
/**
* 3、设置ShareElementTransition,指定的ShareElement会执行这个Transiton动画
*/
// 更多的transition转场动画 参考下面 自定义Transition
TransitionSet transitionSet = new TransitionSet();
transitionSet.addTransition(new ChangeBounds());
transitionSet.addTransition(new ChangeTransform());
transitionSet.addTarget(avatarImg);
transitionSet.addTarget(nameTxt);
getWindow().setSharedElementEnterTransition(transitionSet);
getWindow().setSharedElementExitTransition(transitionSet);
2.2 默认实现
- 默认实现:Fade,Slide,Explode
- ChangeBounds 当 View 的位置或者大小发生变化时触发对应的转场效果
ChangeBounds transition = new ChangeBounds();
transition.setInterpolator(new AnticipateInterpolator());
TransitionManager.beginDelayedTransition(mRoot, transition);
ConstraintLayout.LayoutParams layoutParams = (ConstraintLayout.LayoutParams) view3.getLayoutParams();
if (layoutParams.leftMargin == 400) {
layoutParams.leftMargin = 50;
} else {
layoutParams.leftMargin = 400;
}
view3.setLayoutParams(layoutParams);
- ChangeClipBounds 当调用 view.setClipBounds() 时
ChangeClipBounds transition = new ChangeClipBounds();
transition.setInterpolator(new BounceInterpolator());
TransitionManager.beginDelayedTransition(mRoot, transition);
int width = view2.getWidth();
int height = view2.getHeight();
int gap = 140;
Rect rect = new Rect(0, gap, width, height - gap);
if (rect.equals(view2.getClipBounds())) {
view2.setClipBounds(null);
} else {
view2.setClipBounds(rect);
}
- ChangeScroll 当调用 view.scrollTo()
ChangeScroll transition = new ChangeScroll();
transition.setInterpolator(new AnticipateOvershootInterpolator());
TransitionManager.beginDelayedTransition(mRoot, transition);
if (view1.getScrollX() == -100 && view1.getScrollY() == -100) {
view1.scrollTo(0, 0);
} else {
view1.scrollTo(-100, -100);
}
- ChangeTransform View 的 translation、scale 和 rotation 发生改变时
ChangeTransform transition = new ChangeTransform();
transition.setInterpolator(new OvershootInterpolator());
TransitionManager.beginDelayedTransition(mRoot, transition);
if (view1.getTranslationX() == 100 && view1.getTranslationY() == 100) {
view1.setTranslationX(0);
view1.setTranslationY(0);
} else {
view1.setTranslationX(100);
view1.setTranslationY(100);
}
if (view2.getRotationX() == 30f) {
view2.setRotationX(0);
} else {
view2.setRotationX(30);
}
if (view3.getRotationY() == 30f) {
view3.setRotationY(0);
} else {
view3.setRotationY(30);
}
if (view4.getScaleX() == 0.5f && view4.getScaleY() == 0.5f) {
view4.setScaleX(1f);
view4.setScaleY(1f);
} else {
view4.setScaleX(0.5f);
view4.setScaleY(0.5f);
}
2.3 自定义Transition
- 继承Transition,并实现下述三个方法
- captureStartValues,captureEndValues存入动画值
- createAnimator内取出值进行相关动画
private static String PROPNAME_TEXT = "xiaweizi:changeText:text";
private static String PROPNAME_TEXT_COLOR = "xiaweizi:changeTextColor:color";
private static String PROPNAME_TEXT_SIZE = "xiaweizi:changeTextSize:size";
private static String PROPNAME_TEXT_LEVEL = "xiaweizi:changeTextTypeface:level";
// 记录下起始状态属性值
private void captureValues(TransitionValues transitionValues) {
if (transitionValues == null || !(transitionValues.view instanceof TextView)) return;
TextView view = (TextView) transitionValues.view;
transitionValues.values.put(PROPNAME_TEXT, view.getText());
transitionValues.values.put(PROPNAME_TEXT_COLOR, view.getCurrentTextColor());
transitionValues.values.put(PROPNAME_TEXT_SIZE, view.getTextSize());
transitionValues.values.put(PROPNAME_TEXT_LEVEL, view.getTag(R.id.type_face_level));
}
@Override
public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues, final TransitionValues endValues) {
if (startValues == null || endValues == null) {
return null;
}
if (!(endValues.view instanceof TextView)) {
return super.createAnimator(sceneRoot, startValues, endValues);
}
TextView endView = (TextView) endValues.view;
int startTextColor = (int) startValues.values.get(PROPNAME_TEXT_COLOR);
int endTextColor = (int) endValues.values.get(PROPNAME_TEXT_COLOR);
ObjectAnimator animator = ObjectAnimator.ofArgb(endView, new TextColorProperty(), startTextColor, endTextColor);
animator.setDuration(300);
return animator;
}
2.4 Scene
页面切换 ActivityOptionsCompat.makeSceneTransitionAnimation()
页面内 View变换
– 创建前后变换的layout 注意对应前后变换View需要相同的id
3. MotionLayout
public class TransitionView extends View {
private float mRatio = 1f;
private Paint mTextPaint;
private int mStartColor;
private int mEndColor;
private Rect mRect;
public TransitionView(Context context) {
this(context, null);
}
public TransitionView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public TransitionView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initView(context, attrs, defStyle);
}
private void initView(Context context, AttributeSet attrs, int defStyle) {
mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mTextPaint.setTextSize(getResources().getDimensionPixelSize(R.dimen.text_size));
mTextPaint.setColor(Color.WHITE);
mTextPaint.setTypeface(Typeface.DEFAULT_BOLD);
mTextPaint.setTextAlign(Paint.Align.CENTER);
mStartColor = Color.WHITE;
mEndColor = TransitionUtils.getColor(0);
mRect = new Rect();
}
public void setRatio(float ratio) {
this.mRatio = ratio;
invalidate();
}
public float getRatio() {
return mRatio;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 绘制左边
canvas.save();
mRect.set(0, 0, (int) (getWidth() * mRatio), getHeight());
canvas.clipRect(mRect);
mTextPaint.setColor(mStartColor);
TransitionUtils.drawTextCenter(canvas, "文本三", getWidth() / 2, getHeight() / 2, mTextPaint);
canvas.restore();
// 绘制右边
canvas.save();
mRect.set((int) (getWidth() * mRatio), 0, getWidth(), getHeight());
canvas.clipRect(mRect);
mTextPaint.setColor(mEndColor);
TransitionUtils.drawTextCenter(canvas, "三本文", getWidth() / 2, getHeight() / 2, mTextPaint);
canvas.restore();
}
}