AnimatedOpacity透明度动画详解

在这里插入图片描述

AnimatedOpacity是Flutter中实现透明度过渡动画的专用隐式动画组件,它能够在opacity属性变化时自动执行平滑的透明度过渡。透明度动画是UI动画中最基础也是最常用的效果之一,能够实现元素的淡入淡出、显示隐藏等视觉效果。本文将深入探讨AnimatedOpacity的工作原理、使用场景和最佳实践。

一、透明度动画的重要性

透明度动画是UI设计中非常重要的视觉表现手段,它不仅能够美化界面,还能够传达状态信息和引导用户操作。理解透明度动画的作用和重要性,有助于在合适的场景下正确使用它。

状态指示是透明度动画的重要用途之一。通过改变元素的透明度,可以直观地表示元素的可用状态。例如,禁用的按钮可以降低透明度来表示不可点击状态,加载中的内容可以先隐藏再逐渐显示,完成操作的项目可以淡出以移除。这种视觉反馈让用户能够快速理解界面的当前状态,而无需阅读文字说明。

过渡效果是透明度动画的另一个核心用途。在页面切换、内容刷新、状态改变等场景中,使用透明度动画可以让过渡更加平滑自然。比如,从列表页到详情页的转场可以使用旧内容淡出、新内容淡入的效果;下拉刷新时,新的内容可以从透明逐渐变为完全不透明。这种过渡效果减少了界面的突变感,提升了用户体验的连贯性。

引导关注是透明度动画的第三个重要用途。通过淡入淡出的效果,可以引导用户的注意力到特定区域或元素上。例如,重要通知可以淡入吸引注意,弹出的提示可以在几秒后淡出避免干扰,新功能引导可以逐步淡入展示。这种视觉引导比静态的文字提示更加自然和有效。

层次表达是透明度动画的高级用途。通过调整不同元素的透明度,可以创造视觉上的层次感,让界面更加立体。例如,背景元素可以设置较低的透明度来突出前景,次要信息可以半透明显示以降低视觉权重,叠加层可以渐变透明实现融合效果。这种层次表达让界面更加丰富和专业。

透明度动画的应用场景可以通过下表进行总结:

应用场景 动画效果 作用 持续时间建议
禁用状态 不透明→半透明 表示不可用 200-300ms
加载中 透明→不透明 显示加载内容 300-500ms
移除项目 不透明→透明 平滑移除 300-400ms
页面转场 旧淡出/新淡入 平滑切换 400-600ms
提示消息 淡入→等待→淡出 临时通知 淡入200ms,等待2-3s,淡出300ms
引导元素 透明→不透明 吸引注意 400-600ms
背景层 半透明 突出前景 无动画,静态半透明

二、AnimatedOpacity的核心属性

AnimatedOpacity是一个相对简单的组件,它的属性不多,但每个属性都有其特定的作用和最佳实践。理解这些属性的作用,是正确使用AnimatedOpacity的前提。

opacity属性是最核心的属性,它指定了子Widget的透明度,取值范围是0.0到1.0。0.0表示完全透明(不可见),1.0表示完全不透明(正常显示)。当opacity值变化时,AnimatedOpacity会自动播放从旧值到新值的过渡动画。需要注意的是,opacity只影响子Widget及其子树的透明度,不会影响AnimatedOpacity自身占据的空间,即使opacity为0,子Widget仍然会占据布局空间。

duration属性指定动画的持续时间,是必需属性。合理的持续时间对于用户体验很重要,对于透明度动画,通常建议在200-500毫秒之间。太短的动画会让过渡显得突兀,用户可能来不及看清效果;太长的动画会显得拖沓,影响界面的响应性。对于淡入操作,可以稍短一些(200-300ms)以快速响应;对于淡出操作,可以稍长一些(300-500ms)让用户有足够的时间意识到变化。

curve属性指定动画的缓动曲线,默认为Curves.easeInOut。不同的曲线会产生不同的透明度变化节奏,线性曲线让透明度匀速变化,缓动曲线让透明度变化速度先慢后快再慢。对于透明度动画,通常使用easeInOut曲线比较自然,但也可以根据场景选择其他曲线。比如,淡入可以使用easeOut让显示更快速,淡出可以使用easeIn让消失更平缓。

