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

react-native-viewpager-list

v1.0.5

Published

viewpager2 for react-native

Downloads

12

Readme

安装

yarn add react-native-viewpager-list

(当前仅支持 android,安装完成后无需任何配置)

使用

import {ViewPager, ViewPagerList} from 'react-native-viewpager-list';


<ViewPager {...props}>
    <View />
    <View />
    <View />
</ViewPager>


<ViewPagerList {...props}/>

支持 ViewPagerViewPagerList 两种方式;前者较为方便,有多少个子 view 就有多少个 page;后者主要使用在有很多 page 的情况,比如类似抖音那样,无限下滑。

通用 props

<ViewPagerList
   disableSwipe={false}  //禁用滑动(仍可通过API滑动,但用户不可操作)
   disableWave={false} //是否禁用 滑动到边缘时继续拖拽的水波纹效果
   currentIndex={0}  //当前显示 page
   horizontal={false}  //是否为横向(默认为纵向)
   loop={false}      //是否循环展示
   offscreenPageLimit={0}  //离屏(预加载) page 个数, 
                           //即当前 page 的前后提前渲染的 page 个数
                           //对于 ViewPagerList 创建后不可不可修改, ViewPager 无此限制

   autoplay={false}  //是否自动播放
   autoplayTimeout={2500}  //自动播放时间间隔
   autoplayDirection={false} //自动播放是否仅沿着一个方向(即播放到结尾后停止)

   transformer="|card|zoomOut|depth"   //页面过渡效果,默认为空
   scale={0.85}     //过渡效果: 渐隐的最小缩放比例
   alpha={0.75}     //过渡效果: 渐隐的最小透明度 (depth效果不支持)
   padding={int}  // card 过渡效果: 一屏显示多个, padding 设置 主 page 两端间距
   maring={int}   // margin 设置两端(前后) page 的显示尺寸
   
   //当前显示 page 的背景组件
   //利用该属性可实现类似抖音效果, 背景组件可设置为一个 Video 组件
   //这也可避免滑动过程中更新 子view 导致视频组件不断的销毁与重建
   //当然也可在其他性能敏感的场景使用
   //该参数仅在首次有效, 创建后更改无效
   getBackground={ReactComponent|Function} 

    // 下拉刷新, 与 ScrollView 使用方式基本一致, 仅支持垂直视图
    refreshControl={
        <RefreshControl
            tintColor=""
            onRefresh={this._onRefresh}
        />
    }

    //page状态发生改变,在滑动开始/滑动松开/滑动完成等节点触发
    onPageScrollStateChanged={({state}) => {}}  
    //滑动过程的回调
    onPageScroll={({position, offset, offsetPixels}) => {}}
    //页面切换后触发(此时是刚松开手指, 即将惯性滑动到 position 页面)
    onPageSelected={({position}) => {}}
    //页面切换完成后触发
    onPageChanged={({position}) => {}}
/>

refreshControl 说明

与 ScrollView 不同之处在于,不需要设置 refreshing 属性,若不使用 RN 自带的 refreshControl 刷新器,需保证自行使用的刷新器至少要支持 refreshingenabledonRefresh 三个属性(若不支持的话,可考虑套一层 wrapper)。回调函数会有一个函数参数,完成数据更新后,只需要调用一下即可,使用方法如下

_onRefresh = (resolve) => {
    setTimeout(() => {
        resolve()
    }, 3000);
}

通用 API

以下 api 属于共用接口,ViewPagerViewPagerList 都支持

getCount

// 获取当前页面数量
int count = this.refs.pager.getCount();

setCurrentIndex

// 滑动到指定页面, smooth=true, 使用过渡效果, 反之不使用
this.refs.pager.setCurrentIndex(index, smooth);

getCurrentIndex

// 获取当前正在显示的 page index
int index = this.refs.pager.getCurrentIndex()

disable

// 禁用或启用当前 viewpager, 禁用后仍可通过 api 切换页面
// 但用户不可拖拽操作了, 与直接修改 props.disableSwipe 效果相同
// 不过性能更好一点
this.refs.pager.disable(disabled)

beginFakeDrag / fakeDragBy / endFakeDrag

// 模拟手势, 暂时没想到使用场景, 但 viewpager2 提供了, 索性也暴露给 js
// 需注意: beginFakeDrag 和 endFakeDrag 必须成对出现, 否则会闪退
const pager = this.refs.pager;
pager.beginFakeDrag();
pager.fakeDragBy(30);
pager.endFakeDrag();

ViewPagerList 专用

