Stack动画应用

在这里插入图片描述

Stack动画应用

一、Stack动画概述

Stack组件与Flutter动画系统完美结合,可以实现各种流畅的视觉效果。通过AnimatedPositioned、AnimatedOpacity、AnimatedContainer等组件,可以创建出丰富的动画体验。动画是现代应用不可或缺的组成部分,它不仅能够提升视觉吸引力,还能够改善用户体验,使界面交互更加自然和直观。

在跨平台应用开发中,动画的重要性不言而喻。无论是Android、iOS还是鸿蒙平台,用户都期望应用具有流畅的动画效果。Flutter的动画系统为开发者提供了强大而灵活的API,使得创建复杂的动画效果变得简单。Stack作为Flutter中重要的布局组件,与动画系统的结合更是为开发者提供了无限的创作可能。

Stack动画类型

Stack动画

位置动画

透明度动画

尺寸动画

组合动画

AnimatedPositioned

平移效果

滑动过渡

位置切换

AnimatedOpacity

渐入渐出

闪烁效果

淡入淡出

AnimatedContainer

缩放效果

尺寸变化

形变动画

多属性同时动画

序列动画

复杂过渡

交互反馈

Stack动画的核心是通过改变子组件的属性值,触发Flutter的动画系统自动计算过渡效果。这种方式简单直观,不需要手动编写动画插值逻辑,开发者只需要关注起始状态和结束状态,中间的过渡过程由Flutter自动处理。

动画的基本原理

Flutter的动画系统基于几个核心概念:Animation、AnimationController、Curve和Tween。这些组件共同工作,实现了从初始状态到最终状态的平滑过渡。

动画核心概念:

概念 说明 作用
Animation 表示动画的当前值 生成动画过程中的值
AnimationController 控制动画的播放 管理动画的开始、停止、重复
Curve 定义动画的时间曲线 控制动画的速度变化
Tween 定义动画的值范围 在两个值之间进行插值

Stack动画的优势

使用Stack进行动画具有多方面的优势:

优势 说明 应用场景
简洁性 代码简洁,易于理解 快速实现动画效果
性能 优化过的渲染性能 复杂动画场景
灵活性 可以组合多种动画 创意动画效果
响应式 自动适应不同屏幕 跨平台适配
可维护性 代码结构清晰 大型项目维护

二、AnimatedPositioned详解

AnimatedPositioned是Positioned的动画版本,它可以在位置和尺寸变化时自动创建平滑的过渡动画。这是Stack动画中最常用的组件之一。

AnimatedPositioned属性表

属性 类型 说明 必需 默认值
left double 左边缘距离 null
top double 上边缘距离 null
right double 右边缘距离 null
bottom double 下边缘距离 null
width double 宽度 null
height double 高度 null
duration Duration 动画时长 -
curve Curve 动画曲线 Curves.linear
onEnd VoidCallback 动画结束回调 null
child Widget 子组件 -

常用动画曲线对比表

曲线名称 效果描述 适用场景 持续时间建议
Curves.linear 线性匀速 机械运动 较长(500-1000ms)
Curves.easeIn 慢速开始 进入动画 中等(300-500ms)
Curves.easeOut 慢速结束 离开动画 中等(300-500ms)
Curves.easeInOut 两端慢速中间快 通用过渡 标准(400-600ms)
Curves.elasticIn 弹性进入 强调效果 较长(800-1200ms)
Curves.bounceIn 弹跳进入 有趣动画 较长(800-1200ms)
Curves.fastOutSlowIn 快出慢进 Material风格 标准(300-400ms)
Curves.decelerate 减速 滑动结束 短(200-300ms)

动画时长选择指南

动画类型 推荐时长 说明
微交互(按钮反馈) 100-200ms 快速响应,不影响操作
切换动画 200-400ms 流畅过渡,不过分拖沓
展开收起 300-500ms 给用户足够的时间感知变化
页面切换 400-600ms 平滑过渡,保持连续性
强调动画 500-800ms 引起注意,不造成干扰
特殊效果 800-1200ms 创意展示,避免过长

三、实际案例代码

来自main.dart的_Page04Animated类

以下是一个完整的AnimatedPositioned示例,展示了如何实现卡片展开收起的动画效果:

