You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在React Native中实现用户引导动画?

React Native 实现用户引导高亮动画

针对你需要的引导动画(遮罩高亮目标按钮+脉冲呼吸效果+引导提示框切换),可以用React Native原生动画API结合基础组件实现,以下是具体步骤:

1. 全屏遮罩与目标区域挖空

先做半透明遮罩层,仅目标按钮区域保持透明。这里提供两种实现方式:

原生View拼接实现(适合矩形/圆角矩形目标)

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

const GuideMask = ({ targetRect }) => {
  // targetRect包含目标元素的x、y、width、height(基于屏幕坐标系)
  return (
    <View style={styles.maskContainer}>
      {/* 上下左右五个遮罩块,留出中间目标区域 */}
      <View style={[styles.maskBlock, { top: 0, left: 0, right: 0, bottom: targetRect.y + targetRect.height }]} />
      <View style={[styles.maskBlock, { top: 0, left: 0, right: targetRect.x, bottom: targetRect.y }]} />
      <View style={[styles.maskBlock, { top: 0, left: targetRect.x + targetRect.width, right: 0, bottom: targetRect.y }]} />
      <View style={[styles.maskBlock, { top: targetRect.y, left: 0, right: targetRect.x, bottom: 0 }]} />
      <View style={[styles.maskBlock, { top: targetRect.y, left: targetRect.x + targetRect.width, right: 0, bottom: 0 }]} />
    </View>
  );
};

const styles = StyleSheet.create({
  maskContainer: {
    position: 'absolute',
    top: 0,
    left: 0,
    right: 0,
    bottom: 0,
    zIndex: 1000,
  },
  maskBlock: {
    position: 'absolute',
    backgroundColor: 'rgba(0,0,0,0.7)',
  },
});

SVG遮罩实现(适合任意形状目标)

如果目标是圆形或不规则形状,用react-native-svg的裁剪路径更灵活:

import Svg, { Rect, ClipPath, Defs } from 'react-native-svg';

const GuideMask = ({ targetRect }) => {
  const radius = targetRect.width / 2;
  return (
    <Svg style={styles.maskContainer}>
      <Defs>
        <ClipPath id="guideClip">
          {/* 全屏基础矩形 */}
          <Rect x="0" y="0" width="100%" height="100%" />
          {/* 挖空目标区域(这里是圆角矩形,可换成Circle等) */}
          <Rect 
            x={targetRect.x} 
            y={targetRect.y} 
            width={targetRect.width} 
            height={targetRect.height} 
            rx={radius}
            ry={radius}
            clipRule="evenodd"
          />
        </ClipPath>
      </Defs>
      <Rect 
        x="0" y="0" width="100%" height="100%" 
        fill="rgba(0,0,0,0.7)" 
        clipPath="url(#guideClip)" 
      />
    </Svg>
  );
};

2. 目标按钮的脉冲呼吸动画

用Animated API实现循环缩放的脉冲效果:

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

const PulseEffect = ({ targetRect }) => {
  const pulseAnim = useRef(new Animated.Value(1)).current;

  useEffect(() => {
    // 循环执行缩放动画
    Animated.loop(
      Animated.sequence([
        Animated.timing(pulseAnim, {
          toValue: 1.2,
          duration: 1000,
          useNativeDriver: false, // 涉及border宽高,无法用原生驱动
        }),
        Animated.timing(pulseAnim, {
          toValue: 1,
          duration: 1000,
          useNativeDriver: false,
        }),
      ])
    ).start();
  }, [pulseAnim]);

  return (
    <Animated.View
      style={[
        styles.pulseCircle,
        {
          left: targetRect.x - 10,
          top: targetRect.y - 10,
          width: targetRect.width + 20,
          height: targetRect.height + 20,
          borderRadius: (targetRect.width + 20) / 2,
          transform: [{ scale: pulseAnim }],
        },
      ]}
    />
  );
};

