当前位置: 首页 > 知识库问答 >
问题:

共享元素转换未正确退出

薛弘壮
2023-03-14
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();

共有1个答案

郑波
2023-03-14

基本上,Android使用预定义的视图transitionname开始转换,并自动将相同的属性用于返回转换。当你在ViewPager中改变你的聚焦视图时,Android并不知道这一点,而是在返回的路上保持上一个的转换。因此您需要通知Android有关更改:

  • 重新映射转换属性:在从Activity2返回之前,使用SetEnterShareDelementCallbackTransitionName视图更改为新的。
  • 等待Activity1完成呈现AddonPredrawListener

在最终实现中有点复杂。但是您可以查看我的示例代码https://github.com/tamhuynhit/photogally。我试图实现从许多简单节到复杂节的共享元素转换。您的问题出现在级别3中,并在级别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,这样我就可以在知道要使用哪个视图之前设置回调。

    @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以在转换开始时重新映射新的选定视图。调用SupportPostponeEntertransition以延迟一点,因为此时可能无法呈现新的视图。使用GetViewTreeObserver().AddonPredrawListener侦听布局更改,根据所选索引找到正确的视图并继续转换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

    若要从视图页获取选定视图,请不要使用getchildat,否则获取的视图是错误的,请使用findviewwithtag

    PagerAdapter.InstantiateItem中,将position用作每个视图的标记:

    @Override
    public View instantiateItem(ViewGroup container, int position) {
        // Create the View
        view.setTag(position)
    
        // ...
    }
    
    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) {
    
        }
    });
    
    private View getSelectedView() {
        try {
            return mPhotoViewPager.findViewWithTag(mSelectedIndex);
        } catch (IndexOutOfBoundsException | NullPointerException ex) {
            return null;
        }
    }
    

  •  类似资料:
    • 我一直在尝试实现这个共享元素转换,并在单击转换时不断出现“java.lang.IllegalArgumentException:共享元素不能为null”错误。请帮忙。 这是下面给出的MainActive onCreate方法。请检查我的代码。 这是recyclerView的onClickListener。 图像的过渡名称相同。这里的bug修复在使用共享元素的活动转换中出现问题并不是问题所在。 我卡

    • 我正在实现一个gallery应用程序,它有一个片段,其中包含一个带有图像的RecyclerView,单击一个图像,我会转到ViewPager循环浏览图像 目前,我正试图实现像本视频中那样的入门动画。问题是动画不起作用,我显然遗漏了一些东西(只是显示与转换相关的代码): 查看页面: GridAdapter: 在MainActivity中,我在onClick中实例化ViewPagerFragment:

    • 我在Lollipop上的共享元素转换中看到了奇怪的事情。共享元素在开始动画之前闪烁(请看视频https://www.youtube.com/watch?v=DCoyyC_S-9A) 我不知道为什么会这样。但是,当我添加

    • 我希望采用Glide库来代替通用图像加载器,但在共享元素转换方面遇到了问题。 在我的简单沙盒中,我使用UIL创建了以下过渡:https://dl.dropboxusercontent.com/u/97787025/device-2015-06-18-113333.mp4 非常简单,而且效果很好。但当我使用Glide时,它看起来不太好看:https://dl.dropboxusercontent.c

    • 我已经研究这个问题几个星期了,但我仍然无法解决这个问题。 我有一个CardView,它包含一个带有ImageView的线性布局。 没有那个半径共享元素过渡可以无缝工作。但是,当我将半径(app: cardCornerRadius="25dp")添加到CardView时,共享元素过渡看起来很难看,因为它首先删除半径,然后开始动画。 第一种方法:ObjectAnimator 我创建ObjectAnim

    • 我点击了recyclerview的项目,打开了一个共享元素转换的活动,如下所示: 在活动中,它有视图寻呼机: 在扩展FragmentStatePagerAdapter的viewpager适配器中,返回一个片段ProductDetailViewPagerFraack,该片段具有一个Imageview和im加载图像,如:(MainActivity.position是回收器视图的位置)