关键名词
- ExitTransitionCoordinator、EnterTransitionCoordinator
退出和进入动画协调者,主要负责动画执行的消息交互(使用handler通讯),同时包含一些其他功能的封装(如保存view信息),旧activity使用ExitTransitionCoordinator,新activity使用EnterTransitionCoordinator
- GhostView
每个view中都有一个mGhostView,如果不为空则跳过当前view的绘制,只绘制GhostView
- Transition
转场动画的最终效果实现,本质是对属性动画的封装,通过对比前后view的属性值进行变换
总流程
- 通过makeSceneTransitionAnimation生成ExitTransitionCoordinator,保存view信息,等待EnterTransitionCoordinator信息
- 启动新activity,在performStart中做准备工作,准备工作主要有两步
- 创建EnterTransitionCoordinator,将当前activity置为透明,发送MSG_SET_REMOTE_RECEIVER信息给ExitTransitionCoordinator
- 调用startEnter,在对应共享view中添加ghostView
- ExitTransitionCoordinator接收MSG_SET_REMOTE_RECEIVER,触发onSharedElementsArrived(activity A的ExitSharedElementCallback),发送MSG_TAKE_SHARED_ELEMENTS
- EnterTransitionCoordinator接收MSG_TAKE_SHARED_ELEMENTS,触发onSharedElementsArrived(activity B的EnterSharedElementCallback),然后通过transition执行动画
监听回调顺序
Activity A只触发ExitSharedElementCallback,activity B只触发EnterSharedElementCallback
exit activity A: onMapSharedElements
exit activity A: onPause
exit activity A: onCaptureSharedElementSnapshot
enter activity B: onStart
enter activity B: onResume
exit activity A: onSharedElementsArrived
enter activity B: onMapSharedElements
enter activity B: onSharedElementsArrived
enter activity B: onRejectSharedElements
enter activity B: onCreateSnapshotView
enter activity B: onSharedElementStart
enter activity B: onSharedElementEnd
exit activity A: onStop
源码
生成数据bundle
在我们使用共享元素动画时,需要先通过ActivityOptionsCompat.makeSceneTransitionAnimation(…)传入activity,sharedView,SharedName,生成共享元素的bundle数据
Bundle bundle=ActivityOptionsCompat.
makeSceneTransitionAnimation(MainActivity.this, navToNextWithAnim, "tran").toBundle();
makeSceneTransitionAnimation
- 判断是否支持转场动画
- 保存共享view信息
- 生成ExitTransitionCoordinator,并保存到当前activity的mActivityTransitionState中
static ExitTransitionCoordinator makeSceneTransitionAnimation(Activity activity, Window window, ActivityOptions opts, SharedElementCallback callback, Pair<View, String>[] sharedElements) {
if (!window.hasFeature(Window.FEATURE_ACTIVITY_TRANSITIONS)) {
opts.mAnimationType = ANIM_DEFAULT;
return null;
}
...
ArrayList<View> views = new ArrayList<View>();
if (sharedElements != null) {
for (int i = 0; i < sharedElements.length; i++) {
...
views.add(sharedElement.first);
}
}
ExitTransitionCoordinator exit = new ExitTransitionCoordinator(activity, window,
callback, names, names, views, false);
...
if (activity == null) {
opts.mExitCoordinatorIndex = -1;
} else {
opts.mExitCoordinatorIndex =
activity.mActivityTransitionState.addExitTransitionCoordinator(exit);
}
return exit;
}
ExitTransitionCoordinator是退出过渡的协调者,继承于ActivityTransitionCoordinator,而ActivityTransitionCoordinator又继承于ResultReceiver。其中ResultReceiver包含mHandler和mReceiver,主要用于消息的发送和接收;ActivityTransitionCoordinator是ExitTransitionCoordinator和EnterTransitionCoordinator的公共类,包含它们的共用方法。
ExitTransitionCoordinator
- 保存其他数据信息(如window,监听等)
- 触发退出监听的onMapSharedElements方法
- 生成回调消息监听,等候EnterTransitionCoordinator的消息
ActivityTransitionCoordinator的构造方法
public ActivityTransitionCoordinator(Window window, ArrayList<String> allSharedElementNames, SharedElementCallback listener, boolean isReturning) {
super(new Handler());
mWindow = window;
mListener = listener;
mAllSharedElementNames = allSharedElementNames;
mIsReturning = isReturning;
}
ExitTransitionCoordinator的构造方法
public ExitTransitionCoordinator(Activity activity, Window window, SharedElementCallback listener, ArrayList<String> names, ArrayList<String> accepted, ArrayList<View> mapped, boolean isReturning) {
super(window, names, listener, isReturning);
viewsReady(mapSharedElements(accepted, mapped));
stripOffscreenViews();
mIsBackgroundReady = !isReturning;
mActivity = activity;
}
viewsReady(触发onMapSharedElements)
protected void viewsReady(ArrayMap<String, View> sharedElements) {
sharedElements.retainAll(mAllSharedElementNames);
if (mListener != null) {
mListener.onMapSharedElements(mAllSharedElementNames, sharedElements);
}
setSharedElements(sharedElements);
if (getViewsTransition() != null && mTransitioningViews != null) {
ViewGroup decorView = getDecor();
if (decorView != null) {
decorView.captureTransitioningViews(mTransitioningViews);
}
mTransitioningViews.removeAll(mSharedElements);
}
setEpicenter();
}
消息监听
protected void onReceiveResult(int resultCode, Bundle resultData) {
switch (resultCode) {
case MSG_SET_REMOTE_RECEIVER:
...
break;
case MSG_HIDE_SHARED_ELEMENTS:
...
break;
case MSG_START_EXIT_TRANSITION:
...
break;
case MSG_SHARED_ELEMENT_DESTINATION:
...
break;
case MSG_CANCEL:
...
break;
}
}
新activity
之后执行activity的启动流程,并在新activity的performStart中调用mActivityTransitionState.enterReady(this),初始化数据,创建EnterTransitionCoordinator,并调用startEnter,触发进入的onMapSharedElements
final void performStart(String reason) {
....
mActivityTransitionState.enterReady(this);
...
}
public void enterReady(Activity activity) {
...
mEnterTransitionCoordinator = new EnterTransitionCoordinator(activity,
resultReceiver, sharedElementNames, mEnterActivityOptions.isReturning(),
mEnterActivityOptions.isCrossTask());
...
if (!mIsEnterPostponed) {
startEnter();
}
}
EnterTransitionCoordinator
- 将当前activity置为透明
- 发送MSG_SET_REMOTE_RECEIVER给ExitTransitionCoordinator
- 生成回调消息监听,等待其他操作
EnterTransitionCoordinator的构造方法
public EnterTransitionCoordinator(Activity activity, ResultReceiver resultReceiver, ArrayList<String> sharedElementNames, boolean isReturning, boolean isCrossTask) {
super(activity.getWindow(), sharedElementNames,
getListener(activity, isReturning && !isCrossTask), isReturning);
...
prepareEnter();
...
mResultReceiver.send(MSG_SET_REMOTE_RECEIVER, resultReceiverBundle);
...
}
prepareEnter主要是将当前activity置为透明
protected void prepareEnter() {
ViewGroup decorView = getDecor();
if (mActivity == null || decorView == null) {
return;
}
if (!isCrossTask()) {
mActivity.overridePendingTransition(0, 0);
}
if (!mIsReturning) {
mWasOpaque = mActivity.convertToTranslucent(null, null);
Drawable background = decorView.getBackground();
if (background == null) {
background = new ColorDrawable(Color.TRANSPARENT);
mReplacedBackground = background;
} else {
getWindow().setBackgroundDrawable(null);
background = background.mutate();
background.setAlpha(0);
}
getWindow().setBackgroundDrawable(background);
} else {
mActivity = null; // all done with it now.
}
}
回调监听
protected void onReceiveResult(int resultCode, Bundle resultData) {
switch (resultCode) {
case MSG_TAKE_SHARED_ELEMENTS:
...
break;
case MSG_EXIT_TRANSITION_COMPLETE:
...
break;
case MSG_CANCEL:
...
break;
case MSG_ALLOW_RETURN_TRANSITION:
...
break;
}
}
startEnter会触发EnterTransitionCoordinator的viewInstancesReady,viewInstancesReady再调用triggerViewsReady,triggerViewsReady最终触发EnterTransitionCoordinator的viewsReady
startEnter()
- 调用父类(ActivityTransitionCoordinator)的viewsReady,触发进入的onMapSharedElements
- 隐藏共享元素对应的views
- 调用moveSharedElementsToOverlay,将共享元素移动到顶层view
protected void viewsReady(ArrayMap<String, View> sharedElements) {
super.viewsReady(sharedElements);
mIsReadyForTransition = true;
hideViews(mSharedElements);
Transition viewsTransition = getViewsTransition();
if (viewsTransition != null && mTransitioningViews != null) {
removeExcludedViews(viewsTransition, mTransitioningViews);
stripOffscreenViews();
hideViews(mTransitioningViews);
}
if (mIsReturning) {
sendSharedElementDestination();
} else {
moveSharedElementsToOverlay();
}
if (mSharedElementsBundle != null) {
onTakeSharedElements();
}
}
moveSharedElementsToOverlay会将共享view取出来,然后依次添加GhostView
protected void moveSharedElementsToOverlay() {
...
if (decor != null) {
boolean moveWithParent = moveSharedElementWithParent();
Matrix tempMatrix = new Matrix();
for (int i = 0; i < numSharedElements; i++) {
View view = mSharedElements.get(i);
if (view.isAttachedToWindow()) {
tempMatrix.reset();
mSharedElementParentMatrices.get(i).invert(tempMatrix);
GhostView.addGhost(view, decor, tempMatrix);
...
}
}
}
}
GhostView本质也是一个view,相当于view的附属产物,如果view中存在mGhostView实例,则只会绘制GhostView,而跳过原view的绘制。 而GhostView具体的绘制内容则是调用绑定的view的绘制
//View Class
void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache, boolean fullInvalidate) {
if (mGhostView != null) {
mGhostView.invalidate(true);
return;
}
...
}
//GhostView Class
protected void onDraw(Canvas canvas) {
if (canvas instanceof RecordingCanvas) {
RecordingCanvas dlCanvas = (RecordingCanvas) canvas;
mView.mRecreateDisplayList = true;
RenderNode renderNode = mView.updateDisplayListIfDirty();
if (renderNode.hasDisplayList()) {
dlCanvas.insertReorderBarrier(); // enable shadow for this rendernode
dlCanvas.drawRenderNode(renderNode);
dlCanvas.insertInorderBarrier(); // re-disable reordering/shadows
}
}
}
addGhost中会以decorView的大小创建一个新的父布局(FrameLayout),并添加新建的GhostView
public static GhostView addGhost(View view, ViewGroup viewGroup, Matrix matrix) {
if (!(view.getParent() instanceof ViewGroup)) {
throw new IllegalArgumentException("Ghosted views must be parented by a ViewGroup");
}
ViewGroupOverlay overlay = viewGroup.getOverlay();
ViewOverlay.OverlayViewGroup overlayViewGroup = overlay.mOverlayViewGroup;
GhostView ghostView = view.mGhostView;
int previousRefCount = 0;
if (ghostView != null) {
...
}
if (ghostView == null) {
if (matrix == null) {
matrix = new Matrix();
calculateMatrix(view, viewGroup, matrix);
}
ghostView = new GhostView(view);
ghostView.setMatrix(matrix);
FrameLayout parent = new FrameLayout(view.getContext());
parent.setClipChildren(false);
copySize(viewGroup, parent);
copySize(viewGroup, ghostView);
parent.addView(ghostView);
ArrayList<View> tempViews = new ArrayList<View>();
int firstGhost = moveGhostViewsToTop(overlay.mOverlayViewGroup, tempViews);
insertIntoOverlay(overlay.mOverlayViewGroup, parent, ghostView, tempViews, firstGhost);
ghostView.mReferences = previousRefCount;
} else if (matrix != null) {
ghostView.setMatrix(matrix);
}
ghostView.mReferences++;
return ghostView;
}
ExitTransitionCoordinator接收MSG_SET_REMOTE_RECEIVER消息
会做取消的特殊判断,比如进入一个新界面,又立马退出的情况,正常流程会直接触发notifyComplete()
protected void onReceiveResult(int resultCode, Bundle resultData) {
switch (resultCode) {
case MSG_SET_REMOTE_RECEIVER:
stopCancel();
mResultReceiver = resultData.getParcelable(KEY_REMOTE_RECEIVER);
if (mIsCanceled) {
mResultReceiver.send(MSG_CANCEL, null);
mResultReceiver = null;
} else {
notifyComplete();
}
break;
...
}
}
notifyComplete()
- 触发退出的onSharedElementsArrived
- 发送MSG_TAKE_SHARED_ELEMENTS给EnterTransitionCoordinator
protected void notifyComplete() {
if (isReadyToNotify()) {
if (!mSharedElementNotified) {
....
if (mListener == null) {
mResultReceiver.send(MSG_TAKE_SHARED_ELEMENTS, mSharedElementBundle);
notifyExitComplete();
} else {
final ResultReceiver resultReceiver = mResultReceiver;
final Bundle sharedElementBundle = mSharedElementBundle;
mListener.onSharedElementsArrived(mSharedElementNames, mSharedElements,
new OnSharedElementsReadyListener() {
@Override
public void onSharedElementsReady() {
resultReceiver.send(MSG_TAKE_SHARED_ELEMENTS,
sharedElementBundle);
notifyExitComplete();
}
});
}
} else {
notifyExitComplete();
}
}
}
EnterTransitionCoordinator接收MSG_TAKE_SHARED_ELEMENTS消息
调用onTakeSharedElements
protected void onReceiveResult(int resultCode, Bundle resultData) {
switch (resultCode) {
case MSG_TAKE_SHARED_ELEMENTS:
if (!mIsCanceled) {
mSharedElementsBundle = resultData;
onTakeSharedElements();
}
break;
...
}
}
onTakeSharedElements
- 触发进入的onSharedElementsArrived
private void onTakeSharedElements() {
...
OnSharedElementsReadyListener listener = new OnSharedElementsReadyListener() {
@Override
public void onSharedElementsReady() {
final View decorView = getDecor();
if (decorView != null) {
OneShotPreDrawListener.add(decorView, false, () -> {
startTransition(() -> {
startSharedElementTransition(sharedElementState);
});
});
decorView.invalidate();
}
}
};
if (mListener == null) {
listener.onSharedElementsReady();
} else {
mListener.onSharedElementsArrived(mSharedElementNames, mSharedElements, listener);
}
}
触发之后调用onSharedElementsReady,最终执行startSharedElementTransition
public void onSharedElementsArrived(List<String> sharedElementNames, List<View> sharedElements, OnSharedElementsReadyListener listener) {
listener.onSharedElementsReady();
}
startSharedElementTransition
- 获取被拒绝的elements
- 触发进入的onRejectSharedElements
- 执行被拒绝的elements动画,通过属性动画实现,透明度由1变0
- 创建Snapshots,并回调进入的onCreateSnapshotView
- scheduleSetSharedElementEnd中添加decorView监听,在onPreDraw中回调onSharedElementEnd
- 设置共享元素的状态
- 触发进入的onSharedElementStart
- 最后通过transition执行动画
private void startSharedElementTransition(Bundle sharedElementState) {
ViewGroup decorView = getDecor();
if (decorView == null) {
return;
}
// Remove rejected shared elements
ArrayList<String> rejectedNames = new ArrayList<String>(mAllSharedElementNames);
rejectedNames.removeAll(mSharedElementNames);
ArrayList<View> rejectedSnapshots = createSnapshots(sharedElementState, rejectedNames);
if (mListener != null) {
mListener.onRejectSharedElements(rejectedSnapshots);
}
removeNullViews(rejectedSnapshots);
startRejectedAnimations(rejectedSnapshots);
// Now start shared element transition
ArrayList<View> sharedElementSnapshots = createSnapshots(sharedElementState,
mSharedElementNames);
showViews(mSharedElements, true);
scheduleSetSharedElementEnd(sharedElementSnapshots);
ArrayList<SharedElementOriginalState> originalImageViewState =
setSharedElementState(sharedElementState, sharedElementSnapshots);
requestLayoutForSharedElements();
boolean startEnterTransition = allowOverlappingTransitions() && !mIsReturning;
boolean startSharedElementTransition = true;
setGhostVisibility(View.INVISIBLE);
scheduleGhostVisibilityChange(View.INVISIBLE);
pauseInput();
Transition transition = beginTransition(decorView, startEnterTransition,
startSharedElementTransition);
scheduleGhostVisibilityChange(View.VISIBLE);
setGhostVisibility(View.VISIBLE);
if (startEnterTransition) {
startEnterTransition(transition);
}
setOriginalSharedElementState(mSharedElements, originalImageViewState);
if (mResultReceiver != null) {
// We can't trust that the view will disappear on the same frame that the shared
// element appears here. Assure that we get at least 2 frames for double-buffering.
decorView.postOnAnimation(new Runnable() {
int mAnimations;
@Override
public void run() {
if (mAnimations++ < MIN_ANIMATION_FRAMES) {
View decorView = getDecor();
if (decorView != null) {
decorView.postOnAnimation(this);
}
} else if (mResultReceiver != null) {
mResultReceiver.send(MSG_HIDE_SHARED_ELEMENTS, null);
mResultReceiver = null; // all done sending messages.
}
}
});
}
}
scheduleSetSharedElementEnd中会添加decorView的onPreDraw监听,然后在onPreDraw中触发进入的onSharedElementEnd
protected void scheduleSetSharedElementEnd(final ArrayList<View> snapshots) {
final View decorView = getDecor();
if (decorView != null) {
OneShotPreDrawListener.add(decorView, () -> {
notifySharedElementEnd(snapshots);
});
}
}
protected void notifySharedElementEnd(ArrayList<View> snapshots) {
if (mListener != null) {
mListener.onSharedElementEnd(mSharedElementNames, mSharedElements, snapshots);
}
}
设置共享元素状态时,默认有elevation、位置(上下左右)、大小。并且对ImageView做了特殊判断,会多添加scaleType和matrix
private void setSharedElementState(View view, String name, Bundle transitionArgs, Matrix tempMatrix, RectF tempRect, int[] decorLoc) {
Bundle sharedElementBundle = transitionArgs.getBundle(name);
if (sharedElementBundle == null) {
return;
}
if (view instanceof ImageView) {
int scaleTypeInt = sharedElementBundle.getInt(KEY_SCALE_TYPE, -1);
if (scaleTypeInt >= 0) {
ImageView imageView = (ImageView) view;
ImageView.ScaleType scaleType = SCALE_TYPE_VALUES[scaleTypeInt];
imageView.setScaleType(scaleType);
if (scaleType == ImageView.ScaleType.MATRIX) {
float[] matrixValues = sharedElementBundle.getFloatArray(KEY_IMAGE_MATRIX);
tempMatrix.setValues(matrixValues);
imageView.setImageMatrix(tempMatrix);
}
}
}
float z = sharedElementBundle.getFloat(KEY_TRANSLATION_Z);
view.setTranslationZ(z);
float elevation = sharedElementBundle.getFloat(KEY_ELEVATION);
view.setElevation(elevation);
float left = sharedElementBundle.getFloat(KEY_SCREEN_LEFT);
float top = sharedElementBundle.getFloat(KEY_SCREEN_TOP);
float right = sharedElementBundle.getFloat(KEY_SCREEN_RIGHT);
float bottom = sharedElementBundle.getFloat(KEY_SCREEN_BOTTOM);
if (decorLoc != null) {
left -= decorLoc[0];
top -= decorLoc[1];
right -= decorLoc[0];
bottom -= decorLoc[1];
} else {
// Find the location in the view's parent
getSharedElementParentMatrix(view, tempMatrix);
tempRect.set(left, top, right, bottom);
tempMatrix.mapRect(tempRect);
float leftInParent = tempRect.left;
float topInParent = tempRect.top;
// Find the size of the view
view.getInverseMatrix().mapRect(tempRect);
float width = tempRect.width();
float height = tempRect.height();
// Now determine the offset due to view transform:
view.setLeft(0);
view.setTop(0);
view.setRight(Math.round(width));
view.setBottom(Math.round(height));
tempRect.set(0, 0, width, height);
view.getMatrix().mapRect(tempRect);
left = leftInParent - tempRect.left;
top = topInParent - tempRect.top;
right = left + width;
bottom = top + height;
}
int x = Math.round(left);
int y = Math.round(top);
int width = Math.round(right) - x;
int height = Math.round(bottom) - y;
int widthSpec = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY);
int heightSpec = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY);
view.measure(widthSpec, heightSpec);
view.layout(x, y, x + width, y + height);
}
Transition的效果主要是通过属性动画来实现,通过createAnimator创建Animator,默认实现有ChangeBounds,ChangeClipBounds,ChangeImageTransform,ChangeScroll,ChangeTransform,Visibility
void playTransition(ViewGroup sceneRoot) {
...
createAnimators(sceneRoot, mStartValues, mEndValues, mStartValuesList, mEndValuesList);
runAnimators();
}
protected void createAnimators(ViewGroup sceneRoot, TransitionValuesMaps startValues, TransitionValuesMaps endValues, ArrayList<TransitionValues> startValuesList, ArrayList<TransitionValues> endValuesList) {
...
for (int i = 0; i < startValuesListCount; ++i) {
TransitionValues start = startValuesList.get(i);
TransitionValues end = endValuesList.get(i);
...
if (isChanged) {
...
Animator animator = createAnimator(sceneRoot, start, end);
if (animator != null) {
// Save animation info for future cancellation purposes
...
if (animator != null) {
...
mAnimators.add(animator);
}
}
}
}
...
}
今天的文章从源码了解共享元素的具体实现逻辑分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/22317.html