react-native 组件Transforms属性+Animated + 手势 Demo

react-native transforms 实现动画:

通过组件style 内提供的 transforms 属性来实现改变组件坐标角度旋转等(xyz三坐标轴)
transforms 接收的是array 类型
array of object: {perspective: number}, ,object: {rotate: string}, ,object: {rotateX: string}, ,object: {rotateY: string}, ,object: {rotateZ: string}, ,object: {scale: number}, ,object: {scaleX: number}, ,object: {scaleY: number}, ,object: {translateX: number}, ,object: {translateY: number}, ,object: {skewX: string}, ,object: {skewY: string}

perspective:透视程度; rotate: 旋转角度 ,rotateX x 轴旋转 , rotateY y轴旋转 ,rotateZ z轴旋转 ;scale:缩放; translate 位移; skew:倾斜度

本案例通过 组件onLayout属性 获取组件在当前父视图中的坐标,在通过手势位移去改变组件的坐标.

git地址:https://github.com/CJELLYS/react-native-transform-demo

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 * @flow
 */

import React, {Component} from 'react';
import {
  Platform, 
  StyleSheet, 
  Text, 
  View,
  TouchableOpacity,
  PanResponder,
  Animated,
  Dimensions
} from 'react-native';
import {NativeModules} from 'react-native';
const AppDelegate = NativeModules.AppDelegate;

type Props = {};

const widthScreen = Dimensions.get('window').width;
const rotateXDeg = 90.0 //x轴最终旋转的角度为90度
const offsetX = (widthScreen -80)/2.0 //为 终点坐标左上角X轴坐标位置
const offsetY = 50 //200 为终点左上角Y轴坐标位置
const offsetUnitX = (offsetX - 50)/rotateXDeg//x轴单位位移量 180 为 获取到的组件坐标的x值+组件宽度 50 为 组件初始x轴坐标值
const offsetUnitY = (offsetY-100)/rotateXDeg //y轴单位位移量   100 为 获取到的组件坐标的y值+组件宽度 ;

export default class App extends Component<Props> {
 
  constructor(props){
    super(props)
    this.state =({
      textRotateX:0,//X轴旋转
      translateX:new Animated.Value(0),//X轴位移
      translateY:new Animated.Value(0),//Y轴位移
    });
    this.textRotateX = 0
    this.translateX = 0
    this.translateY = 0
  }

  checkAction(){
    console.log("NativeModules=>",AppDelegate);
    if(AppDelegate){
      AppDelegate.addEvent('Birthday Party', '4 Privet Drive, Surrey');
    }
  }

