123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 |
- /**
- * Copyright (c) Facebook, Inc. and its affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- * @flow
- */
- 'use strict';
- const Platform = require('../../Utilities/Platform');
- const React = require('react');
- import type {ColorValue} from '../../StyleSheet/StyleSheetTypes';
- import type {ViewProps} from '../View/ViewPropTypes';
- import AndroidSwipeRefreshLayoutNativeComponent, {
- Commands as AndroidSwipeRefreshLayoutCommands,
- } from './AndroidSwipeRefreshLayoutNativeComponent';
- import PullToRefreshViewNativeComponent, {
- Commands as PullToRefreshCommands,
- } from './PullToRefreshViewNativeComponent';
- let RefreshLayoutConsts: any;
- if (Platform.OS === 'android') {
- const AndroidSwipeRefreshLayout = require('../../ReactNative/UIManager').getViewManagerConfig(
- 'AndroidSwipeRefreshLayout',
- );
- RefreshLayoutConsts = AndroidSwipeRefreshLayout
- ? AndroidSwipeRefreshLayout.Constants
- : {SIZE: {}};
- } else {
- RefreshLayoutConsts = {SIZE: {}};
- }
- type IOSProps = $ReadOnly<{|
- /**
- * The color of the refresh indicator.
- */
- tintColor?: ?ColorValue,
- /**
- * Title color.
- */
- titleColor?: ?ColorValue,
- /**
- * The title displayed under the refresh indicator.
- */
- title?: ?string,
- |}>;
- type AndroidProps = $ReadOnly<{|
- /**
- * Whether the pull to refresh functionality is enabled.
- */
- enabled?: ?boolean,
- /**
- * The colors (at least one) that will be used to draw the refresh indicator.
- */
- colors?: ?$ReadOnlyArray<ColorValue>,
- /**
- * The background color of the refresh indicator.
- */
- progressBackgroundColor?: ?ColorValue,
- /**
- * Size of the refresh indicator, see RefreshControl.SIZE.
- */
- size?: ?(
- | typeof RefreshLayoutConsts.SIZE.DEFAULT
- | typeof RefreshLayoutConsts.SIZE.LARGE
- ),
- /**
- * Progress view top offset
- */
- progressViewOffset?: ?number,
- |}>;
- export type RefreshControlProps = $ReadOnly<{|
- ...ViewProps,
- ...IOSProps,
- ...AndroidProps,
- /**
- * Called when the view starts refreshing.
- */
- onRefresh?: ?() => void | Promise<void>,
- /**
- * Whether the view should be indicating an active refresh.
- */
- refreshing: boolean,
- |}>;
- /**
- * This component is used inside a ScrollView or ListView to add pull to refresh
- * functionality. When the ScrollView is at `scrollY: 0`, swiping down
- * triggers an `onRefresh` event.
- *
- * ### Usage example
- *
- * ``` js
- * class RefreshableList extends Component {
- * constructor(props) {
- * super(props);
- * this.state = {
- * refreshing: false,
- * };
- * }
- *
- * _onRefresh() {
- * this.setState({refreshing: true});
- * fetchData().then(() => {
- * this.setState({refreshing: false});
- * });
- * }
- *
- * render() {
- * return (
- * <ListView
- * refreshControl={
- * <RefreshControl
- * refreshing={this.state.refreshing}
- * onRefresh={this._onRefresh.bind(this)}
- * />
- * }
- * ...
- * >
- * ...
- * </ListView>
- * );
- * }
- * ...
- * }
- * ```
- *
- * __Note:__ `refreshing` is a controlled prop, this is why it needs to be set to true
- * in the `onRefresh` function otherwise the refresh indicator will stop immediately.
- */
- class RefreshControl extends React.Component<RefreshControlProps> {
- static SIZE: any = RefreshLayoutConsts.SIZE;
- _nativeRef: ?React.ElementRef<
- | typeof PullToRefreshViewNativeComponent
- | typeof AndroidSwipeRefreshLayoutNativeComponent,
- >;
- _lastNativeRefreshing = false;
- componentDidMount() {
- this._lastNativeRefreshing = this.props.refreshing;
- }
- componentDidUpdate(prevProps: RefreshControlProps) {
- // RefreshControl is a controlled component so if the native refreshing
- // value doesn't match the current js refreshing prop update it to
- // the js value.
- if (this.props.refreshing !== prevProps.refreshing) {
- this._lastNativeRefreshing = this.props.refreshing;
- } else if (
- this.props.refreshing !== this._lastNativeRefreshing &&
- this._nativeRef
- ) {
- if (Platform.OS === 'android') {
- AndroidSwipeRefreshLayoutCommands.setNativeRefreshing(
- this._nativeRef,
- this.props.refreshing,
- );
- } else {
- PullToRefreshCommands.setNativeRefreshing(
- this._nativeRef,
- this.props.refreshing,
- );
- }
- this._lastNativeRefreshing = this.props.refreshing;
- }
- }
- render(): React.Node {
- if (Platform.OS === 'ios') {
- const {
- enabled,
- colors,
- progressBackgroundColor,
- size,
- progressViewOffset,
- ...props
- } = this.props;
- return (
- <PullToRefreshViewNativeComponent
- {...props}
- ref={this._setNativeRef}
- onRefresh={this._onRefresh}
- />
- );
- } else {
- const {tintColor, titleColor, title, ...props} = this.props;
- return (
- <AndroidSwipeRefreshLayoutNativeComponent
- {...props}
- ref={this._setNativeRef}
- onRefresh={this._onRefresh}
- />
- );
- }
- }
- _onRefresh = () => {
- this._lastNativeRefreshing = true;
- this.props.onRefresh && this.props.onRefresh();
- // The native component will start refreshing so force an update to
- // make sure it stays in sync with the js component.
- this.forceUpdate();
- };
- _setNativeRef = (
- ref: ?React.ElementRef<
- | typeof PullToRefreshViewNativeComponent
- | typeof AndroidSwipeRefreshLayoutNativeComponent,
- >,
- ) => {
- this._nativeRef = ref;
- };
- }
- module.exports = RefreshControl;
|