@sdcx/pull-to-refresh
v0.27.0
Published
A react-native PullToRefresh component.
Maintainers
Readme
PullToRefresh
PullToRefresh 是一个 React Native 原生 UI 组件。
React Native 内置的下拉刷新组件比较简陋,且 iOS 和 Android 平台的表现很不一致。幸运的是,它提供了一个 refreshControl 属性,可以用来自定义下拉刷新组件。
PullToRefresh 提供了自定义下拉刷新的能力。
特点
- 支持自定义下拉刷新
- 支持全局设置下拉刷新的样式
- 额外支持
WebView、ScrollView、NestedScrollView - 支持上拉加载更多
| | | | --------------------------------------------------- | ------------------------------------------------ | | | |
Installation
yarn add @sdcx/pull-to-refresh
# &
pod installUsage
import { PullToRefresh } from '@sdcx/pull-to-refresh'
function App() {
const [refreshing, setRefreshing] = useState(false)
return (
<PullToRefresh
refreshing={refreshing}
onRefresh={() => {
setRefreshing(true)
setTimeout(() => {
setRefreshing(false)
}, 2000)
}}>
<FlatList
nestedScrollEnabled
data={Array.from({ length: 20 })}
renderItem={({ item, index }) => <Text>{index}</Text>}
keyExtractor={(item, index) => index.toString()}
/>
</PullToRefresh>
)
}或者
import { RefreshControl } from '@sdcx/pull-to-refresh'
function App() {
const [refreshing, setRefreshing] = useState(false)
return (
<FlatList
nestedScrollEnabled
refreshControl={
<RefreshControl
refreshing={refreshing}
onRefresh={() => {
setRefreshing(true)
setTimeout(() => {
setRefreshing(false)
}, 2000)
}}
/>
}
data={Array.from({ length: 20 })}
renderItem={({ item, index }) => <Text>{index}</Text>}
keyExtractor={(item, index) => index.toString()}
/>
)
}:exclamation: :exclamation: :exclamation: Android 是基于 NestedScrolling API 实现的。
:exclamation: :exclamation: :exclamation:
这两种使用方式在效果上并无不同。
此外,PullToRefresh 支持上拉加载更多,以及所有可滚动视图,譬如 WebView, ScrollView, NestedScrollView。
自定义下拉刷新
你一定不会想使用本库提供的默认下拉刷新,因为它太丑了。那么如何自定义下拉刷新呢?
首先,自定义一个 PullToRefreshHeader,你需要合理使用 onStateChanged 和 onOffsetChanged 这两个回调来实现你想要的下拉刷新效果。
记得将 props 中的 onRefresh 和 refreshing 这两个属性透传给 PullToRefreshHeader。
import {
PullToRefreshHeader,
PullToRefreshHeaderProps,
PullToRefreshOffsetChangedEvent,
PullToRefreshStateChangedEvent,
PullToRefreshState,
PullToRefreshStateIdle,
PullToRefreshStateRefreshing,
} from '@sdcx/pull-to-refresh'
export function CustomPullToRefreshHeader(props: PullToRefreshHeaderProps) {
const { onRefresh, refreshing } = props
const [text, setText] = useState('下拉刷新')
const onStateChanged = useCallback((event: PullToRefreshStateChangedEvent) => {
const state = event.nativeEvent.state
if (state === PullToRefreshStateIdle) {
setText('下拉刷新')
} else if (state === PullToRefreshStateRefreshing) {
setText('正在刷新...')
} else {
setText('松开刷新')
}
}, [])
const onOffsetChanged = useCallback((event: PullToRefreshOffsetChangedEvent) => {
console.log('refresh header offset', event.nativeEvent.offset)
}, [])
return (
<PullToRefreshHeader
style={styles.container}
onOffsetChanged={onOffsetChanged}
onStateChanged={onStateChanged}
onRefresh={onRefresh}
refreshing={refreshing}>
<Text style={styles.text}>{text}</Text>
</PullToRefreshHeader>
)
}设置全局默认下拉刷新样式
然后在应用启动时,设置全局默认下拉刷新。通常在你应用的入口文件处设置。
import { PullToRefresh } from '@sdcx/pull-to-refresh'
PullToRefresh.setDefaultHeader(CustomPullToRefreshHeader)该设置同时对 PullToRefresh 和 RefreshControl 生效。
设置局部特定下拉刷新样式
如果你的某些页面不想使用全局默认的下拉刷新样式,那么你可以设置 PullToRefresh 的 header 属性。此时,将 onRefresh 和 refreshing 属性传递给 header。
import { PullToRefresh } from '@sdcx/pull-to-refresh'
function App() {
const [refreshing, setRefreshing] = useState(false)
return (
<PullToRefresh
header={
<CustomPullToRefreshHeader
refreshing={refreshing}
onRefresh={() => {
setRefreshing(true)
setTimeout(() => {
setRefreshing(false)
}, 2000)
}}
/>
}>
<FlatList
nestedScrollEnabled
data={Array.from({ length: 20 })}
renderItem={({ item, index }) => <Text>{index}</Text>}
keyExtractor={(item, index) => index.toString()}
/>
</PullToRefresh>
)
}自定义 RefreshControl
当然,如果你不喜欢包裹 PullToRefresh,也可以自定义 RefreshControl
import { RefreshControlProps } from 'react-native'
import { PullToRefresh } from '@sdcx/pull-to-refresh'
export function CustomRefreshControl(props: RefreshControlProps) {
if (Platform.OS === 'android') {
return <PullToRefresh header={<CustomPullToRefreshHeader {...props} />} />
}
return <CustomPullToRefreshHeader {...props} />
}然后使用自定义的 CustomRefreshControl 即可:
function App() {
const [refreshing, setRefreshing] = useState(false)
return (
<FlatList
nestedScrollEnabled
refreshControl={
<CustomRefreshControl
refreshing={refreshing}
onRefresh={() => {
setRefreshing(true)
setTimeout(() => {
setRefreshing(false)
}, 2000)
}}
/>
}
data={Array.from({ length: 20 })}
renderItem={({ item, index }) => <Text>{index}</Text>}
keyExtractor={(item, index) => index.toString()}
/>
)
}上拉加载更多
加载更多有两种方式,一种方式是列表自身提供的触底加载更多,通过 onEndReached 属性实现。另一种方式是经典的上拉加载更多,通过 PullToRefresh 提供的 onLoadMore 属性实现。
大多数情况下,使用 onEndReached 或许是较好的选择。
如果你的 App 更倾向于上拉加载更多,那么你可以使用 PullToRefresh 的 onLoadMore 属性。
上拉加载有两种模式,一种是手动模式,像下拉刷新那样,释放后加载更多;另一种是自动模式,上拉一定距离后自动加载更多。
你需要根据 App 的设计偏好来选择合适的模式。
import { PullToRefresh } from '@sdcx/pull-to-refresh'
function App() {
const [loadingMore, setLoadingMore] = useState(false)
const [noMoreData, setNoMoreData] = useState(false)
const loadMore = () => {
setLoadingMore(true)
setTimeout(() => {
setLoadingMore(false)
}, 2000)
}
return (
<PullToRefresh loadingMore={loadingMore} onLoadMore={loadMore} noMoreData={noMoreData}>
<FlatList
nestedScrollEnabled
data={Array.from({ length: 20 })}
renderItem={({ item, index }) => <Text>{index}</Text>}
keyExtractor={(item, index) => index.toString()}
/>
</PullToRefresh>
)
}自定义上拉加载更多
自定义加载更多和自定义下拉刷新差不多,自定义一个组合组件,将 PullToRefreshFooter 包裹在里面,并透传相关属性即可,如下:
import {
PullToRefreshFooter,
PullToRefreshFooterProps,
PullToRefreshStateChangedEvent,
PullToRefreshStateIdle,
PullToRefreshStateRefreshing,
} from '@sdcx/pull-to-refresh'
export function CustomPullToRefreshFooter(props: PullToRefreshFooterProps) {
const { onRefresh, refreshing, noMoreData } = props
const [text, setText] = useState('上拉加载更多')
const onStateChanged = useCallback((event: PullToRefreshStateChangedEvent) => {
const state = event.nativeEvent.state
if (state === PullToRefreshStateIdle) {
setText('上拉加载更多')
} else if (state === PullToRefreshStateRefreshing) {
setText('正在加载更多...')
} else {
setText('松开加载更多')
}
}, [])
const onOffsetChanged = useCallback((event: PullToRefreshOffsetChangedEvent) => {
console.log('refresh footer offset', event.nativeEvent.offset)
}, [])
return (
<PullToRefreshFooter
style={styles.container}
manual={true /* 设置模式为手动 */}
onOffsetChanged={onOffsetChanged}
onStateChanged={onStateChanged}
onRefresh={onRefresh}
refreshing={refreshing}
noMoreData={noMoreData}>
<Text style={styles.text}>{noMoreData ? '没有更多数据了' : text}</Text>
</PullToRefreshFooter>
)
}然后在应用启动时,设置全局默认上拉加载更多。通常在你应用的入口文件处设置。
import { PullToRefresh } from '@sdcx/pull-to-refresh'
PullToRefresh.setDefaultFooter(CustomPullToRefreshFooter)当然,也可以通过 PullToRefresh 的 footer 属性来为特定页面设置特定的上拉加载更多样式。
import { PullToRefresh } from '@sdcx/pull-to-refresh'
function App() {
const [loadingMore, setLoadingMore] = useState(false)
return (
<PullToRefresh
footer={
<LocalPullToRefreshFooter
loadingMore={loadingMore}
onLoadMore={() => {
setLoadingMore(true)
setTimeout(() => {
setLoadingMore(false)
}, 2000)
}}
/>
}>
<FlatList
nestedScrollEnabled
data={Array.from({ length: 20 })}
renderItem={({ item, index }) => <Text>{index}</Text>}
keyExtractor={(item, index) => index.toString()}
/>
</PullToRefresh>
)
}自定义 RefreshControl 来实现加载更多
如果你钟爱 refreshControl, 那么也可以定义一个 LoadMoreRefreshControl
import { RefreshControlProps } from 'react-native'
import { PullToRefresh } from '@sdcx/pull-to-refresh'
export function LoadMoreRefreshControl(props: RefreshControlProps) {
if (Platform.OS === 'android') {
return <PullToRefresh footer={<CustomPullToRefreshFooter {...props} />} />
}
return <CustomPullToRefreshFooter {...props} />
}然后使用自定义的 LoadMoreRefreshControl 即可:
function App() {
const [loadingMore, setLoadingMore] = useState(false)
return (
<FlatList
nestedScrollEnabled
refreshControl={
<LoadMoreRefreshControl
refreshing={loadingMore}
onRefresh={() => {
setLoadingMore(true)
setTimeout(() => {
setLoadingMore(false)
}, 2000)
}}
/>
}
data={Array.from({ length: 20 })}
renderItem={({ item, index }) => <Text>{index}</Text>}
keyExtractor={(item, index) => index.toString()}
/>
)
}嘿嘿,下拉刷新秒变上拉加载更多。
