美文网首页
【react-native】滑动吸顶效果 + 下拉刷新

【react-native】滑动吸顶效果 + 下拉刷新

作者: 空城皆是旧梦 | 来源:发表于2019-11-13 18:38 被阅读0次

    现象:最近开发RN项目,需要开发一个页面滑动过程中的tab吸顶的效果。

    解决方案: 使用Animated创建动画

    具体代码如下:

    1. index.tsx
    import React, { Component } from 'react'
    
    import { View, Text, ViewStyle, StyleSheet, ImageBackground, Animated, RefreshControl } from 'react-native'
    import StickyHeader from "./StickyHeader"
    import { images, dimensions } from '../../../../res'
    
    interface IState {
      refreshing: boolean,
      scrollHeight: number,
      scrollY: Animated.Value
    }
    
    export class PrivateCollectScreen extends Component<any, IState> {
    
      readonly state: IState = {
        scrollY: new Animated.Value(0),
        scrollHeight: -1,
        refreshing: false
      }
    
    
    
      render() {
        return (
          <View style={styles.container}>
            <Animated.ScrollView
              style={{ flex: 1 }}
              onScroll={
                Animated.event( // 映射动画值
                  [{
                    // 垂直滚动时,将 event.nativeEvent.contentOffset.y映射到this.state.scrollY,以此记录滑动距离
                    nativeEvent: { contentOffset: { y: this.state.scrollY } }
                  }],
                  { useNativeDriver: true }) // 启用原生动画驱动。默认不启用(false)
              }
              scrollEventThrottle={1} // 滚动条距离视图边缘的坐标
              refreshControl={ // 下拉刷新功能
                <RefreshControl
                  style={{ backgroundColor: 'transparent' }}
                  tintColor={'white'}
                  refreshing={this.state.refreshing}
                  onRefresh={() => { // 再刷新时调用
                    this.setState({ refreshing: true })
                  }} />
              }
            >
    
    
              <View onLayout={(e) => {
                this.setState({ scrollHeight: e.nativeEvent.layout.height }) // 获取头部的高度
              }}>
                <ImageBackground
                  style={{ width: dimensions.screenWidth, height: 190 }}
                  source={images.icReact}
                >
                  {/* 头部内容 */}
                </ImageBackground>
              </View>
    
    
              <StickyHeader
                stickyHeaderY={this.state.scrollHeight} // 将头部高度传入组件
                stickyScrollY={this.state.scrollY}  // 将滑动距离传入组件
              >
                <View style={{ height: 50, backgroundColor: '#3356d9' }}>
                  <Text style={{ fontSize: 20, textAlign: 'center', color: '#fff', lineHeight: 50 }}>固定栏</Text>
                </View>
              </StickyHeader>
    
    
              {/* 底部内容 */}
              {
                [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11].map((item, index) => {
                  return (<View style={{ height: 100 }}><Text>底部内容{index}</Text></View>)
                })
              }
            </Animated.ScrollView>
          </View>
        )
      }
    }
    
    interface Styles {
      container: ViewStyle
    }
    
    const styles = StyleSheet.create<Styles>({
      container: {
        flex: 1,
        backgroundColor: '#fff'
      }
    })
    
    1. StickyHeader.tsx
    import * as React from 'react'
    import { StyleSheet, Animated } from 'react-native'
    
    interface IState {
      stickyLayoutY: number,
      stickyHeaderY: number,
      stickyScrollY: Animated.Value
    }
    
    /**
     * 滑动吸顶效果组件
     * @export
     * @class StickyHeader
     */
    export default class StickyHeader extends React.Component<any, IState> {
    
    
      readonly state: IState = {
        stickyHeaderY: -1,
        stickyScrollY: new Animated.Value(0),
        stickyLayoutY: 0
      }
      // 兼容代码,防止没有传头部高度
      _onLayout = (event) => {
        this.setState({
          stickyLayoutY: event.nativeEvent.layout.y,
        })
      }
    
      render() {
        const { stickyHeaderY, stickyScrollY, children, style } = this.props
        const { stickyLayoutY } = this.state
        let y = stickyHeaderY !== -1 ? stickyHeaderY : stickyLayoutY
        const translateY = stickyScrollY.interpolate({
          inputRange: [-1, 0, y, y + 1],
          outputRange: [0, 0, 0, 1],
        })
    
        return (
          <Animated.View
            onLayout={this._onLayout}
            style={
              [
                style,
                styles.container,
                { transform: [{ translateY }] }
              ]}
          >
            {children}
          </Animated.View>
        )
      }
    }
    
    const styles = StyleSheet.create({
      container: {
        zIndex: 100
      }
    })
    
    1. 效果图


      效果图

    相关文章

      网友评论

          本文标题:【react-native】滑动吸顶效果 + 下拉刷新

          本文链接:https://www.haomeiwen.com/subject/heskictx.html