// lib/main.dart 451-541行
class _Page04Animated extends StatefulWidget {
  const _Page04Animated();

  
  State<_Page04Animated> createState() => _Page04AnimatedState();
}

class _Page04AnimatedState extends State<_Page04Animated> {
  bool _isExpanded = false;

  void _toggleExpand() {
    setState(() {
      _isExpanded = !_isExpanded;
    });
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Stack动画'),
        backgroundColor: Colors.orange,
        foregroundColor: Colors.white,
      ),
      body: Column(
        children: [
          const SizedBox(height: 20),
          ElevatedButton(
            onPressed: _toggleExpand,
            child: Text(_isExpanded ? '收起' : '展开'),
          ),
          const SizedBox(height: 40),
          Center(
            child: SizedBox(
              width: 300,
              height: 300,
              child: Stack(
                children: [
                  // 背景容器
                  Positioned.fill(
                    child: Container(
                      decoration: BoxDecoration(
                        border: Border.all(color: Colors.grey, width: 2),
                        color: Colors.grey[200],
                      ),
                      child: const Center(child: Text('动画区域')),
                    ),
                  ),
                  // 动画方块
                  AnimatedPositioned(
                    duration: const Duration(milliseconds: 500),
                    curve: Curves.easeInOut,
                    left: _isExpanded ? 20 : 100,
                    top: _isExpanded ? 20 : 100,
                    width: _isExpanded ? 260 : 100,
                    height: _isExpanded ? 260 : 100,
                    child: Container(
                      decoration: BoxDecoration(
                        gradient: const LinearGradient(
                          colors: [Colors.orange, Colors.deepOrange],
                        ),
                        borderRadius: BorderRadius.circular(12),
                        boxShadow: [
                          BoxShadow(
                            color: Colors.orange.withOpacity(0.4),
                            blurRadius: 12,
                          ),
                        ],
                      ),
                      child: Center(
                        child: Text(
                          _isExpanded ? '展开状态' : '收起状态',
                          style: const TextStyle(
                            color: Colors.white,
                            fontSize: 20,
                            fontWeight: FontWeight.bold,
                          ),
                        ),
                      ),
                    ),
                  ),
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }
}

案例解析

这个案例展示了AnimatedPositioned的基本使用方法,实现了卡片从中心到角落的展开收起效果。

关键技术点:

  1. 状态管理

    • 使用_isExpanded布尔值控制动画状态
    • 通过setState触发状态更新
    • 根据状态计算不同的属性值
  2. AnimatedPositioned配置

    • duration设置为500毫秒,动画时长适中
    • 使用Curves.easeInOut曲线,两端平滑
    • 同时动画位置和尺寸
  3. 动画属性变化

    • left: 100→20 (从中心向左移动)
    • top: 100→20 (从中心向上移动)
    • width: 100→260 (宽度展开)
    • height: 100→260 (高度展开)
  4. 视觉设计

    • 使用渐变色增强视觉效果
    • 添加阴影增加立体感
    • 文字内容随状态变化

案例动画流程

初始状态
收起

用户点击展开

AnimatedPositioned开始动画

left: 100→20
top: 100→20

width: 100→260
height: 100→260

容器平滑移动

容器平滑展开

动画完成

展开状态显示
isExpanded = true

用户点击收起

反向动画执行

left: 20→100
top: 20→100

width: 260→100
height: 260→100

返回初始状态

四、Stack动画类型详解

1. 位置动画

位置动画是Stack动画中最常见的类型,通过改变子组件的位置实现移动效果。

技术组件 属性变化 效果 应用场景 实现难度
AnimatedPositioned left/top/right/bottom 平滑移动 卡片展开、抽屉效果 简单
AnimatedContainer transform 旋转缩放 按钮效果、指示器 中等
AnimatedAlign alignment 位置切换 选项卡切换 简单
Tween + AnimationController 自定义属性值 复杂运动 自定义轨迹 较难

位置动画代码示例:

class PositionAnimationExample extends StatefulWidget {
  
  _PositionAnimationExampleState createState() => _PositionAnimationExampleState();
}

class _PositionAnimationExampleState extends State<PositionAnimationExample> {
  bool _moved = false;

  
  Widget build(BuildContext context) {
    return Stack(
      children: [
        AnimatedPositioned(
          duration: Duration(milliseconds: 300),
          curve: Curves.easeInOut,
          left: _moved ? 50 : 0,
          top: _moved ? 50 : 0,
          child: Container(
            width: 100,
            height: 100,
            color: Colors.blue,
          ),
        ),
        ElevatedButton(
          onPressed: () => setState(() => _moved = !_moved),
          child: Text('移动'),
        ),
      ],
    );
  }
}

2. 透明度动画

透明度动画通过改变子组件的opacity属性,实现渐入渐出效果。

AnimatedOpacity

opacity: 0→1

淡入效果
Fade In

opacity: 1→0

淡出效果
Fade Out

opacity: 0→1→0

闪烁效果
Blink

应用: 提示消息

应用: 对话框关闭

应用: 加载指示

透明度动画代码示例:

class OpacityAnimationExample extends StatefulWidget {
  
  _OpacityAnimationExampleState createState() => _OpacityAnimationExampleState();
}

class _OpacityAnimationExampleState extends State<OpacityAnimationExample> {
  bool _visible = false;

  
  Widget build(BuildContext context) {
    return Stack(
      children: [
        AnimatedOpacity(
          opacity: _visible ? 1.0 : 0.0,
          duration: Duration(milliseconds: 300),
          child: Container(
            width: 100,
            height: 100,
            color: Colors.green,
          ),
        ),
        ElevatedButton(
          onPressed: () => setState(() => _visible = !_visible),
          child: Text('显示/隐藏'),
        ),
      ],
    );
  }
}

3. 尺寸动画

尺寸动画通过改变子组件的宽度和高度,实现缩放效果。

属性 效果 使用方法 应用场景
width/height 尺寸变化 AnimatedPositioned中设置 展开/收起
transform.scale 整体缩放 Matrix4.scale 按钮反馈
borderRadius 圆角变化 AnimatedContainer 形状变换

尺寸动画代码示例:

class SizeAnimationExample extends StatefulWidget {
  
  _SizeAnimationExampleState createState() => _SizeAnimationExampleState();
}

class _SizeAnimationExampleState extends State<SizeAnimationExample> {
  bool _expanded = false;

  
  Widget build(BuildContext context) {
    return Stack(
      children: [
        AnimatedPositioned(
          duration: Duration(milliseconds: 400),
          curve: Curves.easeInOut,
          left: 100,
          top: 100,
          width: _expanded ? 200 : 100,
          height: _expanded ? 200 : 100,
          child: Container(
            color: Colors.purple,
          ),
        ),
        ElevatedButton(
          onPressed: () => setState(() => _expanded = !_expanded),
          child: Text('缩放'),
        ),
      ],
    );
  }
}

五、组合动画技巧

多属性同时动画

AnimatedPositioned的一个强大特性是可以同时动画多个属性,创建出丰富的复合效果。

AnimatedPositioned

位置变化

尺寸变化

子组件动画

AnimatedOpacity

AnimatedContainer

平滑过渡

复合效果

丰富动画

动画组合模式表

模式 技术方案 效果 适用场景 复杂度
位置+尺寸 AnimatedPositioned同时改变 展开/收起 卡片详情、面板 简单
位置+透明度 AnimatedPositioned + AnimatedOpacity 平滑出现 提示框、Toast 中等
尺寸+圆角 AnimatedPositioned + AnimatedContainer 形变效果 按钮、指示器 中等
位置+旋转 AnimatedPositioned + Transform 旋转移动 签到按钮 中等
多层同时 多个Animated组件 复杂过渡 列表进入 较高

组合动画代码示例

class CombinedAnimationExample extends StatefulWidget {
  
  _CombinedAnimationExampleState createState() => _CombinedAnimationExampleState();
}

class _CombinedAnimationExampleState extends State<CombinedAnimationExample> {
  bool _expanded = false;

  
  Widget build(BuildContext context) {
    return Stack(
      children: [
        AnimatedPositioned(
          duration: Duration(milliseconds: 400),
          curve: Curves.easeInOut,
          left: _expanded ? 50 : 150,
          top: _expanded ? 50 : 150,
          width: _expanded ? 200 : 100,
          height: _expanded ? 200 : 100,
          child: AnimatedOpacity(
            duration: Duration(milliseconds: 400),
            opacity: _expanded ? 1.0 : 0.5,
            child: AnimatedContainer(
              duration: Duration(milliseconds: 400),
              decoration: BoxDecoration(
                gradient: LinearGradient(
                  colors: _expanded
                      ? [Colors.blue, Colors.purple]
                      : [Colors.blue[200]!, Colors.purple[200]!],
                ),
                borderRadius: BorderRadius.circular(_expanded ? 20 : 10),
              ),
              child: Center(
                child: Text(
                  _expanded ? '展开' : '收起',
                  style: TextStyle(
                    color: Colors.white,
                    fontSize: _expanded ? 24 : 16,
                  ),
                ),
              ),
            ),
          ),
        ),
        ElevatedButton(
          onPressed: () => setState(() => _expanded = !_expanded),
          child: Text('切换'),
        ),
      ],
    );
  }
}

六、动画性能优化

性能优化原则

虽然Flutter的动画系统已经做了很多优化,但在某些情况下还是需要注意性能问题,特别是当动画涉及大量组件或复杂效果时。

优化原则:

  1. 减少动画组件数量

    • 只动画必要的组件
    • 避免全Stack动画
    • 使用RepaintBoundary隔离
  2. 优化动画属性

    • 选择合适的时长
    • 使用简单的曲线
    • 避免频繁的状态变化
  3. 使用const构造函数

    • 静态组件使用const
    • 减少不必要的重建
    • 提高渲染效率
  4. 选择合适的动画组件

    • 简单动画用AnimatedX组件
    • 复杂动画用AnimationController
    • 避免过度动画

优化策略对比表

优化项 优化前 优化后 性能提升
动画时长 1000ms 400ms 减少60%
const使用 0% 80% 提升约30%
动画范围 整个Stack 部分组件 减少重建80%
动画曲线 复杂曲线 简单曲线 提升约20%
重绘区域 整个屏幕 组件区域 减少重绘90%

动画性能诊断流程

动画性能问题

帧率低于60fps?

检查动画组件数量

CPU占用高?

组件数量过多?

减少动画组件

使用const?

优化完成

添加const构造

动画时长过长?

动画复杂?

简化动画效果

检查其他性能瓶颈

缩短动画时长

检查重绘区域

使用RepaintBoundary

性能优化代码示例

优化前:

// 没有使用const,动画整个Stack
Stack(
  children: [
    AnimatedPositioned(
      duration: Duration(milliseconds: 1000),
      left: _left,
      top: _top,
      child: Container(
        width: 200,
        height: 200,
        color: Colors.blue,
        child: Column(
          children: [
            Text('标题'),
            Text('描述'),
            Text('更多内容'),
          ],
        ),
      ),
    ),
  ],
)

优化后:

// 使用const,减少重绘
Stack(
  children: [
    AnimatedPositioned(
      duration: const Duration(milliseconds: 400),
      curve: Curves.easeOut,
      left: _left,
      top: _top,
      child: RepaintBoundary(
        child: Container(
          width: 200,
          height: 200,
          color: Colors.blue,
          child: const Column(
            children: [
              Text('标题'),
              Text('描述'),
              Text('更多内容'),
            ],
          ),
        ),
      ),
    ),
  ],
)

七、常见动画场景

场景与实现对照表

场景 推荐组件 技术要点 难度 适用性
卡片展开 AnimatedPositioned 同时改变位置和尺寸 简单
列表项进入 AnimatedOpacity + SlideTransition 组合使用 中等
加载状态 AnimatedContainer + 旋转 持续动画 中等
删除动画 AnimatedSize + fadeOut 尺寸收缩+透明度 中等
页面切换 Hero + AnimatedOpacity 过渡效果 中等
按钮反馈 AnimatedContainer 颜色或缩放变化 简单
提示消息 AnimatedOpacity + AnimatedPositioned 淡入淡出+移动 中等

场景1: 卡片展开动画

卡片展开动画是Stack动画中最常见的应用场景之一,用于显示更多详细信息。

实现要点:

要点 说明 推荐值
动画时长 不宜过长 300-500ms
动画曲线 两端平滑 Curves.easeInOut
内容过渡 配合文字淡入淡出 AnimatedOpacity
阴影变化 展开时增强阴影 elevation增加

卡片展开代码示例:

class CardExpandExample extends StatefulWidget {
  
  _CardExpandExampleState createState() => _CardExpandExampleState();
}

class _CardExpandExampleState extends State<CardExpandExample> {
  bool _expanded = false;

  
  Widget build(BuildContext context) {
    return Stack(
      children: [
        // 展开的完整卡片
        if (_expanded)
          AnimatedPositioned(
            duration: const Duration(milliseconds: 400),
            curve: Curves.easeInOut,
            left: 0,
            right: 0,
            top: 0,
            bottom: 0,
            child: Card(
              elevation: 8,
              child: Padding(
                padding: EdgeInsets.all(16),
                child: Column(
                  children: [
                    Text('标题'),
                    SizedBox(height: 8),
                    Text('展开后的详细内容...'),
                  ],
                ),
              ),
            ),
          ),
        // 收起的摘要卡片
        if (!_expanded)
          AnimatedPositioned(
            duration: const Duration(milliseconds: 400),
            curve: Curves.easeInOut,
            left: 50,
            top: 50,
            child: Card(
              elevation: 4,
              child: Padding(
                padding: EdgeInsets.all(16),
                child: Text('摘要内容'),
              ),
            ),
          ),
        // 触发按钮
        Positioned(
          right: 16,
          top: 16,
          child: IconButton(
            icon: Icon(_expanded ? Icons.close : Icons.expand),
            onPressed: () => setState(() => _expanded = !_expanded),
          ),
        ),
      ],
    );
  }
}

场景2: 列表项进入动画

列表项进入动画可以提升列表的视觉吸引力,使界面更加生动。

列表进入代码示例:

class ListEnterAnimation extends StatefulWidget {
  
  _ListEnterAnimationState createState() => _ListEnterAnimationState();
}

class _ListEnterAnimationState extends State<ListEnterAnimation> {
  final List<bool> _visible = List.generate(5, (_) => false);

  
  void initState() {
    super.initState();
    // 依次显示列表项
    for (int i = 0; i < _visible.length; i++) {
      Future.delayed(Duration(milliseconds: i * 100), () {
        if (mounted) {
          setState(() {
            _visible[i] = true;
          });
        }
      });
    }
  }

  
  Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: 5,
      itemBuilder: (context, index) {
        return AnimatedOpacity(
          opacity: _visible[index] ? 1.0 : 0.0,
          duration: Duration(milliseconds: 300),
          curve: Curves.easeOut,
          child: AnimatedSlide(
            offset: Offset(0, _visible[index] ? 0 : 0.5),
            duration: Duration(milliseconds: 300),
            curve: Curves.easeOut,
            child: Card(
              child: ListTile(
                title: Text('列表项 ${index + 1}'),
              ),
            ),
          ),
        );
      },
    );
  }
}

场景3: 删除动画

删除动画可以让列表操作更加自然流畅。

删除动画代码示例:

class DeleteAnimationExample extends StatefulWidget {
  
  _DeleteAnimationExampleState createState() => _DeleteAnimationExampleState();
}

class _DeleteAnimationExampleState extends State<DeleteAnimationExample> {
  final List<String> _items = List.generate(5, (i) => '项目 ${i + 1}');
  final Set<int> _deleting = {};

  
  Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: _items.length,
      itemBuilder: (context, index) {
        return AnimatedSize(
          duration: Duration(milliseconds: 300),
          curve: Curves.easeInOut,
          child: _deleting.contains(index)
              ? SizedBox.shrink()
              : AnimatedOpacity(
                  opacity: 1.0,
                  duration: Duration(milliseconds: 200),
                  child: Card(
                    child: ListTile(
                      title: Text(_items[index]),
                      trailing: IconButton(
                        icon: Icon(Icons.delete),
                        onPressed: () {
                          setState(() {
                            _deleting.add(index);
                          });
                          Future.delayed(Duration(milliseconds: 300), () {
                            setState(() {
                              _items.removeAt(index);
                              _deleting.clear();
                            });
                          });
                        },
                      ),
                    ),
                  ),
                ),
        );
      },
    );
  }
}

动画场景示例流程

卡片点击

设置展开状态

AnimatedPositioned触发

位置: 角落→中心

尺寸: 小→大

内容: 显示详情

平滑过渡

展开完成

用户关闭

反向动画

返回原始状态

八、动画设计原则

动画设计指南

良好的动画设计应该遵循一定的原则,既要美观又要实用。

设计原则:

