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

现象:最近开发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. 效果图


    效果图
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,794评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,050评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,587评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,861评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,901评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,898评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,832评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,617评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,077评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,349评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,483评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,199评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,824评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,442评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,632评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,474评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,393评论 2 352