Page 1 of 3

在RN中用svg绘制三角形添加手势无法给予动画转换(Animated transform)

Posted: 2022年 Nov 25日 10:03
by Magnum
  • 问题描述,在RN种直接给View使用PanResponder手势,参考官网给View一些动画是正常的,
    如附件demo中的组件DeviceDrag。官网示例代码链接 https://reactnative.cn/docs/animations

  • 但我们是要给一些图形(正方形、三角形)手势及拖拽移动效果,
    如svg画出的三角形,当前代码所绘制的便是三角形

  • 当前问题是:Svg的G/Polygon添加手势会有响应,但无法给予拖拽移动。或者可以说是无法给Animated适合的变换。有无大佬可以在技术上指点迷津下,多谢!感恩! :D

Code: Select all


const AnimatedPolygon = Animated.createAnimatedComponent(Polygon);
const AnimatedG = Animated.createAnimatedComponent(G);

/// SVG相关代码
const SvgItemMove = () => {

// item信息    
const [item, setItem] = useState({"points":{"x":62.89,"y":240.31},"rotate":90,"type":"A","scale":1,"color":"#0CC5E3","index":0})

const l = (77.89 - 28.44) 

const getItemPoints = (item) => {
    const points = item.points
    const a = item.scale; 
    if (item.type !== 'D') { 
        switch (item.rotate) {
            case 0:
                return [
                    [points.x, points.y],
                    [points.x - a * l, points.y + a * l],
                    [points.x + a * l, points.y + a * l]
                ]
            case 90:
                return [
                    [points.x, points.y],
                    [points.x - a * l, points.y - a * l],
                    [points.x - a * l, points.y + a * l]
                ]
            case 180:
                return [
                    [points.x, points.y],
                    [points.x - a * l, points.y - a * l],
                    [points.x + a * l, points.y - a * l]
                ]
            case 270:
                return [
                    [points.x, points.y],
                    [points.x + a * l, points.y - a * l],
                    [points.x + a * l, points.y + a * l]
                ]
            default:
                return [
                    [points.x, points.y],
                    [points.x - a * l, points.y + a * l],
                    [points.x + a * l, points.y + a * l]
                ]
        }
    } else {
        return [
            [points.x, points.y - a * l],
            [points.x - a * l, points.y],
            [points.x, points.y + a * l],
            [points.x + a * l, points.y]
        ]
    }
}


const pan = useRef(new Animated.ValueXY()).current;
const panResponder = useRef(
    PanResponder.create({
        onMoveShouldSetPanResponder: () => true,
        onPanResponderMove: Animated.event([
            null,
            { dx: pan.x, dy: pan.y }
        ]),
        onPanResponderRelease: () => {
            console.log("手势响应结束?" + JSON.stringify(pan))

            const tempItem = item
            // tempItem.points = {"x":62.89,"y":240.31}

            /**
             * 问题描述,直接使用PanResponder手势,参考官网给View一些动画是正常的,如组件DeviceDrag。https://reactnative.cn/docs/animations
             * 但我们是要给一些图形(正方形、三角形)手势及拖拽移动效果,如svg画出的三角形,当前代码所绘制的便是三角形
             * 当前问题是:添加手势会有响应,但无法给予拖拽移动
             */
            tempItem.points = {"x":pan.x,"y":pan.y}
            setItem(tempItem)

            Animated.spring(pan, { toValue: { x: 0, y: 0 } }).start();
        }
    })
).current;


return (
    <View style={anistyles.container}>
        <Text style={anistyles.titleText}>Drag & Release this box!</Text>
        <Svg
            width={deviceWidth}
            height={deviceHeight}
        >
            <AnimatedG
                style={{
                    transform: [{ translateX: pan.x }, { translateY: pan.y }]
                }}
                {...panResponder.panHandlers}
            >
                <Polygon
                
                    // points={"62.89,240.31 13.439999999999998,190.86 13.439999999999998,289.76"}
                    points={getItemPoints(item).map(_ => `${_[0]},${_[1]}`).join(' ')}
                    stroke={"black"} // 边线颜色
                    strokeWidth="2"
                    fill={"white"}
                >
                </Polygon>
            </AnimatedG>
        </Svg>
    </View>
)
}