child属性是要应用透明度动画的子Widget,是必需属性。这个子Widget及其所有后代都会受到影响,它们的透明度都会根据opacity值进行缩放。需要注意的是,opacity是通过RenderOpacity实现的,它使用颜色滤镜来调整透明度,这种方式性能较好但有一个限制:如果child是图片或视频,透明度的变化可能会导致颜色失真。

onEnd属性是一个回调函数,当动画完成时会被调用。这个属性在需要动画完成后执行某些操作时非常有用,比如在淡出动画完成后移除Widget,在淡入动画完成后启动其他动画。需要注意的是,onEnd只在动画正常完成时调用,如果动画被中断或取消,不会调用onEnd。

AnimatedOpacity核心属性的配置建议可以通过下表来参考:

属性 默认值 推荐设置 说明
opacity - 根据状态切换 0.0-1.0之间
duration 必需 200-500ms 淡入可短,淡出可长
curve Curves.easeInOut 根据场景选择 fadeIn用easeOut,fadeOut用easeIn
child 必需 任意Widget 会影响整个子树
onEnd null 需要时设置 动画完成回调

三、AnimatedOpacity的工作机制

AnimatedOpacity通过RenderOpacity实现透明度效果,当opacity属性变化时,它会创建一个内部AnimationController来管理过渡动画。这个过程对开发者是透明的,所有细节都由AnimatedOpacity自动处理。

RenderOpacity是Flutter的渲染层组件,它使用ColorFilter来调整子Widget的透明度。ColorFilter是图像处理中的一个概念,它可以在绘制时对像素的颜色应用矩阵变换,包括调整透明度。通过这种方式,RenderOpacity能够高效地实现透明度效果,而不需要重建子Widget或修改其属性。

当opacity值变化时,AnimatedOpacity会执行以下步骤:

opacity值变化

新旧值是否相同?

不执行动画

创建AnimationController

配置Tween从旧值到新值

启动动画

每帧更新opacity值

动画是否完成?

销毁Controller

调用onEnd回调

从流程图可以看出,AnimatedOpacity的动画管理是完全自动的,开发者只需改变opacity值,剩余的所有工作都由组件内部处理。

AnimatedOpacity的一个重要特性是它能处理opacity值的多次快速变化。如果在动画执行过程中,opacity值又发生了变化,AnimatedOpacity会取消当前动画,并启动一个新的动画到新的目标值。这种处理机制保证了最终的透明度总是与最新的opacity值一致,避免了动画状态不同步的问题。

另一个重要特性是即使opacity为0.0(完全透明),子Widget仍然会占据布局空间。这是因为opacity的实现方式不会影响布局计算,只是改变绘制时的透明度。如果需要在透明度为0时让Widget不占据空间,应该使用Visibility组件或Offstage组件。

四、透明度动画的常见模式

在实际应用中,透明度动画有一些常见的使用模式和最佳实践,掌握这些模式能够帮助开发者快速实现各种透明度效果。

开关模式是最基本的透明度动画模式,实现元素的显示和隐藏。通常使用布尔值状态来控制opacity,值为true时opacity为1.0,值为false时opacity为0.0。这种模式常用于实现菜单的展开收起、模态对话框的显示隐藏、列表项的展开折叠等功能。

bool _isVisible = true;

AnimatedOpacity(
  duration: const Duration(milliseconds: 300),
  opacity: _isVisible ? 1.0 : 0.0,
  child: Text('可以隐藏的文本'),
)

void _toggleVisibility() {
  setState(() {
    _isVisible = !_isVisible;
  });
}

渐变模式是实现元素逐渐显示或消失的动画,通常用于新内容加载、旧内容移除等场景。渐变模式的实现方式是让opacity从0.0逐渐增加到1.0(淡入),或者从1.0逐渐减小到0.0(淡出)。这种模式比开关模式更平滑,给人的视觉体验更好。

// 淡入效果
double _opacity = 0.0;


void initState() {
  super.initState();
  // 延迟执行淡入
  Future.delayed(const Duration(milliseconds: 100), () {
    setState(() {
      _opacity = 1.0;
    });
  });
}

AnimatedOpacity(
  duration: const Duration(milliseconds: 500),
  opacity: _opacity,
  curve: Curves.easeOut,
  child: YourWidget(),
)