  1. 自然流畅

    • 动画应该符合物理规律
    • 避免突兀的变化
    • 使用合适的曲线
  2. 快速响应

    • 动画时长不宜过长
    • 快速反馈用户操作
    • 不影响用户操作流程
  3. 有意义

    • 动画应该有明确目的
    • 不要为了动画而动画
    • 提供有价值的信息
  4. 可预测

    • 动画应该符合用户预期
    • 遵循平台的设计规范
    • 保持一致性
  5. 性能友好

    • 避免过度的动画效果
    • 优化动画性能
    • 考虑低性能设备

动画设计检查清单

检查项 说明 通过标准
时长合适 动画不会太长或太短 200-600ms之间
曲线自然 动画速度变化合理 符合物理预期
性能良好 帧率稳定 60fps
有意义 动画有明确目的 传达信息或反馈
可访问 支持减少动画 遵循系统设置
一致性 风格统一 整体应用一致

常见动画错误

错误 现象 解决方案
动画过长 用户等待时间过长 缩短动画时长
动画过快 用户看不清变化 增加动画时长或曲线
动画卡顿 帧率低 优化性能
动画无意义 不传达任何信息 重新设计或移除
动画不一致 不同页面动画不同 建立动画规范

九、动画在跨平台中的应用

平台差异

不同平台对动画有不同的期望和规范,了解这些差异有助于创建更好的跨平台体验。

平台动画规范对比:

特性 iOS Android 鸿蒙
默认曲线 iOS标准曲线 Material曲线 自定义曲线
动画时长 300-500ms 300-400ms 300-500ms
过渡方式 淡入淡出 滑动 滑动+淡入淡出
强调动画 弹性 缩放 混合

跨平台动画适配

// 根据平台选择动画曲线
Curve getPlatformCurve() {
  if (Theme.of(context).platform == TargetPlatform.iOS) {
    return Curves.easeInOut;
  } else {
    return Curves.fastOutSlowIn;
  }
}

// 根据平台选择动画时长
Duration getPlatformDuration() {
  if (Theme.of(context).platform == TargetPlatform.iOS) {
    return Duration(milliseconds: 400);
  } else {
    return Duration(milliseconds: 300);
  }
}

// 使用平台适配的动画
AnimatedPositioned(
  duration: getPlatformDuration(),
  curve: getPlatformCurve(),
  left: _left,
  top: _top,
  child: child,
)

十、总结

Stack动画是Flutter动画系统的重要组成部分,通过AnimatedPositioned、AnimatedOpacity等组件,可以创建出流畅而吸引人的视觉效果。

核心要点:

  • AnimatedPositioned实现位置和尺寸动画
  • AnimatedOpacity实现透明度动画
  • AnimatedContainer实现多种属性动画
  • 合理组合多种动画效果
  • 注意动画性能优化
  • 遵循动画设计原则

适用场景:

  • 卡片展开收起
  • 列表进入删除
  • 提示消息显示
  • 页面切换过渡
  • 按钮反馈效果
  • 加载状态指示

最佳实践:

  • 选择合适的动画时长(300-500ms)
  • 使用自然的动画曲线
  • 优化动画性能
  • 保持动画有意义
  • 考虑跨平台差异
  • 遵循平台设计规范

技术要点:

  • AnimatedPositioned是最常用的Stack动画组件
  • 可以同时动画多个属性
  • 组合动画可以创建丰富的效果
  • 使用const和RepaintBoundary优化性能
  • 注意动画的可访问性

掌握Stack动画的技巧,可以帮助开发者创建出更加流畅和吸引人的用户界面,提升应用的整体品质和用户体验。在Flutter跨平台开发中,动画是区分优秀应用和普通应用的重要因素之一,值得投入时间深入学习和实践。

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

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