From 5f41769485e72570e94dd95fdfa46b8f446f788d Mon Sep 17 00:00:00 2001 From: Ahmed El-Helw Date: Fri, 22 Jul 2016 15:30:58 -0700 Subject: [PATCH] Fix ViewPager behavior with Nodes Summary: Add a batch addition operation for ViewPager. Differential Revision: D3597840 fbshipit-source-id: 1c9c42e03da2492444298220e75f547b6567b4e5 --- .../react/uimanager/ViewGroupManager.java | 20 +++++++-- .../react/views/viewpager/ReactViewPager.java | 41 ++++++++++++++++++- 2 files changed, 56 insertions(+), 5 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewGroupManager.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewGroupManager.java index a5094e7d5..6a728db8f 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewGroupManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/ViewGroupManager.java @@ -9,15 +9,16 @@ package com.facebook.react.uimanager; -import android.view.View; -import android.view.ViewGroup; - import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; +import java.util.List; import java.util.WeakHashMap; +import android.view.View; +import android.view.ViewGroup; + /** * Class providing children management API for view managers of classes extending ViewGroup. */ @@ -45,6 +46,19 @@ public abstract class ViewGroupManager reorderChildrenByZIndex(parent); } + /** + * Convenience method for batching a set of addView calls + * Note that this adds the views to the beginning of the ViewGroup + * + * @param parent the parent ViewGroup + * @param views the set of views to add + */ + public void addViews(T parent, List views) { + for (int i = 0, size = views.size(); i < size; i++) { + addView(parent, views.get(i), i); + } + } + public static void setViewZIndex(View view, int zIndex) { mZIndexHash.put(view, zIndex); // zIndex prop gets set BEFORE the view is added, so parent may be null. diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/viewpager/ReactViewPager.java b/ReactAndroid/src/main/java/com/facebook/react/views/viewpager/ReactViewPager.java index 3f9d8961a..c5a2ea12f 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/viewpager/ReactViewPager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/viewpager/ReactViewPager.java @@ -28,11 +28,12 @@ import com.facebook.react.uimanager.events.NativeGestureUtil; * views to custom {@link PagerAdapter} instance which is used by {@link NativeViewHierarchyManager} * to add children nodes according to react views hierarchy. */ -/* package */ class ReactViewPager extends ViewPager { +public class ReactViewPager extends ViewPager { private class Adapter extends PagerAdapter { private final List mViews = new ArrayList<>(); + private boolean mIsViewPagerInIntentionallyInconsistentState = false; void addView(View child, int index) { mViews.add(index, child); @@ -57,6 +58,32 @@ import com.facebook.react.uimanager.events.NativeGestureUtil; setOffscreenPageLimit(mViews.size()); } + /** + * Replace a set of views to the ViewPager adapter and update the ViewPager + */ + void setViews(List views) { + mViews.clear(); + mViews.addAll(views); + notifyDataSetChanged(); + + // we want to make sure we return POSITION_NONE for every view here, since this is only + // called after a removeAllViewsFromAdapter + mIsViewPagerInIntentionallyInconsistentState = false; + } + + /** + * Remove all the views from the adapter and de-parents them from the ViewPager + * After calling this, it is expected that notifyDataSetChanged should be called soon + * afterwards. + */ + void removeAllViewsFromAdapter(ViewPager pager) { + mViews.clear(); + pager.removeAllViews(); + // set this, so that when the next addViews is called, we return POSITION_NONE for every + // entry so we can remove whichever views we need to and add the ones that we need to. + mIsViewPagerInIntentionallyInconsistentState = true; + } + View getViewAt(int index) { return mViews.get(index); } @@ -68,7 +95,9 @@ import com.facebook.react.uimanager.events.NativeGestureUtil; @Override public int getItemPosition(Object object) { - return mViews.contains(object) ? mViews.indexOf(object) : POSITION_NONE; + // if we've removed all views, we want to return POSITION_NONE intentionally + return mIsViewPagerInIntentionallyInconsistentState || !mViews.contains(object) ? + POSITION_NONE : mViews.indexOf(object); } @Override @@ -190,4 +219,12 @@ import com.facebook.react.uimanager.events.NativeGestureUtil; /*package*/ View getViewFromAdapter(int index) { return getAdapter().getViewAt(index); } + + public void setViews(List views) { + getAdapter().setViews(views); + } + + public void removeAllViewsFromAdapter() { + getAdapter().removeAllViewsFromAdapter(this); + } }