脉冲模式是让元素周期性地闪烁,用于吸引用户注意力。实现方式是让opacity在一定范围内周期性变化,比如从0.5变化到1.0再回到0.5。这种模式常用于通知提示、状态指示等场景。脉冲动画的频率不宜过高,通常设置为1-2秒一个周期。

// 脉冲动画需要使用显式动画
late AnimationController _pulseController;
late Animation<double> _pulseAnimation;


void initState() {
  super.initState();
  _pulseController = AnimationController(
    duration: const Duration(seconds: 1),
    vsync: this,
  )..repeat(reverse: true);

  _pulseAnimation = Tween<double>(begin: 0.5, end: 1.0).animate(
    CurvedAnimation(parent: _pulseController, curve: Curves.easeInOut),
  );
}


void dispose() {
  _pulseController.dispose();
  super.dispose();
}

AnimatedBuilder(
  animation: _pulseAnimation,
  builder: (context, child) {
    return Opacity(
      opacity: _pulseAnimation.value,
      child: child,
    );
  },
  child: YourWidget(),
)

跟随模式是根据某个值的变化来动态调整opacity,实现透明度与其他属性的关联。比如,根据滚动位置调整顶部导航栏的透明度,根据距离目标的远近调整提示的透明度,根据音量大小调整音量指示器的透明度等。这种模式能够创造更加丰富和自然的交互体验。

// 根据滚动位置调整透明度
double _scrollPosition = 0.0;
final double _maxScroll = 300.0;


Widget build(BuildContext context) {
  return NotificationListener<ScrollNotification>(
    onNotification: (notification) {
      setState(() {
        _scrollPosition = notification.metrics.pixels;
      });
      return false;
    },
    child: ListView(
      children: [
        AnimatedOpacity(
          duration: const Duration(milliseconds: 100),
          opacity: (_scrollPosition / _maxScroll).clamp(0.0, 1.0),
          child: AppBar(
            title: const Text('滚动渐变的标题栏'),
          ),
        ),
        // 其他内容
      ],
    ),
  );
}

透明度动画常见模式的对比可以通过下表来体现:

模式 实现方式 典型场景 动画时长 复杂度
开关模式 布尔值→opacity值 显示/隐藏 200-400ms
渐变模式 0→1或1→0 加载/移除 300-600ms
脉冲模式 周期性变化 提示/通知 1-2s周期
跟随模式 值映射到opacity 滚动/位置 动态

五、AnimatedOpacity的嵌套与组合

AnimatedOpacity可以与其他隐式动画组件嵌套或组合使用,实现更复杂的动画效果。这种组合能够同时控制多个属性的动画,创造出更加丰富的视觉效果。

与AnimatedContainer组合是常见的组合方式,可以同时实现透明度和尺寸/颜色/圆角等属性的变化。比如,淡入的同时放大容器,淡出的同时缩小容器;显示时背景色从浅到深,消失时背景色从深到浅。这种组合方式能够让过渡效果更加丰富和协调。

与AnimatedPadding组合可以实现透明度和内边距的同时变化。比如,淡入的同时增加内边距让内容展开,淡出的同时减少内边距让内容收缩。这种组合方式常用于实现卡片展开收起的效果。

与AnimatedAlign组合可以实现透明度和位置的同时变化。比如,淡入的同时从边缘移动到中心,淡出的同时从中心移动到边缘。这种组合方式常用于实现元素的进场和出场动画。

多层嵌套可以实现多个属性的独立控制。比如,外层AnimatedOpacity控制整体透明度,内层AnimatedContainer控制尺寸变化,更内层AnimatedOpacity控制某个子元素的透明度。这种多层嵌套的优点是每个属性的动画独立控制,互不影响;缺点是嵌套层次过多会影响代码可读性和性能。

AnimatedOpacity组合方式的对比可以通过下表来参考:

组合方式 效果 优点 缺点 适用场景
AnimatedContainer 透明度+尺寸/颜色 效果丰富 代码稍复杂 卡片展开/收起
AnimatedPadding 透明度+内边距 展开收缩自然 场景局限 内容区域动画
AnimatedAlign 透明度+位置 进场出场效果好 需要位置计算 元素进场/出场
多层嵌套 多属性独立控制 灵活性高 代码复杂 复杂过渡效果

