我正在努力实现以下目标:
我有一个项目视图,显示ViewPager
包含该项目的图像和其他一些信息。当用户点击其中一个ViewPager
的图片时,我希望第一个屏幕上的图片与新ViewPager
中另一个Activity
上的相同图片之间进行转换}。
到目前为止,我已经设法使基本功能正常工作,但有一些关键的事情没有按预期工作:
ViewPager
A中索引0或1处的图片时,Activity
A与ViewPager
B的ViewPager
的转换才有效。ViewPager
中的Activity
B按回来时 是返回动画 - 只要我不滑动到另一个图像,所以转换来自全屏模式我将在ViewPager
B中显示ViewPager
A中的相同图像。当滑动到另一个图像并按下时 - 没有动画。第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" />