mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Support contentOffset property in Android's ScrollView and HorizontalScrollView
Summary: For a very long time, iOS has supported the `contentOffset` property but Android has not: https://github.com/facebook/react-native/issues/6849 This property can be used, primarily, to autoscroll the ScrollView to a starting position when it is first rendered, to avoid "jumps" that occur by asynchronously scrolling to a start position. Changelog: [Android][Changed] ScrollView now supports `contentOffset` Reviewed By: mdvacca Differential Revision: D21198236 fbshipit-source-id: 2b0773569ba42120cb1fcf0f3847ca98af2285e7
This commit is contained in:
committed by
Facebook GitHub Bot
parent
bda8aaeec2
commit
ed29ba13f9
+31
-1
@@ -50,6 +50,8 @@ public class ReactHorizontalScrollView extends HorizontalScrollView
|
||||
private static final String CONTENT_OFFSET_LEFT = "contentOffsetLeft";
|
||||
private static final String CONTENT_OFFSET_TOP = "contentOffsetTop";
|
||||
|
||||
private static final int UNSET_CONTENT_OFFSET = -1;
|
||||
|
||||
private final OnScrollDispatchHelper mOnScrollDispatchHelper = new OnScrollDispatchHelper();
|
||||
private final @Nullable OverScroller mScroller;
|
||||
private final VelocityHelper mVelocityHelper = new VelocityHelper();
|
||||
@@ -76,6 +78,8 @@ public class ReactHorizontalScrollView extends HorizontalScrollView
|
||||
private boolean mSnapToEnd = true;
|
||||
private ReactViewBackgroundManager mReactBackgroundManager;
|
||||
private boolean mPagedArrowScrolling = false;
|
||||
private int pendingContentOffsetX = UNSET_CONTENT_OFFSET;
|
||||
private int pendingContentOffsetY = UNSET_CONTENT_OFFSET;
|
||||
private @Nullable StateWrapper mStateWrapper;
|
||||
|
||||
private final Rect mTempRect = new Rect();
|
||||
@@ -224,7 +228,13 @@ public class ReactHorizontalScrollView extends HorizontalScrollView
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int l, int t, int r, int b) {
|
||||
// Call with the present values in order to re-layout if necessary
|
||||
reactScrollTo(getScrollX(), getScrollY());
|
||||
// If a "pending" value has been set, we restore that value.
|
||||
// That value gets cleared by reactScrollTo.
|
||||
int scrollToX =
|
||||
pendingContentOffsetX != UNSET_CONTENT_OFFSET ? pendingContentOffsetX : getScrollX();
|
||||
int scrollToY =
|
||||
pendingContentOffsetY != UNSET_CONTENT_OFFSET ? pendingContentOffsetY : getScrollY();
|
||||
reactScrollTo(scrollToX, scrollToY);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -906,6 +916,7 @@ public class ReactHorizontalScrollView extends HorizontalScrollView
|
||||
public void reactSmoothScrollTo(int x, int y) {
|
||||
smoothScrollTo(x, y);
|
||||
updateStateOnScroll(x, y);
|
||||
setPendingContentOffsets(x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -917,6 +928,25 @@ public class ReactHorizontalScrollView extends HorizontalScrollView
|
||||
public void reactScrollTo(int x, int y) {
|
||||
scrollTo(x, y);
|
||||
updateStateOnScroll(x, y);
|
||||
setPendingContentOffsets(x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* If contentOffset is set before the View has been laid out, store the values and set them when
|
||||
* `onLayout` is called.
|
||||
*
|
||||
* @param x
|
||||
* @param y
|
||||
*/
|
||||
private void setPendingContentOffsets(int x, int y) {
|
||||
View child = getChildAt(0);
|
||||
if (child != null && child.getWidth() != 0 && child.getHeight() != 0) {
|
||||
pendingContentOffsetX = UNSET_CONTENT_OFFSET;
|
||||
pendingContentOffsetY = UNSET_CONTENT_OFFSET;
|
||||
} else {
|
||||
pendingContentOffsetX = x;
|
||||
pendingContentOffsetY = y;
|
||||
}
|
||||
}
|
||||
|
||||
public void updateState(@Nullable StateWrapper stateWrapper) {
|
||||
|
||||
+8
@@ -12,6 +12,7 @@ import android.util.DisplayMetrics;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.module.annotations.ReactModule;
|
||||
import com.facebook.react.uimanager.DisplayMetricsHolder;
|
||||
import com.facebook.react.uimanager.PixelUtil;
|
||||
@@ -299,4 +300,11 @@ public class ReactHorizontalScrollViewManager extends ViewGroupManager<ReactHori
|
||||
view.setFadingEdgeLength(0);
|
||||
}
|
||||
}
|
||||
|
||||
@ReactProp(name = "contentOffset")
|
||||
public void setContentOffset(ReactHorizontalScrollView view, ReadableMap value) {
|
||||
double x = value.getDouble("x");
|
||||
double y = value.getDouble("y");
|
||||
view.reactScrollTo((int) PixelUtil.toPixelFromDIP(x), (int) PixelUtil.toPixelFromDIP(y));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +55,8 @@ public class ReactScrollView extends ScrollView
|
||||
private static final String CONTENT_OFFSET_LEFT = "contentOffsetLeft";
|
||||
private static final String CONTENT_OFFSET_TOP = "contentOffsetTop";
|
||||
|
||||
private static final int UNSET_CONTENT_OFFSET = -1;
|
||||
|
||||
private final OnScrollDispatchHelper mOnScrollDispatchHelper = new OnScrollDispatchHelper();
|
||||
private final @Nullable OverScroller mScroller;
|
||||
private final VelocityHelper mVelocityHelper = new VelocityHelper();
|
||||
@@ -81,6 +83,8 @@ public class ReactScrollView extends ScrollView
|
||||
private boolean mSnapToEnd = true;
|
||||
private View mContentView;
|
||||
private ReactViewBackgroundManager mReactBackgroundManager;
|
||||
private int pendingContentOffsetX = UNSET_CONTENT_OFFSET;
|
||||
private int pendingContentOffsetY = UNSET_CONTENT_OFFSET;
|
||||
private @Nullable StateWrapper mStateWrapper;
|
||||
|
||||
public ReactScrollView(ReactContext context) {
|
||||
@@ -200,7 +204,13 @@ public class ReactScrollView extends ScrollView
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int l, int t, int r, int b) {
|
||||
// Call with the present values in order to re-layout if necessary
|
||||
reactScrollTo(getScrollX(), getScrollY());
|
||||
// If a "pending" value has been set, we restore that value.
|
||||
// That value gets cleared by reactScrollTo.
|
||||
int scrollToX =
|
||||
pendingContentOffsetX != UNSET_CONTENT_OFFSET ? pendingContentOffsetX : getScrollX();
|
||||
int scrollToY =
|
||||
pendingContentOffsetY != UNSET_CONTENT_OFFSET ? pendingContentOffsetY : getScrollY();
|
||||
reactScrollTo(scrollToX, scrollToY);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -777,6 +787,7 @@ public class ReactScrollView extends ScrollView
|
||||
public void reactSmoothScrollTo(int x, int y) {
|
||||
smoothScrollTo(x, y);
|
||||
updateStateOnScroll(x, y);
|
||||
setPendingContentOffsets(x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -788,6 +799,25 @@ public class ReactScrollView extends ScrollView
|
||||
public void reactScrollTo(int x, int y) {
|
||||
scrollTo(x, y);
|
||||
updateStateOnScroll(x, y);
|
||||
setPendingContentOffsets(x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* If contentOffset is set before the View has been laid out, store the values and set them when
|
||||
* `onLayout` is called.
|
||||
*
|
||||
* @param x
|
||||
* @param y
|
||||
*/
|
||||
private void setPendingContentOffsets(int x, int y) {
|
||||
View child = getChildAt(0);
|
||||
if (child != null && child.getWidth() != 0 && child.getHeight() != 0) {
|
||||
pendingContentOffsetX = UNSET_CONTENT_OFFSET;
|
||||
pendingContentOffsetY = UNSET_CONTENT_OFFSET;
|
||||
} else {
|
||||
pendingContentOffsetX = x;
|
||||
pendingContentOffsetY = y;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user