  componentWillMount(){
    if(!this._panResponder)
    this._panResponder = PanResponder.create({
      // 要求成为响应者:
      onStartShouldSetPanResponder: (evt, gestureState) => true,
      onStartShouldSetPanResponderCapture: (evt, gestureState) => true,
      // onMoveShouldSetPanResponder: (evt, gestureState) => true,
      // onMoveShouldSetPanResponderCapture: (evt, gestureState) => true,

      onPanResponderGrant: (evt, gestureState) => {
        // 开始手势操作。给用户一些视觉反馈,让他们知道发生了什么事情!

        // gestureState.{x,y} 现在会被设置为0
        // console.log("===>>0",'开始手势操作');
      },
      onPanResponderMove: (evt, gestureState) => {
        // 最近一次的移动距离为gestureState.move{X,Y}

        // 从成为响应者开始时的累计手势移动距离为gestureState.d{x,y}
        if(this.textRotateX < -rotateXDeg){
          this.textRotateX = -rotateXDeg;
          this.setState({
            textRotateX:this.textRotateX
          })
          return
        }
        if(gestureState.dy < 0 && this.textRotateX> -rotateXDeg){
          this.textRotateX = this.textRotateX -1;
          this.translateX = this.translateX + offsetUnitX;
          this.translateY = this.translateY + offsetUnitY ;
          this.setState({
            textRotateX:this.textRotateX
          })
          Animated.parallel([
            // 执行缩放
            Animated.timing(this.state.translateX, {
                toValue: this.translateX,
                duration: 0,
            }),
            Animated.timing(this.state.translateY, {
                toValue: this.translateY,
                duration: 0,
            })
        ]).start();

        }else if(gestureState.dy > 0 && this.textRotateX <= 0){
          this.textRotateX = this.textRotateX +1;
          this.translateX = this.translateX - offsetUnitX;
          this.translateY = this.translateY - offsetUnitY ;
          this.setState({
            textRotateX:this.textRotateX
          })
           Animated.parallel([
            // 执行缩放
            Animated.timing(this.state.translateX, {
                toValue: this.translateX,
                duration: 0,
            }),
            Animated.timing(this.state.translateY, {
                toValue: this.translateY,
                duration: 0,
            })
        ]).start();
        }
      },

      onPanResponderTerminationRequest: (evt, gestureState) => true,
      onPanResponderRelease: (evt, gestureState) => {
        // 用户放开了所有的触摸点,且此时视图已经成为了响应者。
        // 一般来说这意味着一个手势操作已经成功完成。
        // console.log("用户放开",gestureState.moveX,gestureState.moveY);

        if(this.textRotateX > -rotateXDeg/2.0 && this.textRotateX < rotateXDeg/2.0){
          this.textRotateX = 0  
          this.translateX = 0;
          this.translateY = 0;
          this.setState({
            textRotateX:this.textRotateX
          })
          Animated.parallel([
          Animated.spring(this.state.translateX,
            { 
              toValue: this.translateX,
              duration: 500
            }),
          Animated.spring(this.state.translateY,
          { 
            toValue: this.translateY,
            duration: 500
          })
        ]).start()
        }else{
          this.textRotateX = -rotateXDeg
          this.translateX = offsetX - 50;
          this.translateY = (offsetY-100);
          this.setState({
            textRotateX:this.textRotateX
          })
          Animated.parallel([
            Animated.spring(this.state.translateX,
              { 
                toValue: this.translateX,
                duration: 500
              }),
            Animated.spring(this.state.translateY,
            { 
              toValue: this.translateY,
              duration: 500
            })
          ]).start()
        }
        
      },
      onPanResponderTerminate: (evt, gestureState) => {
        // 另一个组件已经成为了新的响应者,所以当前手势将被取消。
        console.log("===>>3",'另一个组件');
      },
      onShouldBlockNativeResponder: (evt, gestureState) => {
        // 返回一个布尔值,决定当前组件是否应该阻止原生组件成为JS响应者
        // 默认返回true。目前暂时只支持android。
        return true;
      },
    });
  }

  getAnimatedView(event){
    let {x,y,width,height} = event.nativeEvent.layout
    console.log("xxxxxxx==>",x,y,width,height)
  }

  render() {
    return (
      <View style={styles.container} {...this._panResponder.panHandlers}>
      <Animated.View style={{
        width:80,
        height:80,
        marginTop:100,
        marginLeft:50,
        backgroundColor:'red',
        borderRadius:40,
        transform:[{translateX:this.state.translateX},{translateY:this.state.translateY}]
      }}
      onLayout = {this.getAnimatedView.bind(this)}
      ref={(animatedView)=>this.animatedView = animatedView}
      >
      </Animated.View>
       <Text style={{
         fontSize:12,
         height:30,
         width:80,
         marginLeft:200,
         marginTop:30,
         backgroundColor:'cyan',
         alignItems:'center',
         justifyContent:'center',
         transform:[{ rotateX: this.state.textRotateX +'deg'}],
         marginBottom:30
       }}>{'Hello'}</Text>       
        <TouchableOpacity 
        onPress={this.checkAction.bind(this)}
        style={{width:80,height:40,alignItems:'center',justifyContent:'center',backgroundColor:'cyan'}}>
          <Text>验证</Text>
        </TouchableOpacity>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#F5FCFF',
  },
});


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

推荐阅读更多精彩内容