第13课:添加优化动画

知识点:

  • 首页动画
  • 动画组件说明
  • 动画优化

首页加入动画

我们在首页加入这样一个动画,在默认情况下首页顶部是透明的,当内容往下滚动的时候,将顶部的背景颜色变成白色,搜索框颜色变成其他颜色。

在首页的 state 中加入默认的位置值,这里使用动画库的单项值,设置默认值为 0。

scrollTop: new Animated.Value(0)

修改 FlatList 组件的滚动监听频率,这里的意思是每秒触发 100 次监听方法,即等于每 10 毫秒触发一次方法。

scrollEventThrottle={100}

修改监听方法,如果滚动超过 200 就不再做任何操作,这里使用直接设置值的方式,滚动的数字变化特别频繁,已经不需要使用动画的方式改变值了。

//滚动监听
_onScroll(e) {
    const y = e.contentOffset.y;
    if (y < 200) this.state.scrollTop.setValue(y)
}

将顶部的组件外层替换使用 Animated.View,这里做了一个映射,将数字直接映射成对应的颜色透明度。注意不要使用 opacity,该属性会把内容也变成透明的,这里同时映射负数是因为列表在下拉刷新的时候会变成负数,也要将这个因素也考虑进来。

<Animated.View style={[styles.headerView,{
                backgroundColor: this.state.scrollTop.interpolate({
                    inputRange: [-100, 0, 100],
                    outputRange: ['rgba(255,255,255,.5)', 'rgba(255,255,255,0)', 'rgba(255,255,255,1)']
                })
            }]}>
                <SearchHeader share={() => this.share()} navigation={this.props.navigation} />
            </Animated.View>
回到顶部

在监听滚动条的基础上可以直接做滚动到顶部的判断,如果滚动距离超过 400 并且回到顶部按钮是隐藏的,直接显示按钮,反之则把按钮隐藏起来。

在渲染方法中加入一个可点击的图片,设置点击滚动到最顶层。

{this.state.showTop && <TouchableOpacity onPress={()=>this.toTop()}>
  <Image style={styles.toBtn}
      source={{ uri: require("../images/icon-to-top") }} />
</TouchableOpacity>}

修改监听方法,让滚动的时候可以根据情况改变按钮的显示隐藏,这里加上判断可以减少很多不必要的状态设置。

//滚动监听
_onScroll(e) {
    const y = e.contentOffset.y;
    if (y < 200) this.state.scrollTop.setValue(y)
    if (y < 500 && this.state.showTop) {
        this.setState({ showTop: false })
    }
    if (y > 500 && !this.state.showTop) {
        this.setState({ showTop: true })
    }
}

添加回到顶部的方法:

//回到顶部
toTop(){
    this.refs.flatlist.scrollToOffset({offset:0})
}
其他动画

顶部颜色变换只是一个很简单的动画,有兴趣的同学可以试试加入更多的变化,比如通过叠加的两个图片造成一个图片的变色动画,以及字体的颜色、阴影(提示:不能用阴影属性)动画等,这些都需要靠各位的聪明才智来实现了。

动画组件说明

RN 自带的 Animated 组件提供了几个已经处理过的组件,在使用动画的时候必须使用处理过的组件,不然是不支持的。虽然 RN 也提供了 createAnimatedComponent 方法来自定义组件,但是尽量还是不要使用的好。

  • Animated.Image
  • Animated.ScrollView
  • Animated.Text
  • Animated.View

创建动画组件能够接收的值必须使用下面其中之一初始化变量。动画组件会根据配置动态的改变值的内容,同时这个变化也会体现在 UI 界面上,不需要使用 set 方式去改变。

  • Animated.Value() //改变单个值
  • Animated.ValueXY() //改变两个值

最常用的是 timing 方法,该方法根据时间动态生成最终的结果,比如点击之后:

Animated.timing(value/*要改变的值*/,{
    //配置
    duration:500,//动画持续时间
    easing:Easing.inOut(Easing.ease),//动画方式,需要引入 Easing
    delay:0,//开始动画之前的延迟,默认0
    useNativeDriver:false//是否使用原生方式动画,默认不实用
}).start();//最后调用start启动动画

设置好的变量还可以直接调用它上面的方法,比如停止动画、改变值等操作。

this.state.anim.setValue(1);//直接设置值
this.state.anim.stopAnimation(callback?);//停止动画,参数是停止之后的回调
this.state.anim.addListener(callback);//监听值的变化
this.state.anim.setOffset(1);//动画偏移,每次计算都会加上这个值
this.state.anim.flattenOffset();//清除偏移

要使用动画做效果,最好使用 Transform 下面的值来生成最终的结果,Transform 下面通常支持 scale、scaleX、scaleY、translateX、translateY、rotate、rotateX、rotateY、rotateZ 这几个属性。

如果要设置颜色、角度等字符串型的值就要使用到插值函数 interpolate,该方法可以将对应的值映射为最终的结果,如果不在映射区间的则不会有改动。

//设置背景色
backgroundColor: this.state.scrollTop.interpolate({
  inputRange: [0, 100],
  outputRange: ['rgba(255,255,255,0)', 'rgba(255,255,255,1)']
  })
//设置角度
transform:[
 {rotate: this.state.rotateValue.interpolate({
    inputRange: [0, 1],
    outputRange: ['0deg', '360deg']})}
]

除了上面的简单动画,也可以使用 RN 的方法将几个动画组合使用。

  • Animated.delay(time);//延迟毫秒执行动画
  • Animated.parallel([],config); //同时开始执行动画
  • Animated.sequence([]); //一次执行动画

下面是一个顺序执行动画的例子。

startAnimation() {
  this.state.bounceValue.setValue(1.5); // 设置一个较大的初始值
  this.state.fadeOutOpacity.setValue(1);

  Animated.sequence([
      //  基础的单次弹跳物理模型
      Animated.spring(
          this.state.bounceValue, {
            toValue: 0.8,
            friction: 1,// 摩擦力,默认为7.
            tension: 40,// 张力,默认40。
          }), 
      //渐隐动画
      Animated.timing(this.state.fadeOutOpacity, {
        toValue: 0,
        duration: 2000,
        easing: Easing.linear,
      })
  ]).start();
}

优化建议

写动画的地方很有可能会引起 UI 的频繁刷新,在做动画的时候要注意一点这个。

如果使用定时器控制动画,请在销毁组件的时候清除定时器。

尽量使用 Transfrom 的属性来做动画的效果,其他的样式属性不如这个效率高。

尽量直接改变要动画的节点,要记得使用 Animted 提供的组件来做。

可以在动画的 start 中回调自身达成循环动画,也可以使用定时器定时重启动画。

在写这篇文章的时候 App 联盟出了一个快应用,这个模式还是很不错的,在未来有很大的潜力,如果要类比,可以看做是一个环境更大的小程序吧,对于快速开发上线的中小项目都非常的有利。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

疯狂紫萧

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值