react-native ScrollView 实现上拉滑动全屏,下拉恢复原先大小

ScrollView 系列的都可以完成, 比如 FlatView 和 SectionList 都可以。

1 需求

需求
大概就是一个 scroll 组件向上滑动的时候可以完全展示出来。完全展示之后下滑再恢复缩小时的高度。

1.1需求分析

  • 缩小时不允许滚动,只有上滑动能唤醒动画,移至指定位置
  • 完全展示出来后可以内部进行滑动,当滑动到顶部,再向上滑(手势是从上至下)时,缩小整个 list

1.2 技术分析

  • list 采用 react-native 组件 ScrollView / FlatView / SectionList
  • 动画: react-native 自带一套动画系统,性能尚可
  • 手势: react-native 自带手势响应系统

1.3

前期知识准备不足的童靴,可以刷刷文档
手势响应系统
动画

2 Let’s do it!

2.1 列表页

    <ScrollView
        style={
            {
                position: 'absolute',
                top: 500,
                height: '展开后的高度'
            }
        }
    >
        // children
    <ScrollView>

ScrollView 没有什么好说的, 设置好样式,定位在页面中下方就可以了。
需要注意的是高度设置成展开后的高度,要么无法滚动。

2.2 动画

如果要使用动画的话,需要改变的是 ScrollView 的 top 值。
首先在 constructor 中定义 state, 为初始化的 top 值

    this._top = 500
    this.state = {
        topValue: new Animated.Value(this._top)
    }

之后来写两个动画开始的函数

    Animated.timing(
        this.state.fadeAnim,
            {
                toValue: 100,
                duration: 500,
            }
        ).start(() => {
            this.setState({listScroll: false}) // 开启 or 关闭 ScrollView 滚动
        }
    )

向上 / 向下的函是一样的,值不一样而已,就不多赘述了。

2.3 手势响应

组件 & 动画设计好了,就差什么时候触发动画了!
首先先给 ScrollView 一套自定义的手势响应

    this._panResponder = PanResponder.create({
            onMoveShouldSetPanResponderCapture:this._handleMoveShouldSetPanResponderCapture,
            onPanResponderGrant: this._handlePanResponderGrant,
            onPanResponderMove: this._handlePanResponderMove,
            onPanResponderRelease: this._handlePanResponderEnd
        })

这几个函数都没得说,在文档里已经写得很清楚了。下面我们来看看什么时候触发向上的动画。前面说了在初始画面里向上滚动,列表会变长,那么就判断是不是向上滚动。

    _handlePanResponderEnd = (event, gestureState) => {
        // 我们只需要在这里判断 gestureState.dy 的值是否为正负
        if (gestureState.dy < 0) {
            // 执行向上移动画
        }
    }

向上很简单,向下移动(缩小) 的话需要判断,用户已经在在 ScrollView 滚动到顶部,并且手势是向下滑动的,才可以收回 ScrollView。

    <ScrollView
        {...this._panResponder.panHandlers} // 绑定手势响应
        style={
            {
                position: 'absolute',
                top: 500,
                height: '展开后的高度'
            }
        }
        onScroll={this._handleScrollEnd} // 每次滚动记录滚动位置
        scrollEventThrottle={16} // 设置 onScroll 触发频率,一般为 16
    >
        // children
    <ScrollView>

    this._handleScrollEnd = (e) => {
        this._switchScrollBottom = e.nativeEvent.contentOffset.y // 保存最后滚动位置
    }
    // 在申请成功时候保存上次滚动
    _handlePanResponderGrant = (event, gestureState) => {
        this._previousScrollValue = this._switchScrollBottom
    }
    _handlePanResponderEnd = (event, gestureState) => {
        // 如果上次滚动和这次滚动位置的值一样,证明没有滚动, 已经到达顶部了。
        // 这时候则触发移动至 bottom 的动画
        if (gestureState.dy > 0) {
            if (this._previousScrollValue == this._switchScrollBottom) {
                this._scrollAnimToBotton()
            }       
        }

总结

rn 自带的动画系统性能还是可以的,而且使用起来也比较方便, 和手势系统一同使用可以解决很多需求。本文章只是大概提供了思路,由于时间紧迫,没来得及写 dome, 所以都是一些伪代码。如果遇到问题可以在下方留言,欢迎一同讨论!

猜你喜欢

转载自blog.csdn.net/sunlei19951007/article/details/82659847