npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@sdcx/pull-to-refresh

v0.23.0

Published

A react-native PullToRefresh component.

Downloads

6,730

Readme

PullToRefresh

PullToRefresh 是一个 React Native 原生 UI 组件。

React Native 内置的下拉刷新组件比较简陋,且 iOS 和 Android 平台的表现很不一致。幸运的是,它提供了一个 refreshControl 属性,可以用来自定义下拉刷新组件。

PullToRefresh 提供了自定义下拉刷新的能力。

特点

  • 支持自定义下拉刷新
  • 支持全局设置下拉刷新的样式
  • 额外支持 WebViewScrollViewNestedScrollView
  • 支持上拉加载更多

| | | | --------------------------------------------------- | ------------------------------------------------ | | | |

Installation

yarn add @sdcx/pull-to-refresh
# &
pod install

Usage

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,你需要合理使用 onStateChangedonOffsetChanged 这两个回调来实现你想要的下拉刷新效果。

记得将 props 中的 onRefreshrefreshing 这两个属性透传给 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)

该设置同时对 PullToRefreshRefreshControl 生效。

设置局部特定下拉刷新样式

如果你的某些页面不想使用全局默认的下拉刷新样式,那么你可以设置 PullToRefreshheader 属性。此时,将 onRefreshrefreshing 属性传递给 header

import { PullToRefresh } from '@sdcx/pull-to-refresh'

function App() {
  const [refreshing, setRefreshing] = useState(false)

  return (
    <PullToRefresh
      header={
        <LocalPullToRefreshHeader
          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 LocalRefreshControl(props: RefreshControlProps) {
  if (Platform.OS === 'android') {
    return <PullToRefresh header={<LocalPullToRefreshHeader {...props} />} />
  }
  return <LocalPullToRefreshHeader {...props} />
}

然后使用自定义的 LocalRefreshControl 即可:

function App() {
  const [refreshing, setRefreshing] = useState(false)

  return (
    <FlatList
      nestedScrollEnabled
      refreshControl={
        <LocalRefreshControl
          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 更倾向于上拉加载更多,那么你可以使用 PullToRefreshonLoadMore 属性。

上拉加载有两种模式,一种是手动模式,像下拉刷新那样,释放后加载更多;另一种是自动模式,上拉一定距离后自动加载更多。

你需要根据 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)

当然,也可以通过 PullToRefreshfooter 属性来为特定页面设置特定的上拉加载更多样式。

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()}
    />
  )
}

嘿嘿,下拉刷新秒变上拉加载更多。