六、性能优化与注意事项

虽然AnimatedOpacity的性能总体良好,但在某些场景下仍需要注意性能问题和一些特殊的注意事项,确保动画流畅运行。

避免频繁的opacity变化是首要的性能建议。opacity变化会触发重绘,虽然RenderOpacity的实现已经优化,但如果opacity值频繁变化,仍然会对性能产生影响。特别是在列表或GridView中,如果每个item都有AnimatedOpacity且同时变化,可能会造成卡顿。这种情况下,应该考虑使用ListView.builder或其他方式优化列表渲染。

使用Opacity代替AnimatedOpacity是另一种优化建议。如果opacity值不变化或者变化后不再需要动画,应该直接使用Opacity组件而不是AnimatedOpacity。Opacity没有动画能力,也没有动画相关的开销,性能更好。这个建议也适用于其他隐式动画组件:如果不需要动画,使用对应的非动画版本。

注意ColorFilter的限制是一个重要的注意事项。RenderOpacity使用ColorFilter实现透明度,这种方式对于大多数组件效果很好,但对于图片和视频可能导致颜色失真。特别是当opacity不是0.0或1.0时,图片的颜色可能会发生变化。如果需要精确的颜色,应该考虑其他实现方式,比如直接修改图片的颜色值。

考虑替代方案是在某些场景下的必要考虑。虽然AnimatedOpacity很方便,但它不是唯一的透明度解决方案。在某些性能敏感的场景,可以考虑使用ShaderMask或自定义RenderObject来实现透明度效果。这些替代方案可能有更好的性能,但实现复杂度也更高。

性能优化的具体措施可以通过下表来总结:

优化措施 适用场景 实现方式 预期效果
避免频繁变化 列表/Grid 减少opacity变化次数 降低重绘开销
使用Opacity 不需要动画 替换AnimatedOpacity 消除动画开销
使用Visibility 完全隐藏 条件渲染 节省布局计算
使用Offstage 不占空间 包装AnimatedOpacity 节省布局空间
ShaderMask 图片视频 替代ColorFilter 避免颜色失真

七、常见应用场景示例

理解AnimatedOpacity的应用场景能够帮助开发者在合适的时机使用它,实现更好的用户体验。以下是一些常见且实用的应用场景。

按钮禁用状态是最常见的应用场景之一。当按钮被禁用时,可以降低透明度(如0.5)来表示不可点击状态,同时配合灰化效果。这种视觉反馈比简单的文字提示更加直观和及时。实现方式是根据按钮的enabled状态设置opacity值,enabled为true时opacity为1.0,为false时opacity为0.5。

bool _isEnabled = true;

AnimatedOpacity(
  duration: const Duration(milliseconds: 200),
  opacity: _isEnabled ? 1.0 : 0.5,
  child: ElevatedButton(
    onPressed: _isEnabled ? _onPressed : null,
    style: ElevatedButton.styleFrom(
      backgroundColor: _isEnabled ? Colors.blue : Colors.grey,
    ),
    child: const Text('可禁用的按钮'),
  ),
)

加载状态指示是另一个常见场景。在数据加载过程中,可以先用透明度0.5的占位符显示内容,数据加载完成后将opacity改为1.0实现淡入效果。这种方式让用户知道内容正在加载,同时平滑的过渡不会产生视觉突变。

bool _isLoading = true;
String _content = '';

Future<void> _loadData() async {
  setState(() => _isLoading = true);
  
  // 模拟数据加载
  await Future.delayed(const Duration(seconds: 2));
  
  setState(() {
    _isLoading = false;
    _content = '加载完成的内容';
  });
}

AnimatedOpacity(
  duration: const Duration(milliseconds: 300),
  opacity: _isLoading ? 0.5 : 1.0,
  child: _isLoading 
    ? _buildLoadingPlaceholder()
    : Text(_content),
)

列表项移除场景中,当用户删除列表项时,可以先通过opacity从1.0渐变到0.0实现淡出效果,然后从列表中移除该项。这种平滑的移除效果比直接删除更加友好。实现方式是在确认删除后先执行淡出动画,动画完成后再从数据源中移除并刷新列表。

List<Item> _items = [];