const styles = StyleSheet.create({
  pulseCircle: {
    position: 'absolute',
    borderWidth: 2,
    borderColor: '#ffffff',
    opacity: 0.5,
    zIndex: 1001,
  },
});

3. 引导提示框与步骤切换

用状态管理引导步骤,配合淡入淡出动画切换提示框:

import { useState, useRef, useEffect } from 'react';
import { View, Text, TouchableOpacity, Animated, StyleSheet } from 'react-native';

const UserGuide = ({ onFinish }) => {
  const [currentStep, setCurrentStep] = useState(0);
  // 自定义引导步骤,实际项目中可通过ref获取真实元素位置
  const steps = [
    {
      targetRect: { x: 150, y: 300, width: 80, height: 40 },
      tipText: '点击这里开始操作',
    },
    {
      targetRect: { x: 200, y: 400, width: 60, height: 35 },
      tipText: '接下来点击这里完成设置',
    },
  ];
  const fadeAnim = useRef(new Animated.Value(0)).current;

  // 切换步骤时的淡入动画
  useEffect(() => {
    Animated.timing(fadeAnim, {
      toValue: 1,
      duration: 300,
      useNativeDriver: true,
    }).start();
  }, [currentStep]);

  const handleNext = () => {
    if (currentStep === steps.length - 1) {
      onFinish();
      return;
    }
    // 先淡出当前提示,再切换步骤
    Animated.timing(fadeAnim, {
      toValue: 0,
      duration: 300,
      useNativeDriver: true,
    }).start(() => setCurrentStep(currentStep + 1));
  };

  const currentData = steps[currentStep];
  return (
    <>
      <GuideMask targetRect={currentData.targetRect} />
      <PulseEffect targetRect={currentData.targetRect} />
      <Animated.View
        style={[
          styles.tipBox,
          {
            left: currentData.targetRect.x + currentData.targetRect.width + 20,
            top: currentData.targetRect.y - 20,
            opacity: fadeAnim,
          },
        ]}
      >
        <Text style={styles.tipText}>{currentData.tipText}</Text>
        <TouchableOpacity onPress={handleNext} style={styles.nextBtn}>
          <Text style={styles.nextBtnText}>{currentStep === steps.length - 1 ? '完成' : '下一步'}</Text>
        </TouchableOpacity>
      </Animated.View>
    </>
  );
};

const styles = StyleSheet.create({
  tipBox: {
    position: 'absolute',
    backgroundColor: '#ffffff',
    padding: 15,
    borderRadius: 8,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.3,
    shadowRadius: 4,
    elevation: 5,
    zIndex: 1002,
  },
  tipText: {
    fontSize: 14,
    color: '#333333',
    marginBottom: 10,
  },
  nextBtn: {
    alignSelf: 'flex-end',
    backgroundColor: '#007AFF',
    paddingHorizontal: 12,
    paddingVertical: 6,
    borderRadius: 4,
  },
  nextBtnText: {
    color: '#ffffff',
    fontSize: 12,
  },
});

4. 获取真实元素位置

上面的targetRect是模拟数据,实际项目中需要通过useRef获取目标元素的屏幕位置:

import { useRef, useEffect, useState } from 'react';
import { TouchableOpacity } from 'react-native';

// 在页面组件中
const targetBtnRef = useRef(null);
const [targetRect, setTargetRect] = useState({});

useEffect(() => {
  targetBtnRef.current?.measure((x, y, width, height, pageX, pageY) => {
    setTargetRect({
      x: pageX,
      y: pageY,
      width,
      height,
    });
  });
}, []);

// 目标按钮组件
<TouchableOpacity ref={targetBtnRef} style={styles.targetBtn}>
  <Text>目标按钮</Text>
</TouchableOpacity>

优化提示

  • 若需更流畅的动画,可替换为react-native-reanimated库,支持更多原生驱动动画
  • 遮罩层可添加点击拦截,只允许目标区域响应点击
  • 可封装通用引导组件,支持自定义遮罩透明度、脉冲速度、提示框样式

内容的提问来源于stack exchange,提问作者Developer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 19:40:57