feat(onScroll): Add `onScroll` callback for iOS & Android (#516)

* Add `onScroll` callback for iOS & Android

This code was mostly extracted from https://github.com/react-native-community/react-native-webview/pull/202

I tried and tried to make it work with `Animated.event`'s `useNativeDriver`, but I was unsuccessful 😢 that'll have to be done later once I understand better how Animated's native stuff is hooked up.

* fix crash for missing onScroll
This commit is contained in:
Jared Forsyth 2019-05-16 18:27:16 -04:00 committed by Thibault Malbranche
parent 409b9ae620
commit e4c8dab2ae
5 changed files with 59 additions and 0 deletions

View File

@ -31,6 +31,9 @@ import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.FrameLayout;
import com.facebook.react.views.scroll.ScrollEvent;
import com.facebook.react.views.scroll.ScrollEventType;
import com.facebook.react.views.scroll.OnScrollDispatchHelper;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.LifecycleEventListener;
import com.facebook.react.bridge.ReactContext;
@ -446,6 +449,7 @@ public class RNCWebViewManager extends SimpleViewManager<WebView> {
}
export.put(TopLoadingProgressEvent.EVENT_NAME, MapBuilder.of("registrationName", "onLoadingProgress"));
export.put(TopShouldStartLoadWithRequestEvent.EVENT_NAME, MapBuilder.of("registrationName", "onShouldStartLoadWithRequest"));
export.put(ScrollEventType.SCROLL.getJSEventName(), MapBuilder.of("registrationName", "onScroll"));
return export;
}
@ -780,6 +784,7 @@ public class RNCWebViewManager extends SimpleViewManager<WebView> {
protected @Nullable
RNCWebViewClient mRNCWebViewClient;
protected boolean sendContentSizeChangeEvents = false;
private final OnScrollDispatchHelper mOnScrollDispatchHelper = new OnScrollDispatchHelper();
/**
* WebView must be created with an context of the current activity
@ -886,6 +891,26 @@ public class RNCWebViewManager extends SimpleViewManager<WebView> {
dispatchEvent(this, new TopMessageEvent(this.getId(), message));
}
protected void onScrollChanged(int x, int y, int oldX, int oldY) {
super.onScrollChanged(x, y, oldX, oldY);
if (mOnScrollDispatchHelper.onScrollChanged(x, y)) {
ScrollEvent event = ScrollEvent.obtain(
this.getId(),
ScrollEventType.SCROLL,
x,
y,
mOnScrollDispatchHelper.getXFlingVelocity(),
mOnScrollDispatchHelper.getYFlingVelocity(),
this.computeHorizontalScrollRange(),
this.computeVerticalScrollRange(),
this.getWidth(),
this.getHeight());
dispatchEvent(this, event);
}
}
protected void cleanupCallbacksAndDestroy() {
setWebViewClient(null);
destroy();

View File

@ -34,6 +34,7 @@ static NSURLCredential* clientAuthenticationCredential;
@property (nonatomic, copy) RCTDirectEventBlock onLoadingProgress;
@property (nonatomic, copy) RCTDirectEventBlock onShouldStartLoadWithRequest;
@property (nonatomic, copy) RCTDirectEventBlock onMessage;
@property (nonatomic, copy) RCTDirectEventBlock onScroll;
@property (nonatomic, copy) WKWebView *webView;
@end
@ -509,6 +510,30 @@ static NSURLCredential* clientAuthenticationCredential;
if (!_scrollEnabled) {
scrollView.bounds = _webView.bounds;
}
else if (_onScroll != nil) {
NSDictionary *event = @{
@"contentOffset": @{
@"x": @(scrollView.contentOffset.x),
@"y": @(scrollView.contentOffset.y)
},
@"contentInset": @{
@"top": @(scrollView.contentInset.top),
@"left": @(scrollView.contentInset.left),
@"bottom": @(scrollView.contentInset.bottom),
@"right": @(scrollView.contentInset.right)
},
@"contentSize": @{
@"width": @(scrollView.contentSize.width),
@"height": @(scrollView.contentSize.height)
},
@"layoutMeasurement": @{
@"width": @(scrollView.frame.size.width),
@"height": @(scrollView.frame.size.height)
},
@"zoomScale": @(scrollView.zoomScale ?: 1),
};
_onScroll(event);
}
}
- (void)setDirectionalLockEnabled:(BOOL)directionalLockEnabled

View File

@ -56,6 +56,7 @@ RCT_EXPORT_VIEW_PROPERTY(allowsLinkPreview, BOOL)
*/
RCT_EXPORT_VIEW_PROPERTY(messagingEnabled, BOOL)
RCT_EXPORT_VIEW_PROPERTY(onMessage, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onScroll, RCTDirectEventBlock)
RCT_EXPORT_METHOD(postMessage:(nonnull NSNumber *)reactTag message:(NSString *)message)
{

View File

@ -382,6 +382,7 @@ class WebView extends React.Component<IOSWebViewProps, State> {
onLoadingProgress={this.onLoadingProgress}
onLoadingStart={this.onLoadingStart}
onMessage={this.onMessage}
onScroll={this.props.onScroll}
onShouldStartLoadWithRequest={onShouldStartLoadWithRequest}
ref={this.webViewRef}
scalesPageToFit={scalesPageToFit}

View File

@ -7,6 +7,7 @@ import {
NativeMethodsMixin,
Constructor,
UIManagerStatic,
NativeScrollEvent,
} from 'react-native';
export interface WebViewCommands {
@ -213,6 +214,7 @@ export interface CommonNativeWebViewProps extends ViewProps {
injectedJavaScript?: string;
mediaPlaybackRequiresUserAction?: boolean;
messagingEnabled: boolean;
onScroll?: (event: NativeScrollEvent) => void;
onLoadingError: (event: WebViewErrorEvent) => void;
onLoadingFinish: (event: WebViewNavigationEvent) => void;
onLoadingProgress: (event: WebViewProgressEvent) => void;
@ -542,6 +544,11 @@ export interface WebViewSharedProps extends ViewProps {
*/
renderLoading?: () => ReactElement;
/**
* Function that is invoked when the `WebView` scrolls.
*/
onScroll?: (event: NativeScrollEvent) => void;
/**
* Function that is invoked when the `WebView` has finished loading.
*/