视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
使用RN Animated做一个“添加购物车”动画的方法
2020-11-27 22:07:48 责编:小采
文档

最近在选座的新项目中试用了一下 React Native,熟悉新框架的同时,可以略微将交互效果和 Native 看齐了。

分享一下项目本身比较重要的一个交互动画的做法, RT。

这次我们就不装大象了,因为我真的买了冰箱 =,=

本着言简意赅,不故弄玄虚的原则,依然是三步:

第 1 步:通过 Animated 创建合成动画的 View。仔细观察,“选择座位” 动画和 “添加购物车” 动画类似,都可以分解为透明度变化( opacity )和 3D 变化( transform )两部分。而 transform 又能进一步分解为水平位移( translateX )、垂直位移( translateY )、旋转( rotateZ )、缩放( scale )四个分动画( 代码见 render() );

第 2 步:响应点击事件,准备好动画的相关参数。目标位置被点击时,在动画的父级组件中通过 onPress 事件的 event 对象获取点击的位置坐标( event.nativeEvent.changedTouches[0].pageX|Y )作为动画起始位置。终点位置一般为固定位置,当然你也可以指定动态值;

第 3 步:获取参数, start() 播放动画( 代码见 componentDidMount() )。从父级组件中获取位置参数并通过 props 传入子动画组件。其中 opacityrotateZscale 属性值都是静态变化,分别为 1 -> 0 0deg -> 360deg 1 -> 0 (可以利用 interpolate 方法做各个属性不同类型值的 mapping,更加方便统一控制);

注意:类似的全局动画要展示在最高层级,防止被后渲染的组件遮挡,最好单独封装组建提升其在 UI 中的渲染层级。

import React from 'react';

import {
 StyleSheet,
 View,
 Image,
 Animated
} from 'react-native';

export default class SeatDroppingextends React.PureComponent{
 constructor (props) {
 super(props);
 this.state = {
 animValue: new Animated.Value(0),
 fromPageX: props.clickedPosition.x, // from event.nativeEvent.changedTouches[0]
 fromPageY: props.clickedPosition.y,
 toPageX: props.psgPosition.x,
 toPageY: props.psgPosition.y
 };
 }
 componentDidMount() {
 Animated.timing(
 this.state.animValue,
 {
 toValue: 1,
 duration: 600
 }
 ).start();
 }
 render () {
 const {
 animValue,
 fromPageX,
 fromPageY,
 toPageX,
 toPageY
 } = this.state;
 return (
 <Animated.View
 style={{
 zIndex: 9,
 position: 'absolute',
 opacity: animValue.interpolate({
 inputRange: [0, 1],
 outputRange: [1, 0]
 }),
 transform: [
 {
 translateX: animValue.interpolate({
 inputRange: [0, 1],
 outputRange: [`${fromPageX}px`, `${toPageX}px`]
 })
 },
 {
 translateY: animValue.interpolate({
 inputRange: [0, 1],
 outputRange: [`${fromPageY}px`, `${toPageY}px`]
 })
 },
 {
 rotateZ: animValue.interpolate({
 inputRange: [0, 1],
 outputRange: ['0deg', '180deg']
 })
 },
 {
 scale: animValue.interpolate({
 inputRange: [0, 1],
 outputRange: [1, 0]
 })
 }
 ]}}
 >
 <Image
 source={require('../img/ic_seat_focus.png')}
 style={[
 {
 width: 36,
 height: 32,
 zIndex: 9
 }
 ]}
 />
 </Animated.View>
 );
 }
}

 

下载本文
显示全文
专题