Future<void> _removeItem(int index) async {
  final item = _items[index];
  
  // 先移除该项
  setState(() {
    _items.removeAt(index);
  });
  
  // 添加淡出动画
  if (mounted) {
    await Future.delayed(const Duration(milliseconds: 300));
  }
}

// 在列表中使用
AnimatedOpacity(
  duration: const Duration(milliseconds: 300),
  opacity: _items.contains(item) ? 1.0 : 0.0,
  onEnd: () {
    if (!_items.contains(item)) {
      // 动画完成后的清理工作
    }
  },
  child: ListItemWidget(item: item),
)

模态对话框的显示隐藏通常使用透明度动画。对话框显示时先淡入背景遮罩(从透明到半透明),再淡入对话框内容(从透明到不透明);对话框隐藏时先淡出内容,再淡出遮罩。这种分层淡入淡出的效果比同时显示隐藏更加自然。

void _showDialog() {
  showGeneralDialog(
    context: context,
    barrierDismissible: true,
    barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel,
    transitionDuration: const Duration(milliseconds: 300),
    pageBuilder: (context, animation, secondaryAnimation) {
      return FadeTransition(
        opacity: CurvedAnimation(
          parent: animation,
          curve: Curves.easeOut,
        ),
        child: const DialogContent(),
      );
    },
    transitionBuilder: (context, animation, secondaryAnimation, child) {
      return FadeTransition(
        opacity: CurvedAnimation(
          parent: animation,
          curve: Curves.easeOut,
        ),
        child: child,
      );
    },
  );
}

消息提示的显示隐藏是另一个典型场景。提示消息出现时淡入显示,停留几秒后自动淡出消失。淡入时间可以短一些(200ms)以快速显示,停留时间根据消息重要性调整(2-5s),淡出时间可以稍长一些(300ms)让用户有时间注意到变化。

class ToastMessage extends StatefulWidget {
  final String message;
  final Duration duration;

  const ToastMessage({
    super.key,
    required this.message,
    this.duration = const Duration(seconds: 3),
  });

  
  State<ToastMessage> createState() => _ToastMessageState();
}

class _ToastMessageState extends State<ToastMessage> 
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<double> _animation;

  
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: const Duration(milliseconds: 200),
      vsync: this,
    );
    
    _animation = Tween<double>(begin: 0.0, end: 1.0).animate(
      CurvedAnimation(parent: _controller, curve: Curves.easeOut),
    );
    
    // 淡入
    _controller.forward();
    
    // 自动淡出
    Future.delayed(widget.duration, _fadeOut);
  }

  Future<void> _fadeOut() async {
    await _controller.reverse();
    if (mounted) {
      Navigator.of(context).pop();
    }
  }

  
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  
  Widget build(BuildContext context) {
    return FadeTransition(
      opacity: _animation,
      child: Container(
        padding: const EdgeInsets.all(16),
        decoration: BoxDecoration(
          color: Colors.black87,
          borderRadius: BorderRadius.circular(8),
        ),
        child: Text(
          widget.message,
          style: const TextStyle(color: Colors.white),
        ),
      ),
    );
  }
}

这些应用场景的实现要点可以通过下表来参考:

场景 淡入时间 淡出时间 停留时间 特殊处理
按钮禁用 200ms 200ms - 配合颜色灰化
加载状态 300ms - - 配合加载指示器
列表项移除 - 300-400ms - 动画后移除
模态对话框 300ms 300ms - 分层淡入淡出
消息提示 200ms 300ms 2-5s 自动隐藏

八、AnimatedOpacity的局限性与替代方案

尽管AnimatedOpacity使用方便,但它也有一些局限性,了解这些局限性有助于在选择透明度方案时做出正确的决策。

无法精确控制动画时机是AnimatedOpacity的主要局限。动画是自动启动的,开发者无法精确控制动画何时开始、何时停止、何时暂停。如果需要精确的时机控制,需要使用显式动画,如AnimationController配合Tween。

无法实现复杂的透明度变化模式是另一个局限。AnimatedOpacity只支持从旧值到新值的简单过渡,如果需要实现如透明度先增后减、周期性变化等复杂模式,需要使用显式动画或组合多个AnimatedOpacity。

