react-native-mjrefresh-xys
Version:
>React-Native-MJRefresh可完成使用React Native对IOS进行自定义下拉刷新设置 > >onPulling参数为{nativeEvent:percent},结合lottie-react-native可以获得绝佳的下拉刷新效果 > >自定义详情可见Example:[HuaWeiRefreshControl.js](https://github.com/react-native-studio/react-native-MJRefresh/blob/master/Example/H
297 lines (280 loc) • 12.6 kB
JavaScript
import React,{Component} from 'react';
import {
requireNativeComponent,
ScrollView,
View,
Platform,
StyleSheet,
UIManager,
findNodeHandle
} from 'react-native';
const warning = require('fbjs/lib/warning');
const flattenStyle = require('react-native/Libraries/StyleSheet/flattenStyle');
const invariant = require('fbjs/lib/invariant');
const ScrollViewStickyHeader = require('react-native/Libraries/Components/ScrollView/ScrollViewStickyHeader');
const processDecelerationRate = require('react-native/Libraries/Components/ScrollView/processDecelerationRate');
const RCTMJScrollView = requireNativeComponent('RCTMJScrollView', MJScrollView, {
nativeOnly: {
onMomentumScrollBegin: true,
onMomentumScrollEnd : true,
onScrollBeginDrag: true,
onScrollEndDrag: true,
}
})
const RCTMJScrollContentView = requireNativeComponent('RCTMJScrollContentView', View)
class MJScrollView extends ScrollView {
/**
* Scrolls to a given x, y offset, either immediately or with a smooth animation.
*
* Example:
*
* `scrollTo({x: 0, y: 0, animated: true})`
*
* Note: The weird function signature is due to the fact that, for historical reasons,
* the function also accepts separate arguments as an alternative to the options object.
* This is deprecated due to ambiguity (y before x), and SHOULD NOT BE USED.
*/
scrollTo(
options?: {x?: number, y?: number, animated?: boolean} | number,
deprecatedX?: number,
deprecatedAnimated?: boolean,
) {
let x, y, animated;
if (typeof options === 'number') {
console.warn(
'`scrollTo(y, x, animated)` is deprecated. Use `scrollTo({x: 5, y: 5, ' +
'animated: true})` instead.',
);
y = options;
x = deprecatedX;
animated = deprecatedAnimated;
} else if (options) {
y = options.y;
x = options.x;
animated = options.animated;
}
UIManager.dispatchViewManagerCommand(
findNodeHandle(this._scrollViewRef),
UIManager.getViewManagerConfig('RCTMJScrollView').Commands.scrollTo,
[x || 0, y || 0, animated !== false],
);
}
/**
* If this is a vertical ScrollView scrolls to the bottom.
* If this is a horizontal ScrollView scrolls to the right.
*
* Use `scrollToEnd({animated: true})` for smooth animated scrolling,
* `scrollToEnd({animated: false})` for immediate scrolling.
* If no options are passed, `animated` defaults to true.
*/
scrollToEnd(options?: ?{animated?: boolean}) {
// Default to true
const animated = (options && options.animated) !== false;
UIManager.dispatchViewManagerCommand(
findNodeHandle(this._scrollViewRef),
UIManager.getViewManagerConfig('RCTMJScrollView').Commands.scrollToEnd,
[animated],
);
}
/**
* Displays the scroll indicators momentarily.
*
* @platform ios
*/
flashScrollIndicators() {
UIManager.dispatchViewManagerCommand(
findNodeHandle(this._scrollViewRef),
UIManager.getViewManagerConfig('RCTMJScrollView').Commands.flashScrollIndicators,
[],
);
}
render() {
let ScrollViewClass = RCTMJScrollView;
let ScrollContentContainerViewClass = RCTMJScrollContentView;
warning(
!this.props.snapToInterval || !this.props.pagingEnabled,
'snapToInterval is currently ignored when pagingEnabled is true.'
);
invariant(
ScrollViewClass !== undefined,
'ScrollViewClass must not be undefined'
);
invariant(
ScrollContentContainerViewClass !== undefined,
'ScrollContentContainerViewClass must not be undefined'
);
const contentContainerStyle = [
this.props.horizontal && styles.contentContainerHorizontal,
this.props.contentContainerStyle,
];
let style, childLayoutProps;
if (__DEV__ && this.props.style) {
style = flattenStyle(this.props.style);
childLayoutProps = ['alignItems', 'justifyContent']
.filter((prop) => style && style[prop] !== undefined);
invariant(
childLayoutProps.length === 0,
'ScrollView child layout (' + JSON.stringify(childLayoutProps) +
') must be applied through the contentContainerStyle prop.'
);
}
let contentSizeChangeProps = {};
if (this.props.onContentSizeChange) {
contentSizeChangeProps = {
onLayout: this._handleContentOnLayout,
};
}
const {stickyHeaderIndices} = this.props;
const hasStickyHeaders = stickyHeaderIndices && stickyHeaderIndices.length > 0;
/* $FlowFixMe(>=0.53.0 site=react_native_fb,react_native_oss) This comment
* suppresses an error when upgrading Flow's support for React. To see the
* error delete this comment and run Flow. */
const childArray = hasStickyHeaders && React.Children.toArray(this.props.children);
const children = hasStickyHeaders ?
/* $FlowFixMe(>=0.53.0 site=react_native_fb,react_native_oss) This
* comment suppresses an error when upgrading Flow's support for React.
* To see the error delete this comment and run Flow. */
childArray.map((child, index) => {
/* $FlowFixMe(>=0.53.0 site=react_native_fb,react_native_oss) This
* comment suppresses an error when upgrading Flow's support for React.
* To see the error delete this comment and run Flow. */
const indexOfIndex = child ? stickyHeaderIndices.indexOf(index) : -1;
if (indexOfIndex > -1) {
const key = child.key;
/* $FlowFixMe(>=0.53.0 site=react_native_fb,react_native_oss) This
* comment suppresses an error when upgrading Flow's support for
* React. To see the error delete this comment and run Flow. */
const nextIndex = stickyHeaderIndices[indexOfIndex + 1];
const StickyHeaderComponent =
this.props.StickyHeaderComponent || ScrollViewStickyHeader;
return (
<StickyHeaderComponent
key={key}
ref={(ref) => this._setStickyHeaderRef(key, ref)}
nextHeaderLayoutY={
/* $FlowFixMe(>=0.53.0 site=react_native_fb,react_native_oss)
* This comment suppresses an error when upgrading Flow's
* support for React. To see the error delete this comment and
* run Flow. */
this._headerLayoutYs.get(this._getKeyForIndex(nextIndex, childArray))
}
onLayout={(event) => this._onStickyHeaderLayout(index, event, key)}
scrollAnimatedValue={this._scrollAnimatedValue}>
{child}
</StickyHeaderComponent>
);
} else {
return child;
}
}) :
/* $FlowFixMe(>=0.53.0 site=react_native_fb,react_native_oss) This
* comment suppresses an error when upgrading Flow's support for React.
* To see the error delete this comment and run Flow. */
this.props.children;
const contentContainer =
<ScrollContentContainerViewClass
{...contentSizeChangeProps}
/* $FlowFixMe(>=0.53.0 site=react_native_fb,react_native_oss) This
* comment suppresses an error when upgrading Flow's support for React.
* To see the error delete this comment and run Flow. */
ref={this._setInnerViewRef}
style={contentContainerStyle}
removeClippedSubviews={
// Subview clipping causes issues with sticky headers on Android and
// would be hard to fix properly in a performant way.
Platform.OS === 'android' && hasStickyHeaders ?
false :
this.props.removeClippedSubviews
}
collapsable={false}>
{children}
</ScrollContentContainerViewClass>;
const alwaysBounceHorizontal =
this.props.alwaysBounceHorizontal !== undefined ?
this.props.alwaysBounceHorizontal :
this.props.horizontal;
const alwaysBounceVertical =
this.props.alwaysBounceVertical !== undefined ?
this.props.alwaysBounceVertical :
!this.props.horizontal;
const DEPRECATED_sendUpdatedChildFrames =
!!this.props.DEPRECATED_sendUpdatedChildFrames;
const baseStyle = this.props.horizontal ? styles.baseHorizontal : styles.baseVertical;
const props = {
...this.props,
alwaysBounceHorizontal,
alwaysBounceVertical,
style: [baseStyle, this.props.style],
// Override the onContentSizeChange from props, since this event can
// bubble up from TextInputs
onContentSizeChange: null,
onMomentumScrollBegin: this.scrollResponderHandleMomentumScrollBegin,
onMomentumScrollEnd: this.scrollResponderHandleMomentumScrollEnd,
onResponderGrant: this.scrollResponderHandleResponderGrant,
onResponderReject: this.scrollResponderHandleResponderReject,
onResponderRelease: this.scrollResponderHandleResponderRelease,
/* $FlowFixMe(>=0.53.0 site=react_native_fb,react_native_oss) This
* comment suppresses an error when upgrading Flow's support for React.
* To see the error delete this comment and run Flow. */
onResponderTerminate: this.scrollResponderHandleTerminate,
onResponderTerminationRequest: this.scrollResponderHandleTerminationRequest,
onScroll: this._handleScroll,
onScrollBeginDrag: this.scrollResponderHandleScrollBeginDrag,
onScrollEndDrag: this.scrollResponderHandleScrollEndDrag,
onScrollShouldSetResponder: this.scrollResponderHandleScrollShouldSetResponder,
onStartShouldSetResponder: this.scrollResponderHandleStartShouldSetResponder,
onStartShouldSetResponderCapture: this.scrollResponderHandleStartShouldSetResponderCapture,
onTouchEnd: this.scrollResponderHandleTouchEnd,
onTouchMove: this.scrollResponderHandleTouchMove,
onTouchStart: this.scrollResponderHandleTouchStart,
scrollEventThrottle: hasStickyHeaders ? 1 : this.props.scrollEventThrottle,
sendMomentumEvents: (this.props.onMomentumScrollBegin || this.props.onMomentumScrollEnd) ?
true : false,
DEPRECATED_sendUpdatedChildFrames,
};
const { decelerationRate } = this.props;
if (decelerationRate) {
props.decelerationRate = processDecelerationRate(decelerationRate);
}
const refreshControl = this.props.refreshControl;
if (refreshControl) {
// On iOS the RefreshControl is a child of the ScrollView.
// tvOS lacks native support for RefreshControl, so don't include it in that case
return (
/* $FlowFixMe(>=0.53.0 site=react_native_fb,react_native_oss) This
* comment suppresses an error when upgrading Flow's support for
* React. To see the error delete this comment and run Flow. */
<ScrollViewClass {...props} ref={this._setScrollViewRef}>
{Platform.isTVOS ? null : refreshControl}
{contentContainer}
</ScrollViewClass>
);
}
return (
/* $FlowFixMe(>=0.53.0 site=react_native_fb,react_native_oss) This
* comment suppresses an error when upgrading Flow's support for React.
* To see the error delete this comment and run Flow. */
<ScrollViewClass {...props} ref={this._setScrollViewRef}>
{contentContainer}
</ScrollViewClass>
);
}
}
const styles = StyleSheet.create({
baseVertical: {
flexGrow: 1,
flexShrink: 1,
flexDirection: 'column',
overflow: 'scroll',
},
baseHorizontal: {
flexGrow: 1,
flexShrink: 1,
flexDirection: 'row',
overflow: 'scroll',
},
contentContainerHorizontal: {
flexDirection: 'row',
},
});
module.exports = Platform.OS === 'ios' ? MJScrollView : ScrollView