ViewPagerList 的 page 不支持直接使用子 view,而是使用类似 FlatList 的方式,由 数据 和 渲染函数动态创建 page,对于数据较多的情况,可大幅提升性能。

<ViewPagerList
    initData={Array}  //绑定数据
    renderItem={Function}  //page渲染函数

    ref="pager"
/>

renderItem

// 创建第 index 个 page 的 view
// item 为 initData 中下标为 index 的数据
renderItem = (item, index) => {
    return <View>{item.balbla}</View>
}

修改数据可以直接设置 props.initData,但 ViewPagerList 的设计初衷是出于性能考虑,所以不建议直接设置,而是根据实际情况使用以下 API 来操作数据

const pager = this.refs.pager;

// 更新列表数据
// 以下四个函数可额外指定一个 selected 参数
// 在更新完数据后, 将 viewpager 定位到指定页面
// 可缺省, 即不改变当前的 selected page
//---------------------------------------------------

// 追加一批数据
pager.push(Array, selected)

// 在 index 位置插入 data (index 本身也会被替换)
// index 可缺省, 默认为 0, 即插入到开头
pager.insert(Array, index, selected)

// 从 index 位置开始移除 length 个(含 index)
// length 可缺省, 默认为 1
pager.remove(Array, index, selected)

// 一次性更新所有数据, 可放心使用, 会自动按需更新
pager.update(Array, selected)


// 获取/更新 指定 page 的数据
//---------------------------------------------------

// 获取所有 page 数据
Array list = pager.getItem();

// 获取下标 index 的 page 数据
Object item = pager.getItem(index);

// 更新指定 page 的数据
pager.updateItem(index, data);

// 强制更新指定 page 的视图(即使其 data 未变动), 会触发 renderItem
pager.renderItem(index);


// 针对当前正在显示 page 的操作
//---------------------------------------------------

// 获取当前 page 的数据
// 等价于 pager.getItem(this.getCurrentIndex())
Object item = pager.getCurrentItem();

// 更新当前 page 的数据
// 等价于 pager.updateItem(this.getCurrentIndex(), data)
pager.updateCurrentItem(data);

API 使用注意事项

// getItem / getCurrentItem 获取到的数据为原始数据, 并非拷贝的数据
const item = this.refs.pager.getCurrentItem();

// 不会触发 renderItem 重新渲染 page, 但在 page 回收后再次重新创建时,
// 会触发 renderItem 重新渲染, 回收时机由 offscreenPageLimit 决定
item.foo = "foo";

// 同上, 此时仍不会触发, 相当于设置了 item=item, 无法触发 RN 的 props diff 
item.foo = "foo";
this.refs.pager.updateItem(
    this.refs.pager.getCurrentIndex(),
    item
);

// 以下方式可立即更新
this.refs.pager.updateItem(
    this.refs.pager.getCurrentIndex(),
    {...item, foo:"foo"}
);

// 这样设计的原因是为了应对以下场景
// 1. 已通过其他方式更新完了 page, 仅需改变数据以便下次正确渲染
// 2. 没更新 page, 通过改变数据触发 renderItem 立即重新渲染

额外说明

Page 内部也有可能也有 touchmove 相关的组件, 所以 viewpager 默认并未阻止该类型事件,但这会给以下使用场景造成困扰

import React from 'react';
import {View, TouchableOpacity} from 'react-native';
import {ViewPager} from 'react-native-viewpager-list';

class App extends React.Component {
  render(){
    return <ViewPager>
        <View>
            <TouchableOpacity onPress={() => {}}/>
        </View>
    </ViewPager>
  }  
}

按住 TouchableOpacity 拖拽切换 ViewPager 到下一个页面,此时会触发 onPress 事件,这并不符合期望;实际所需要的是点击 TouchableOpacity 且不发生页面切换,才响应 onPress 事件,可通过以下方式解决。

class App extends React.Component {
  
  _pageState = 0;
  _onPageStateChange = ({state}) => {
      this._pageState = state;
  }  

  // _pageState !== 0 意味着发生了拖拽, 此时阻止子视图响应 touch 事件
  _onMoveShouldSetResponderCapture = () => {
      return this._pageState !== 0;
  }
 
  render(){
    return <ViewPager
        onPageScrollStateChanged={this._onPageStateChange}
        onMoveShouldSetResponderCapture={this._onMoveShouldSetResponderCapture}
    >
        <View>
            <TouchableOpacity onPress={() => {}}/>
        </View>
    </ViewPager>
  }  
}