ReactNative: 运用Animted API完成向上转动时隐蔽Header组件

想先引荐一下近期在写的一个React Native项目,名字叫
Gakki :是一个
Mastodon的第三方客户端 (Android App)

预览

《ReactNative: 运用Animted API完成向上转动时隐蔽Header组件》

写在前面

原本我也不想造这个轮子的,怎样没找到适宜的组件。只能本身上了~

思绪很清晰: 监听转动事宜,动态修正Header组件和Content组件的top值(固然,他们默许都是position:relative)。

接下来完成的时刻遇到了题目,我第一个版本是经由过程动态设置state来完成,即:

/**
 * 每次转动时,从新设置headerTop的值
 */
onScroll = event =>{
    const y = event.nativeEvent.contentOffset.y
    if (y >= 270) return
    // headerTop等于Header和Content的top款式对应的值
    this.setState({
        headerTop: y
    })
}

如许虽然能完成,然则结果不好:显著能够看到在上滑的过程当中,Header组件一卡一卡地向上方挪动(一点都不流通)。

由于就只能另寻他法了:动画

React Native 供应了两个互补的动画体系:用于建立邃密的交互掌握的动画
Animated和用于全局的规划动画
LayoutAnimation (笔者注:此次没有用到它)

Animated 相干API引见

起首,这儿有一个简朴“逐步显现”动画的DEMO,须要你先看完(文档很简朴清楚明了且解释清晰,没必要Copy过来)。

在看懂了DEMO的基础上,我们还须要相识两个症结的API才完成完全的结果:

1. interpolate

插值函数。用来对差别范例的数值做映照处置惩罚。

固然,这是文档申明:

Each property can be run through an interpolation first. An interpolation maps input ranges to output ranges, typically using a linear interpolation but also supports easing functions. By default, it will extrapolate the curve beyond the ranges given, but you can also have it clamp the output value.

翻译:

每一个属性能够先经由插值处置惩罚。插值对输入局限和输出局限之间做一个映照,平常运用线性插值,但也支撑紧张函数。默许情况下,假如给定数据超出局限,他也能够自行推断出关于的曲线,但您也能够让它箝位输出值(P.S. 末了一句能够翻译毛病,由于没搞懂clamp value指的是什么, sigh…)

举个例子:

在完成一个图片扭转动画时,输入值只能是如许的:

this.state = {
  rotate: new Animated.Value(0) // 初始化用到的动画变量
}

...

// 这么映照是由于style款式须要的是0deg如许的值,你给它0如许的值,它可不能平常事情。由于一定须要一个映照处置惩罚。
this.state.rotate.interpolate({ // 将0映照成0deg,1映照成360deg。固然中心的数据也是云云映照。
  inputRange: [0, 1],
  outputRange: ['0deg', '360deg']
})

2. Animated.event

平常动画的输入值都是默许设定好的,比方前面DEMO中的逐步显现动画中的透明度:最先是0,末了是1。这是已写死了的。

但假如有些动画结果须要的不是写死的值,而是动态输入的呢,比方:手势(上滑、下滑,左滑,右滑…)、别的事宜。

那就用到了Animated.event

直接看一个将转动事宜的y值(转动条间隔顶部高度)和我们的动画变量绑定起来的例子:

// 这段代码示意:在转动事宜触发时,将event.nativeEvent.contentOffset.y 的值动态绑定到this.state.headerTop上
// 和最前面我经由过程this.setState动态设置的目标一样,但交给Animated.event做就不会形成视觉上的卡顿了。
onScroll={Animated.event([
   {
      nativeEvent: {
        contentOffset: { y: this.state.headerTop }
      }
   }
])}

关于API更多的申明请移步文档

完全代码

import React, { Component } from 'react'
import { StyleSheet, Text, View, Animated, FlatList } from 'react-native'

class List extends Component {
  render() {
    // 模仿列表数据
    const mockData = [
      '强盛',
      '民主',
      '文化',
      '调和',
      '自在',
      '同等',
      '公平',
      '法治',
      '爱国',
      '敬业',
      '诚信',
      '和睦'
    ]

    return (
      <FlatList
        onScroll={this.props.onScroll}
        data={mockData}
        renderItem={({ item }) => (
          <View style={styles.list}>
            <Text>{item}</Text>
          </View>
        )}
      />
    )
  }
}

export default class AnimatedScrollDemo extends Component {
  constructor(props) {
    super(props)
    this.state = {
      headerTop: new Animated.Value(0)
    }
  }

  componentWillMount() {
    // P.S. 270,217,280区间的映照是通知interpolate,一切大于270的值都映照成-50
    // 如许就不会致使Header在上滑的过程当中一向向上滑动了
    this.top = this.state.headerTop.interpolate({
      inputRange: [0, 270, 271, 280],
      outputRange: [0, -50, -50, -50]
    })

    this.animatedEvent = Animated.event([
      {
        nativeEvent: {
          contentOffset: { y: this.state.headerTop }
        }
      }
    ])
  }

  render() {
    return (
      <View style={styles.container}>
        <Animated.View style={{ top: this.top }}>
          <View style={styles.header}>
            <Text style={styles.text}>linshuirong.cn</Text>
          </View>
        </Animated.View>
        {/* 在oHeader组件上移的同时,列表容器也须要同时向上挪动,须要注重。 */}
        <Animated.View style={{ top: this.top }}>
          <List onScroll={this.animatedEvent} />
        </Animated.View>
      </View>
    )
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1
  },
  list: {
    height: 80,
    backgroundColor: 'pink',
    marginBottom: 1,
    alignItems: 'center',
    justifyContent: 'center',
    color: 'white'
  },
  header: {
    height: 50,
    backgroundColor: '#3F51B5',
    alignItems: 'center',
    justifyContent: 'center'
  },
  text: {
    color: 'white'
  }
})

    原文作者:林水溶
    原文地址: https://segmentfault.com/a/1190000017510203
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