diff --git a/Libraries/Components/ScrollResponder.js b/Libraries/Components/ScrollResponder.js index aec5a260ed2..955d7ea43be 100644 --- a/Libraries/Components/ScrollResponder.js +++ b/Libraries/Components/ScrollResponder.js @@ -415,12 +415,6 @@ var ScrollResponderMixin = { scrollResponderScrollToEnd: function( options?: { animated?: boolean }, ) { - if (Platform.OS !== 'ios') { - console.warn( - 'scrollResponderScrollToEnd is not supported on this platform' - ); - return; - } // Default to true const animated = (options && options.animated) !== false; UIManager.dispatchViewManagerCommand( diff --git a/Libraries/Components/ScrollView/ScrollView.js b/Libraries/Components/ScrollView/ScrollView.js index 04dfc3607a9..1c7b704c805 100644 --- a/Libraries/Components/ScrollView/ScrollView.js +++ b/Libraries/Components/ScrollView/ScrollView.js @@ -410,29 +410,15 @@ const ScrollView = React.createClass({ * Use `scrollToEnd({animated: true})` for smooth animated scrolling, * `scrollToEnd({animated: false})` for immediate scrolling. * If no options are passed, `animated` defaults to true. - * - * See `ScrollView#scrollToEnd`. */ scrollToEnd: function( options?: { animated?: boolean }, ) { // Default to true const animated = (options && options.animated) !== false; - if (Platform.OS === 'ios') { - this.getScrollResponder().scrollResponderScrollToEnd({ - animated: animated, - }); - } else if (Platform.OS === 'android') { - // On Android scrolling past the end of the ScrollView gets clipped - // - scrolls to the end. - if (this.props.horizontal) { - this.scrollTo({x: 10*1000*1000, animated: animated}); - } else { - this.scrollTo({y: 10*1000*1000, animated: animated}); - } - } else { - console.warn('scrollToEnd is not supported on this platform'); - } + this.getScrollResponder().scrollResponderScrollToEnd({ + animated: animated, + }); }, /** diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/recyclerview/RecyclerViewBackedScrollViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/recyclerview/RecyclerViewBackedScrollViewManager.java index b82c03f7473..ca4586d76a3 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/recyclerview/RecyclerViewBackedScrollViewManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/recyclerview/RecyclerViewBackedScrollViewManager.java @@ -80,6 +80,15 @@ public class RecyclerViewBackedScrollViewManager extends scrollView.scrollTo(data.mDestX, data.mDestY, data.mAnimated); } + @Override + public void scrollToEnd( + RecyclerViewBackedScrollView scrollView, + ReactScrollViewCommandHelper.ScrollToEndCommandData data) { + // Not implemented. + // RecyclerViewBackedScrollView is deprecated and will be removed. + // People should use a standard ScrollView or ListView instead. + } + @Override public @Nullable Map getExportedCustomDirectEventTypeConstants() { diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java index 2865a94c590..769a90738b5 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java @@ -117,6 +117,20 @@ public class ReactHorizontalScrollViewManager } } + @Override + public void scrollToEnd( + ReactHorizontalScrollView scrollView, + ReactScrollViewCommandHelper.ScrollToEndCommandData data) { + // ScrollView always has one child - the scrollable area + int right = + scrollView.getChildAt(0).getWidth() + scrollView.getPaddingRight(); + if (data.mAnimated) { + scrollView.smoothScrollTo(right, scrollView.getScrollY()); + } else { + scrollView.scrollTo(right, scrollView.getScrollY()); + } + } + /** * When set, fills the rest of the scrollview with a color to avoid setting a background and * creating unnecessary overdraw. diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewCommandHelper.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewCommandHelper.java index aa9560df071..af97a8bba8e 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewCommandHelper.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewCommandHelper.java @@ -25,9 +25,11 @@ import com.facebook.react.common.MapBuilder; public class ReactScrollViewCommandHelper { public static final int COMMAND_SCROLL_TO = 1; + public static final int COMMAND_SCROLL_TO_END = 2; public interface ScrollCommandHandler { void scrollTo(T scrollView, ScrollToCommandData data); + void scrollToEnd(T scrollView, ScrollToEndCommandData data); } public static class ScrollToCommandData { @@ -42,10 +44,21 @@ public class ReactScrollViewCommandHelper { } } + public static class ScrollToEndCommandData { + + public final boolean mAnimated; + + ScrollToEndCommandData(boolean animated) { + mAnimated = animated; + } + } + public static Map getCommandsMap() { return MapBuilder.of( "scrollTo", - COMMAND_SCROLL_TO); + COMMAND_SCROLL_TO, + "scrollToEnd", + COMMAND_SCROLL_TO_END); } public static void receiveCommand( @@ -64,6 +77,11 @@ public class ReactScrollViewCommandHelper { viewManager.scrollTo(scrollView, new ScrollToCommandData(destX, destY, animated)); return; } + case COMMAND_SCROLL_TO_END: { + boolean animated = args.getBoolean(0); + viewManager.scrollToEnd(scrollView, new ScrollToEndCommandData(animated)); + return; + } default: throw new IllegalArgumentException(String.format( "Unsupported command %d received by %s.", diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java index ba9173bccd4..76cc41ac9bb 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java @@ -131,6 +131,20 @@ public class ReactScrollViewManager } } + @Override + public void scrollToEnd( + ReactScrollView scrollView, + ReactScrollViewCommandHelper.ScrollToEndCommandData data) { + // ScrollView always has one child - the scrollable area + int bottom = + scrollView.getChildAt(0).getHeight() + scrollView.getPaddingBottom(); + if (data.mAnimated) { + scrollView.smoothScrollTo(scrollView.getScrollX(), bottom); + } else { + scrollView.scrollTo(scrollView.getScrollX(), bottom); + } + } + @Override public @Nullable Map getExportedCustomDirectEventTypeConstants() { return createExportedCustomDirectEventTypeConstants();