我有一个 fragment ,我正在从中启动带有 viewpager 的共享元素转换的 Activity ,输入转换工作正常,但是当我在 View 寻呼机中滚动并完成转换时,共享图像来自左侧,这是不需要的应该将自身重新定位到启动的位置,这是我的代码:
Intent myIntent = new Intent(getActivity(), EnlargeActivity.class);
ActivityOptionsCompat options = ActivityOptionsCompat.
makeSceneTransitionAnimation(getActivity(),
imageView,
ViewCompat.getTransitionName(imageView));
startActivity(myIntent, options.toBundle());
我在完成 Activity 时更新包含 viewpager 的 Activity 中的 View 及其名称,但它与闪烁一起使用:
public void finishAfterTransition() {
setEnterSharedElementCallback(new SharedElementCallback() {
@Override
public void onMapSharedElements(List<String> names, Map<String, View> sharedElements) {
// Clear all current shared views and names
names.clear();
sharedElements.clear();
ViewGroup viewGroup = (ViewGroup) viewPagerDetail.getAdapter()
.instantiateItem(viewPagerDetail, viewPagerDetail.getCurrentItem());
if (viewGroup == null) {
return;
}
// Map the first shared element name to the child ImageView.
sharedElements.put(viewGroup.findViewById(R.id.img).getTransitionName(), viewGroup.findViewById(R.id.img));
// setExitSharedElementCallback((SharedElementCallback) this);
}
});
super.finishAfterTransition();
最佳答案
基本上,Android 会使用您预定义的 View
开始转换。和transitionName
并自动使用相同的属性进行返回转换。当您在 ViewPager 中更改焦点 View 时,Android 不会知道这一点,并会在返回时保持前一个 View 的转换。因此您需要将更改通知 Android:
- 重新映射过渡属性:使用
setEnterSharedElementCallback
更改transitionName
和View
从Activity2
返回之前到新的. - 等待
Activity1
完成渲染addOnPreDrawListener
.
最终的实现有点复杂。不过你可以看看我的示例代码https://github.com/tamhuynhit/PhotoGallery 。我尝试实现从许多简单部分到复杂部分的共享元素转换。
您的问题出现在 Level 3
并在 Level 4
中解决。
我正在写一个关于此的教程,但它不是英文的,所以希望代码可以提供帮助
更新 1:工作流程
以下是我在代码中实现它的方法:
覆盖
finishAfterTransition
在 Activity2 中并调用setEnterSharedElementCallback
方法重新映射 ViewPager 中当前选定的项目。另外,请调用setResult
将新选定的索引传递回此处的先前 Activity 。@Override @TargetApi(Build.VERSION_CODES.LOLLIPOP) public void finishAfterTransition() { setEnterSharedElementCallback(new SharedElementCallback() { @Override public void onMapSharedElements(List<String> names, Map<String, View> sharedElements) { View selectedView = getSelectedView(); if (selectedView == null) return; // Clear all current shared views and names names.clear(); sharedElements.clear(); // Store new selected view and name String transitionName = ViewCompat.getTransitionName(selectedView); names.add(transitionName); sharedElements.put(transitionName, selectedView); setExitSharedElementCallback((SharedElementCallback) null); } }); Intent intent = new Intent(); intent.putExtra(PHOTO_FOCUSED_INDEX, mCurrentIndex); setResult(RESULT_PHOTO_CLOSED, intent); super.finishAfterTransition(); }
编写自定义
ShareElementCallback
所以我可以在知道哪个View
之前设置回调即将被使用。@TargetApi(Build.VERSION_CODES.LOLLIPOP) private static class CustomSharedElementCallback extends SharedElementCallback { private View mView; /** * Set the transtion View to the callback, this should be called before starting the transition so the View is not null */ public void setView(View view) { mView = view; } @Override public void onMapSharedElements(List<String> names, Map<String, View> sharedElements) { // Clear all current shared views and names names.clear(); sharedElements.clear(); // Store new selected view and name String transitionName = ViewCompat.getTransitionName(mView); names.add(transitionName); sharedElements.put(transitionName, mView); } }
覆盖
onActivityReenter
在Activity1中,从结果Intent
中获取选定的索引。设置setExitSharedElementCallback
重新映射新选定的View
当过渡开始时。调用supportPostponeEnterTransition
延迟一下,因为你的新View
此时可能无法渲染。使用getViewTreeObserver().addOnPreDrawListener
要监听布局更改,请找到正确的View
按所选索引并继续转换supportStartPostponedEnterTransition
.@Override @TargetApi(Build.VERSION_CODES.LOLLIPOP) public void onActivityReenter(int resultCode, Intent data) { if (resultCode != LevelFourFullPhotoActivity.RESULT_PHOTO_CLOSED || data == null) return; final int selectedIndex = data.getIntExtra(LevelFourFullPhotoActivity.PHOTO_FOCUSED_INDEX, -1); if (selectedIndex == -1) return; // Scroll to the new selected view in case it's not currently visible on the screen mPhotoList.scrollToPosition(selectedIndex); final CustomSharedElementCallback callback = new CustomSharedElementCallback(); getActivity().setExitSharedElementCallback(callback); // Listen for the transition end and clear all registered callback getActivity().getWindow().getSharedElementExitTransition().addListener(new Transition.TransitionListener() { @Override public void onTransitionStart(Transition transition) {} @Override public void onTransitionPause(Transition transition) {} @Override public void onTransitionResume(Transition transition) {} @Override public void onTransitionEnd(Transition transition) { removeCallback(); } @Override public void onTransitionCancel(Transition transition) { removeCallback(); } private void removeCallback() { if (getActivity() != null) { getActivity().getWindow().getSharedElementExitTransition().removeListener(this); getActivity().setExitSharedElementCallback((SharedElementCallback) null); } } }); // Pause transition until the selected view is fully drawn getActivity().supportPostponeEnterTransition(); // Listen for the RecyclerView pre draw to make sure the selected view is visible, // and findViewHolderForAdapterPosition will return a non null ViewHolder mPhotoList.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { mPhotoList.getViewTreeObserver().removeOnPreDrawListener(this); RecyclerView.ViewHolder holder = mPhotoList.findViewHolderForAdapterPosition(selectedIndex); if (holder instanceof ViewHolder) { callback.setView(((ViewHolder) holder).mPhotoImg); } // Continue the transition getActivity().supportStartPostponedEnterTransition(); return true; } }); }
更新 2:getSelectedItem
要从 ViewPager 获取选定的 View ,请勿使用 getChildAt
或者你得到错误的 View ,使用findViewWithTag
相反
在 PagerAdapter.instantiateItem
,使用position作为每个View的标签:
@Override
public View instantiateItem(ViewGroup container, int position) {
// Create the View
view.setTag(position)
// ...
}
听onPageSelected
获取所选索引的事件:
mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
mSelectedIndex = position;
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
调用getSelectedView
通过所选索引获取当前 View
private View getSelectedView() {
try {
return mPhotoViewPager.findViewWithTag(mSelectedIndex);
} catch (IndexOutOfBoundsException | NullPointerException ex) {
return null;
}
}
关于java - 共享元素转换未正确退出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50189286/