自定义组件间如何实现从底部滑入滑出的效果?

问题描述

一个页面底部默认显示自定义组件A,点击自定义组件A,则A消失,自定义组件B从底部出现;点击自定义组件B,则组件B消失,A从底部出现。这个效果要如何实现?

阅读 847
avatarAI BotBETA

要实现这个效果,你可以使用动画和视图切换的方式。以下是一个基本的实现思路:

  1. 创建自定义组件:首先,你需要创建两个自定义组件A和B。你可以使用React Native的组件来创建这些组件。
  2. 设置动画:使用React Native的动画库(例如react-native-animatableAnimated API)为组件的进出添加动画效果。例如,你可以创建一个从底部滑入滑出的动画。
  3. 控制组件的显示与隐藏:在点击事件中,通过改变状态来控制组件的显示与隐藏。例如,当点击组件A时,可以设置一个状态变量来控制组件A的显示与隐藏,同时触发动画效果。
  4. 切换组件:根据状态变量的值,切换显示不同的组件。如果状态变量表示要显示组件B,则隐藏组件A并显示组件B,同时触发相应的动画效果。

下面是一个简单的示例代码:

import React, { useState } from 'react';
import { View, Animated, TouchableOpacity } from 'react-native';

// 创建自定义组件A和B
const ComponentA = () => <View>Component A</View>;
const ComponentB = () => <View>Component B</View>;

// 实现切换逻辑
const ToggleComponent = () => {
  const [isComponentAVisible, setComponentAVisible] = useState(true);
  const animation = Animated.createValue(0);

  const toggleComponent = () => {
    setComponentAVisible(!isComponentAVisible);
    animation.setValue(isComponentAVisible ? 1 : 0); // 设置动画值
    Animated.timing(animation, {
      toValue: isComponentAVisible ? 0 : 1, // 动画目标值
      duration: 300, // 动画持续时间
      useNativeDriver: true, // 使用原生驱动以获得更好的性能
    }).start(); // 开始动画
  };

  return (
    <View>
      {isComponentAVisible && (
        <Animated.View style={{ bottom: animation }}>
          <TouchableOpacity onPress={toggleComponent}>
            <ComponentA />
          </TouchableOpacity>
        </Animated.View>
      )}
      {!isComponentAVisible && (
        <Animated.View style={{ bottom: 0 }}>
          <TouchableOpacity onPress={toggleComponent}>
            <ComponentB />
          </TouchableOpacity>
        </Animated.View>
      )}
    </View>
  );
};

这个示例代码创建了两个简单的自定义组件(ComponentAComponentB),并通过使用Animated API为它们添加了从底部滑入滑出的动画效果。通过控制isComponentAVisible状态变量,可以切换显示不同的组件,并触发相应的动画效果。

1 个回答

解决措施

可以使用transition产生组件转场动画,其参数type用来设置组件变化场景,包括新增和删除;参数translate用来设置转场时的平移效果。注意transition需要配合animateTo才能生效,动效时长、曲线、延时跟随animateTo中的配置。

代码示例

@Entry 
@Component 
struct ComponentTransition { 
  @State flag: boolean = true; 
 
  build() { 
    Stack({ alignContent: Alignment.Bottom }) { 
        if (this.flag) { 
          ComponentChild1({ flag: $flag }) 
            .transition({ type: TransitionType.Insert,translate: { x: 0, y: 200 } }) 
        } 
        if (!this.flag) { 
          ComponentChild2({ flag: $flag }) 
            .transition({ type: TransitionType.Insert, translate: { x: 0, y: 200 } }) 
        } 
    }.height('100%').width('100%') 
  } 
} 
 
@Component 
struct ComponentChild1 { 
  @Link flag: boolean 
 
  build() { 
    Column() { 
      Image($r('app.media.ic_banner01'))//resources\base\media路径 
        .width('100%') 
        .height(200) 
        .onClick(() => { 
          animateTo({ duration: 1000 }, () => { 
            this.flag = !this.flag; 
          }) 
        }) 
    } 
  } 
} 
 
@Component 
struct ComponentChild2 { 
  @Link flag: boolean 
 
  build() { 
    Column() { 
      Image($r('app.media.ic_banner02'))//resources\base\media路径 
        .width('100%') 
        .height(200) 
        .onClick(() => { 
          animateTo({ duration: 1000 }, () => { 
            this.flag = !this.flag; 
          }) 
        }) 
    } 
  } 
}

参考链接

组件内转场

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进