Re: 在RN中用svg绘制三角形添加手势无法给予动画转换(Animated transform)

Posted: 2022年 Nov 25日 11:19
by xuanyi

react-native-svg 中的组件多数为原生导出的组件, 并不支持 style 中的 transform,并且也并不支持 animated 包装。
建议直接使用 setState 来保存数据。


Re: 在RN中用svg绘制三角形添加手势无法给予动画转换(Animated transform)

Posted: 2022年 Nov 25日 11:28
by Magnum
xuanyi 2022年 Nov 25日 11:19

react-native-svg 中的组件多数为原生导出的组件, 并不支持 style 中的 transform,并且也并不支持 animated 包装。
建议直接使用 setState 来保存数据。

大佬,直接用setState保存数据会不会有性能问题,或者卡顿?


Re: 在RN中用svg绘制三角形添加手势无法给予动画转换(Animated transform)

Posted: 2022年 Nov 25日 11:46
by Magnum
xuanyi 2022年 Nov 25日 11:19

react-native-svg 中的组件多数为原生导出的组件, 并不支持 style 中的 transform,并且也并不支持 animated 包装。
建议直接使用 setState 来保存数据。

大佬,用setState可以滑动。但每次重新点击item准备滑动时,就会从上次滑动后的位置跳回初始值的位置,怎么更新Polygon的point坐标呢,让Polygon不会跳回初始值的位置?多谢了


Re: 在RN中用svg绘制三角形添加手势无法给予动画转换(Animated transform)

Posted: 2022年 Nov 25日 16:16
by xuanyi

在同一组件内部使用 useState 去设置问题不大。 只要不是透传到其他组件或存 redux 处理。

回原点是不是图片上代码没去掉呢


Re: 在RN中用svg绘制三角形添加手势无法给予动画转换(Animated transform)

Posted: 2022年 Nov 25日 18:07
by Magnum

onPanResponderRelease的代码都注释掉了


Re: 在RN中用svg绘制三角形添加手势无法给予动画转换(Animated transform)

Posted: 2022年 Nov 28日 11:14
by Magnum

紧着上次问题,我发现在RN工程环境(单独创建RN工程demo)中,是可以用Animated和PanResponder完成拖拽和坐标(points)重新赋值更新,但在涂鸦环境中,就无法响应Animated,请问这个情况需要怎么处理?

另外,如果采用之前大佬提供的方法,是可以实现移动,但如何更新坐标points的值?

单独创建RN工程中demo代码如下:

Code: Select all


import React, { useRef, useState } from "react";
import res from "./res";
import Svg, { Rect, G, Polygon, Path, } from "react-native-svg";

import {
    Image,
    View, ScrollView,
    Text, StyleSheet, TouchableOpacity, PanResponder
} from 'react-native';

import {
    Dimensions,
    Animated
} from 'react-native';

const {
    height: deviceHeight,
    width: deviceWidth
} = Dimensions.get('window');

const AnimatedPolygon = Animated.createAnimatedComponent(Polygon);
const AnimatedG = Animated.createAnimatedComponent(G);

