两个ViewPagers之间的Android共享元素转换

时间:2016-11-21 00:25:41

标签: android android-viewpager android-transitions shared-element-transition

我正在努力实现以下目标:

我有一个项目视图,显示ViewPager包含该项目的图像和其他一些信息。当用户点击其中一个ViewPager的图片时,我希望第一个屏幕上的图片与新ViewPager中另一个Activity上的相同图片之间进行转换}。

到目前为止,我已经设法使基本功能正常工作,但有一些关键的事情没有按预期工作:

  1. 只有点击ViewPager A中索引0或1处的图片时,Activity A与ViewPager B的ViewPager的转换才有效。
  2. 当从新ViewPager中的Activity B按回来时 是返回动画 - 只要我不滑动到另一个图像,所以转换来自全屏模式我将在ViewPager B中显示ViewPager A中的相同图像。当滑动到另一个图像并按下时 - 没有动画。
  3. 第1号正在发生,因为ViewPager的前几页在创建时会被实例化,因此instantiateItem的{​​{1}}方法会被调用,这就是我正在设置Adapter。 事实证明,在transitionName上调用此问题会使问题消失,并且条目动画可在所有屏幕上运行:

    ViewPager

    显然这是不可持续的,我宁愿有这么高的屏幕外限。

    我的问题有两个:

    如何在不通过上述黑客将所有页面保留在内存中的情况下为每个detailPager.setOffscreenPageLimit(largeNumber);项目实现动画?

    如何在ViewPager B中滑动到另一个页面时确保返回转换?

    我在下面提供了我的代码:

    ItemActivity

    ViewPager

    ItemFragment - 这是第一个ViewPager

    的地方
    public class ItemActivity extends AppCompatActivity {
    
    private static final String ITEM_TAG = "item_tag";
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_with_fragment_container);
        ButterKnife.bind(this);
        if (savedInstanceState == null) {
            attachFragment();
        }
    }
    
    private void attachFragment() {
        getSupportFragmentManager().beginTransaction()
                .replace(R.id.fragment_container, ItemFragment.newInstance(), ITEM_TAG)
                .commit();
    }
    
    @Override
    public void onActivityReenter(int resultCode, Intent data) {
        super.onActivityReenter(resultCode, data);
        ItemFragment fragment = (ItemFragment) getSupportFragmentManager().findFragmentByTag(ITEM_TAG);
        if (fragment != null) {
            fragment.onReenter(data);
        }
    }}
    

    }

    FullScreenActivity - 这是第二个ViewPager所在的位置

    public class ItemFragment extends Fragment implements MyAdapter.MyListener {
    
    public static final String EXTRA_STARTING_ALBUM_POSITION = "extra_starting_item_position";
    public static final String EXTRA_CURRENT_ALBUM_POSITION = "extra_current_item_position";
    public static final String[] IMAGE_NAMES = {"One", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten"};
    private static final int FULL_SCREEN_CODE = 1234;
    
    private Unbinder unbinder;
    private Bundle tempReenterState;
    private final SharedElementCallback callback = new SharedElementCallback() {
        @Override
        public void onMapSharedElements(List<String> names, Map<String, View> sharedElements) {
            if (tempReenterState != null) {
                int startingPosition = tempReenterState.getInt(EXTRA_STARTING_ALBUM_POSITION);
                int currentPosition = tempReenterState.getInt(EXTRA_CURRENT_ALBUM_POSITION);
                if (startingPosition != currentPosition) {
    
                    String newTransitionName = IMAGE_NAMES[currentPosition];
                    View newSharedElement = detailPager.findViewWithTag(newTransitionName);
                    if (newSharedElement != null) {
                        names.clear();
                        names.add(newTransitionName);
                        sharedElements.clear();
                        sharedElements.put(newTransitionName, newSharedElement);
                    }
                }
    
                tempReenterState = null;
            } else {
                View navigationBar = getActivity().findViewById(android.R.id.navigationBarBackground);
                View statusBar = getActivity().findViewById(android.R.id.statusBarBackground);
                if (navigationBar != null) {
                    names.add(navigationBar.getTransitionName());
                    sharedElements.put(navigationBar.getTransitionName(), navigationBar);
                }
                if (statusBar != null) {
                    names.add(statusBar.getTransitionName());
                    sharedElements.put(statusBar.getTransitionName(), statusBar);
                }
            }
        }
    };
    
    private List<String> images = Arrays.asList("http://wowslider.com/sliders/demo-9/data/images/1293441583_nature_forest_morning_in_the_forest_015232_.jpg",
            "http://wowslider.com/sliders/demo-18/data1/images/hongkong1081704.jpg",
            "http://www.irishtimes.com/polopoly_fs/1.2614603.1461003507!/image/image.jpg_gen/derivatives/box_620_330/image.jpg",
            "http://weknowyourdreams.com/images/sky/sky-05.jpg");
    
    @BindView(R.id.detail_pager)
    ViewPager detailPager;
    
    public static ItemFragment newInstance() {
        return new ItemFragment();
    }
    
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_image_detail, container, false);
        unbinder = ButterKnife.bind(this, view);
        return view;
    }
    
    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        ActivityCompat.setExitSharedElementCallback(getActivity(), callback);
        detailPager.setAdapter(new MyAdapter(getActivity(), images, this));
    
    }
    
    @Override
    public void goFullScreen(final int position, View view) {
        Intent intent = FullScreenActivity.newIntent(getActivity(), position, images);
        startActivityForResult(intent, FULL_SCREEN_CODE, ActivityOptions.makeSceneTransitionAnimation(getActivity(), view, view.getTransitionName()).toBundle());
    }
    
    public void onReenter(Intent data) {
        tempReenterState = new Bundle(data.getExtras());
        int startingPosition = tempReenterState.getInt(EXTRA_STARTING_ALBUM_POSITION);
        int currentPosition = tempReenterState.getInt(EXTRA_CURRENT_ALBUM_POSITION);
        if (startingPosition != currentPosition) {
            detailPager.setCurrentItem(currentPosition, false);
        }
        ActivityCompat.postponeEnterTransition(getActivity());
        detailPager.post(new Runnable() {
            @Override
            public void run() {
                ActivityCompat.startPostponedEnterTransition(getActivity());
            }
        });
    }
    
    @Override
    public void onDestroyView() {
        super.onDestroyView();
        if (unbinder != null) {
            unbinder.unbind();
        }
    }
    

    }

    MyAdapter

    public class FullScreenActivity extends AppCompatActivity {
    
    private final SharedElementCallback callback = new SharedElementCallback() {
        @Override
        public void onMapSharedElements(List<String> names, Map<String, View> sharedElements) {
            if (mIsReturning) {
                if (currentImage == null) {
                    // If shared element is null, then it has been scrolled off screen and
                    // no longer visible. In this case we cancel the shared element transition by
                    // removing the shared element from the shared elements map.
                    names.clear();
                    sharedElements.clear();
                } else if (selectedIndex != mCurrentPosition) {
                    // If the user has swiped to a different ViewPager page, then we need to
                    // remove the old shared element and replace it with the new shared element
                    // that should be transitioned instead.
                    names.clear();
                    names.add(currentImage.getTransitionName());
                    sharedElements.clear();
                    sharedElements.put(currentImage.getTransitionName(), currentImage);
                }
            }
        }
    };
    
    private boolean mIsReturning;
    private int mCurrentPosition;
    private int selectedIndex;
    
    
    private static final String ARG_PRESELECTED_INDEX = "arg_preselected_index";
    private static final String ARG_GALLERY_IMAGES = "arg_gallery_images";
    
    public static final String KEY_SELECTED_IMAGE_INDEX = "key_selected_image_index";
    
    public static final String KEY_RETAINED_IMAGES = "key_retained_images";
    private static final int DEFAULT_SELECTED_INDEX = 0;
    
    private List<String> images;
    private ImageAdapter adapter;
    private ImageView currentImage;
    
    @BindView(R.id.full_screen_pager)
    ViewPager viewPager;
    
    public static Intent newIntent(@NonNull final Context context, final int selectedIndex, @NonNull final List<String> images) {
        Intent intent = new Intent(context, FullScreenActivity.class);
        intent.putExtra(ARG_PRESELECTED_INDEX, selectedIndex);
        intent.putStringArrayListExtra(ARG_GALLERY_IMAGES, new ArrayList<>(images));
        return intent;
    }
    
    @CallSuper
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.layout_full_screen);
        ButterKnife.bind(this);
        ActivityCompat.postponeEnterTransition(this);
        ActivityCompat.setExitSharedElementCallback(this, callback);
    
        if (savedInstanceState == null) {
            selectedIndex = getIntent().getIntExtra(ARG_PRESELECTED_INDEX, 0);
            mCurrentPosition = selectedIndex;
            images = getIntent().getStringArrayListExtra(ARG_GALLERY_IMAGES);
        } else {
            selectedIndex = savedInstanceState.getInt(KEY_SELECTED_IMAGE_INDEX);
            images = savedInstanceState.getStringArrayList(KEY_RETAINED_IMAGES);
        }
        setupViewPager(selectedIndex, images);
    }
    
    private void setupViewPager(final int selectedIndex, List<String> images) {
        adapter = new ImageAdapter(this, images);
        viewPager.post(new Runnable() {
            @Override
            public void run() {
                viewPager.setAdapter(adapter);
                viewPager.setCurrentItem(selectedIndex);
                viewPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
                    @Override
                    public void onPageSelected(int position) {
                        mCurrentPosition = position;
                    }
                });
                ActivityCompat.startPostponedEnterTransition(FullScreenActivity.this);
            }
        });
    }
    
    @Override
    public void finishAfterTransition() {
        mIsReturning = true;
        Intent data = new Intent();
        data.putExtra(EXTRA_STARTING_ALBUM_POSITION, selectedIndex);
        data.putExtra(EXTRA_CURRENT_ALBUM_POSITION, viewPager.getCurrentItem());
        setResult(RESULT_OK, data);
        super.finishAfterTransition();
    }
    
    private class ImageAdapter extends PagerAdapter {
    
        private final LayoutInflater layoutInflater;
        private final List<String> images;
        private ImageLoader<ImageView> imageLoader;
    
        public ImageAdapter(Context context, List<String> images) {
            this.imageLoader = new PicassoImageLoader(context);
            this.images = images;
            this.layoutInflater = LayoutInflater.from(context);
        }
    
        @Override
        public int getCount() {
            return images.size();
        }
    
        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            final ImageView imageView = (ImageView) layoutInflater.inflate(R.layout.full_image, container, false);
            imageView.setTransitionName(IMAGE_NAMES[position]);
            imageView.setTag(IMAGE_NAMES[position]);
            imageLoader.loadImage(images.get(position), imageView);
            container.addView(imageView);
            return imageView;
        }
    
        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            container.removeView((ImageView) object);
        }
    
        @Override
        public void setPrimaryItem(ViewGroup container, int position, Object object) {
            super.setPrimaryItem(container, position, object);
            currentImage = (ImageView) object;
        }
    
        @Override
        public boolean isViewFromObject(View view, Object object) {
            return view == object;
        }
    }
    

    }

    ImageLoader的

    public class MyAdapter extends PagerAdapter {
    
    private final LayoutInflater layoutInflater;
    private final List<String> images;
    private final MyListener listener;
    
    private ImageLoader<ImageView> imageLoader;
    
    public interface MyListener {
        void goFullScreen(final int position, View selected);
    }
    
    public MyAdapter(Context context, List<String> images, MyListener listener) {
        this.imageLoader = new PicassoImageLoader(context);
        this.layoutInflater = LayoutInflater.from(context);
        this.images = images;
        this.listener = listener;
    }
    
    @Override
    public int getCount() {
        return images.size();
    }
    
    @Override
    public Object instantiateItem(ViewGroup container, final int position) {
        final ImageView imageView = (ImageView) layoutInflater.inflate(R.layout.pager_item_image_thing, container, false);
        imageView.setTransitionName(IMAGE_NAMES[position]);
        imageView.setTag(IMAGE_NAMES[position]);
        if (listener != null) {
            imageView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    listener.goFullScreen(position, imageView);
                }
            });
        }
        imageLoader.loadImage(images.get(position), imageView);
        container.addView(imageView);
        return imageView;
    }
    
    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        container.removeView((ImageView) object);
    }
    
    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view == object;
    }
    

    }

    PicassoImageLoader

    public interface ImageLoader<T extends ImageView> {
    
    void loadImage(@NonNull final Uri imageSource, @NonNull final T imageView);
    
    void loadImage(@NonNull final String imageSource, @NonNull final T imageView);
    

    }

    XML布局

    fragment_image_detail.xml

    public class PicassoImageLoader implements ImageLoader {
    
    private final Context context;
    
    public PicassoImageLoader(@NonNull final Context context) {
        this.context = context;
    }
    
    @Override
    public void loadImage(@NonNull Uri imageSource, @NonNull ImageView imageView) {
        Picasso.with(context).load(imageSource).into(imageView);
    }
    
    @Override
    public void loadImage(@NonNull String imageSource, @NonNull ImageView imageView) {
        Picasso.with(context).load(imageSource).into(imageView);
    }
    

    layout_full_screen.xml

     <?xml version="1.0" encoding="utf-8"?>
        <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
        android:orientation="vertical">
    
        <android.support.v4.view.ViewPager
            android:id="@+id/detail_pager"
            android:layout_width="match_parent"
            android:layout_height="390dp" />
    
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="This is the title"/>
    
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Some other descriptive text about things"/>
    
    </LinearLayout>
    

    pager_item_thing.xml

     <?xml version="1.0" encoding="utf-8"?>
       <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">
    
            <android.support.v4.view.ViewPager
                android:id="@+id/full_screen_pager"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />
    
        </LinearLayout>
    

    full_image.xml

    <?xml version="1.0" encoding="utf-8"?>
    <ImageView xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/pager_item_image"
        android:layout_width="match_parent"
        android:layout_height="200dp"
        android:foreground="?android:attr/selectableItemBackgroundBorderless"
        android:layout_marginBottom="16dp" />
    

0 个答案:

没有答案