我有片段,我正在启动具有viewpager的共享元素转换的活动,输入转换工作正常但是当我在视图寻呼机中滚动并完成转换时,共享图像来自左侧,这是不希望的应该将自己重新定位到它的启动位置,这是我的代码:
Intent myIntent = new Intent(getActivity(), EnlargeActivity.class);
ActivityOptionsCompat options = ActivityOptionsCompat.
makeSceneTransitionAnimation(getActivity(),
imageView,
ViewCompat.getTransitionName(imageView));
startActivity(myIntent, options.toBundle());
我在完成活动时在包含viewpager的活动中更新视图及其名称,但它会闪烁:
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();
答案 0 :(得分:0)
这实际上是一种默认行为,我在很多方面都在努力争取SharedElementTransitions,但我已经嵌套了片段。我从一篇文章(最近的文章)中得到了我的解决方案,它显示了一个RecyclerView
的实现,我猜你有。简而言之,解决方案是覆盖onLayoutChange
:
recyclerView.addOnLayoutChangeListener(
new OnLayoutChangeListener() {
@Override
public void onLayoutChange(View view,
int left,
int top,
int right,
int bottom,
int oldLeft,
int oldTop,
int oldRight,
int oldBottom) {
recyclerView.removeOnLayoutChangeListener(this);
final RecyclerView.LayoutManager layoutManager =
recyclerView.getLayoutManager();
View viewAtPosition =
layoutManager.findViewByPosition(MainActivity.currentPosition);
// Scroll to position if the view for the current position is null (not
// currently part of layout manager children), or it's not completely
// visible.
if (viewAtPosition == null
|| layoutManager.isViewPartiallyVisible(viewAtPosition, false, true)){
recyclerView.post(()
-> layoutManager.scrollToPosition(MainActivity.currentPosition));
}
}
});
答案 1 :(得分:0)
基本上,Android会使用预定义的View
和transitionName
启动转换,并自动使用相同的属性进行返回转换。当您在ViewPager中更改焦点视图时,Android不知道这一点,并在返回途中保持对前一个的转换。因此,您需要告知Android有关更改的信息:
setEnterSharedElementCallback
返回之前,使用transitionName
将View
和Activity2
更改为新属。Activity1
完成呈现addOnPreDrawListener
。最终实施中有点复杂。但是你可以查看我的示例代码https://github.com/tamhuynhit/PhotoGallery。我尝试实现从许多简单到复杂部分的共享元素转换。
您的问题出现在Level 3
,并在Level 4
中解决了。
我正在编写一个关于此的教程,但它不是英文的,所以希望代码可以提供帮助
更新1:工作流程
以下是我在代码中实现的方法:
覆盖Activity2中的finishAfterTransition
并调用setEnterSharedElementCallback
方法重新映射ViewPager中当前选定的项目。此外,请致电setResult
将新选定的索引传回此处的上一个活动。
@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);
}
}
在Activity1中覆盖onActivityReenter
,从结果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获取选定的视图,请不要使用getChildAt
,否则您的视图会显示错误,请改用findViewWithTag
在PagerAdapter.instantiateItem
中,使用position作为每个视图的标记:
@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
以获取所选索引的当前视图
private View getSelectedView() {
try {
return mPhotoViewPager.findViewWithTag(mSelectedIndex);
} catch (IndexOutOfBoundsException | NullPointerException ex) {
return null;
}
}