/// SVG相关代码
const SvgItemMove = () => {

// item信息    
const [item, setItem] = useState({"points":{"x":62.89,"y":240.31},"rotate":90,"type":"A","scale":1,"color":"#0CC5E3","index":0})

const l = (77.89 - 28.44) 

const getItemPoints = (item) => {
    const points = item.points
    const a = item.scale; 
    if (item.type !== 'D') { 
        switch (item.rotate) {
            case 0:
                return [
                    [points.x, points.y],
                    [points.x - a * l, points.y + a * l],
                    [points.x + a * l, points.y + a * l]
                ]
            case 90:
                return [
                    [points.x, points.y],
                    [points.x - a * l, points.y - a * l],
                    [points.x - a * l, points.y + a * l]
                ]
            case 180:
                return [
                    [points.x, points.y],
                    [points.x - a * l, points.y - a * l],
                    [points.x + a * l, points.y - a * l]
                ]
            case 270:
                return [
                    [points.x, points.y],
                    [points.x + a * l, points.y - a * l],
                    [points.x + a * l, points.y + a * l]
                ]
            default:
                return [
                    [points.x, points.y],
                    [points.x - a * l, points.y + a * l],
                    [points.x + a * l, points.y + a * l]
                ]
        }
    } else {
        return [
            [points.x, points.y - a * l],
            [points.x - a * l, points.y],
            [points.x, points.y + a * l],
            [points.x + a * l, points.y]
        ]
    }
}


const pan = useRef(new Animated.ValueXY()).current;
const panResponder = useRef(
    PanResponder.create({
        onMoveShouldSetResponderCapture: () => true,
        onMoveShouldSetPanResponderCapture: () => true,
        // 设置初始位置
        onPanResponderGrant: (e, gestureState) => {
            pan.setOffset({
            x: pan.x._value,
            y: pan.y._value,
            });
            pan.setValue({ x: 0, y: 0 });
        },

        onPanResponderMove: Animated.event([
            null,
            { dx: pan.x, dy: pan.y }
        ]),
        onPanResponderRelease: () => {
            console.log("手势响应结束?" + JSON.stringify(pan))

            const tempItem = item
            // tempItem.points = {"x":62.89,"y":240.31}

            /**
             * 问题描述,直接使用PanResponder手势,参考官网给View一些动画是正常的,如组件DeviceDrag。https://reactnative.cn/docs/animations
             * 但我们是要给一些图形(正方形、三角形)手势及拖拽移动效果,如svg画出的三角形,当前代码所绘制的便是三角形
             * 当前问题是:添加手势会有响应,但无法给予拖拽移动
             */
            tempItem.points = {"x":pan.x,"y":pan.y}
            setItem(tempItem)

            // Animated.spring(pan, { toValue: { x: 0, y: 0 } }).start();

            pan.flattenOffset();
        }
    })
).current;


return (
    <View style={anistyles.container}>
        <Text style={anistyles.titleText}>Drag & Release this box!</Text>
        <Svg
            width={deviceWidth}
            height={deviceHeight}
        >
            <AnimatedG
                style={{
                    transform: [{ translateX: pan.x }, { translateY: pan.y }]
                }}
                {...panResponder.panHandlers}
            >
                <AnimatedPolygon
                
                    // points={"62.89,240.31 13.439999999999998,190.86 13.439999999999998,289.76"}
                    points={getItemPoints(item).map(_ => `${_[0]},${_[1]}`).join(' ')}
                    stroke={"black"} // 边线颜色
                    strokeWidth="2"
                    fill={"white"}
                    // style={{
                    //     transform: [{ translateX: pan.x }, { translateY: pan.y }]
                    // }}
                    // {...panResponder.panHandlers}
                >
                </AnimatedPolygon>
            </AnimatedG>
        </Svg>
    </View>
)
}


Re: 在RN中用svg绘制三角形添加手势无法给予动画转换(Animated transform)

Posted: 2022年 Nov 28日 11:32
by xuanyi

涂鸦环境中 react-native-animated 版本 1.19.0 。版本较低


Re: 在RN中用svg绘制三角形添加手势无法给予动画转换(Animated transform)

Posted: 2022年 Nov 28日 11:36
by Magnum

demo代码中没使用react-native-animated这个框架,使用的react-native的Animated。


Re: 在RN中用svg绘制三角形添加手势无法给予动画转换(Animated transform)

Posted: 2022年 Nov 28日 13:35
by xuanyi

Demo 里 RN 什么版本呢。