在图片上可能导致颜色失真是技术层面的局限。由于使用ColorFilter实现,当opacity不是0.0或1.0时,图片的颜色可能会发生变化。对于需要精确颜色的场景,应该考虑其他实现方式。

性能不如经过优化的显式动画是性能层面的局限。虽然AnimatedOpacity已经优化,但显式动画可以通过针对特定场景的优化获得更好的性能。对于性能要求极高的场景,显式动画可能有优势。

AnimatedOpacity与其他透明度方案的对比可以通过下表来体现:

方案 代码复杂度 性能 灵活性 控制精度 适用场景
AnimatedOpacity 简单淡入淡出
AnimationController 复杂模式、精确控制
Opacity组件 最高 静态透明度
ShaderMask 图片视频精确透明度
自定义RenderObject 最高 最高 特殊需求

九、示例案例:多元素透明度动画演示

本示例演示了AnimatedOpacity的基本使用方法,包括多个元素同时变化透明度的效果。示例中创建三个不同颜色的容器,通过切换它们的opacity值实现淡入淡出效果,展示了如何使用AnimatedOpacity实现多个元素的协调动画。

示例代码

import 'package:flutter/material.dart';

class AnimatedOpacityDemo extends StatefulWidget {
  const AnimatedOpacityDemo({super.key});

  
  State<AnimatedOpacityDemo> createState() => _AnimatedOpacityDemoState();
}

class _AnimatedOpacityDemoState extends State<AnimatedOpacityDemo> {
  double _opacity1 = 1.0;
  double _opacity2 = 0.3;
  double _opacity3 = 1.0;

  void _toggleOpacity() {
    setState(() {
      _opacity1 = _opacity1 == 1.0 ? 0.2 : 1.0;
      _opacity2 = _opacity2 == 0.3 ? 1.0 : 0.3;
      _opacity3 = _opacity3 == 1.0 ? 0.0 : 1.0;
    });
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('AnimatedOpacity'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                AnimatedOpacity(
                  duration: const Duration(milliseconds: 800),
                  opacity: _opacity1,
                  curve: Curves.easeInOut,
                  child: Container(
                    width: 100,
                    height: 100,
                    decoration: BoxDecoration(
                      color: Colors.red,
                      borderRadius: BorderRadius.circular(15),
                    ),
                  ),
                ),
                AnimatedOpacity(
                  duration: const Duration(milliseconds: 800),
                  opacity: _opacity2,
                  curve: Curves.easeInOut,
                  child: Container(
                    width: 100,
                    height: 100,
                    decoration: BoxDecoration(
                      color: Colors.green,
                      borderRadius: BorderRadius.circular(15),
                    ),
                  ),
                ),
                AnimatedOpacity(
                  duration: const Duration(milliseconds: 800),
                  opacity: _opacity3,
                  curve: Curves.easeInOut,
                  child: Container(
                    width: 100,
                    height: 100,
                    decoration: BoxDecoration(
                      color: Colors.blue,
                      borderRadius: BorderRadius.circular(15),
                    ),
                  ),
                ),
              ],
            ),
            const SizedBox(height: 40),
            ElevatedButton(
              onPressed: _toggleOpacity,
              child: const Text('切换透明度'),
            ),
          ],
        ),
      ),
    );
  }
}

示例说明

这个示例展示了AnimatedOpacity的多元素使用:

  1. 定义三个透明度状态变量: 分别控制三个容器的透明度
  2. 创建三个AnimatedOpacity: 每个包装一个不同颜色的容器
  3. 设置动画参数: duration为800毫秒,curve为easeInOut
  4. 切换透明度: 点击按钮时同时切换三个容器的opacity值

三个容器的透明度变化模式不同:

  • 红色容器: 在1.0和0.2之间切换
  • 绿色容器: 在0.3和1.0之间切换(初始状态就是半透明)
  • 蓝色容器: 在1.0和0.0之间切换(可以完全消失)

所有容器的透明度变化都使用easeInOut曲线,让开始和结束都慢,中间快,呈现自然流畅的效果。动画时长设置为800毫秒,给用户足够的时间观察变化。

这个示例清晰地展示了AnimatedOpacity的简单用法:只需改变opacity值,透明度动画会自动执行,无需手动管理动画状态。同时,多个AnimatedOpacity可以同时使用,实现协调的多元素动画效果。

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