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

Flutter:如何在Row组件中使用AnimatedPositioned并解决动画报错

问题解决:Row中使用AnimatedPositioned导致的错误与动画适配方案

错误原因

AnimatedPositioned是仅能作为Stack直接子组件的特殊组件,你把它嵌套在Row里,不仅它的定位属性(right)无法生效,还会触发"Incorrect use of ParentDataWidget"错误,这就是组件尺寸无法正确调整的核心原因。

无需改用AnimatedSize的简单方案

把Row里的隐形占位盒子换成AnimatedContainer,利用它的宽度动画来实现和侧边栏同步的过渡效果,完全适配Row的布局逻辑:

修改后的完整代码

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: Scaffold(
        body: SafeArea(
          child: Center(
            child: MyWidget(),
          ),
        ),
      ),
    );
  }
}

class MyWidget extends StatefulWidget {
  const MyWidget({Key? key}) : super(key: key);

  @override
  State<MyWidget> createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  bool showSidebar = true;

  @override
  Widget build(BuildContext context) {
    double height = MediaQuery.of(context).size.height;

    return SafeArea(
      child: Stack(
        children: [
          Row(
            mainAxisAlignment: MainAxisAlignment.end,
            children: [
              Expanded(
                child: SingleChildScrollView(
                  child: Column(
                    children: [
                      Container(
                        width: double.maxFinite,
                        height: 700,
                        color: Colors.red,
                      ),
                      Text(
                        'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.',
                        softWrap: true,
                      ),
                      Container(
                        width: double.maxFinite,
                        height: 700,
                        color: Colors.yellow,
                      ),
                    ],
                  ),
                ),
              ),
              // 替换成AnimatedContainer实现宽度动画
              AnimatedContainer(
                width: showSidebar ? 43 : 0,
                height: height,
                curve: Curves.ease,
                duration: const Duration(milliseconds: 100),
                color: Colors.transparent,
              ),
            ],
          ),
          // Sidebar box
          AnimatedPositioned(
            right: showSidebar ? 0 : -43,
            curve: Curves.ease,
            duration: const Duration(milliseconds: 100),
            child: Container(
              width: 43.0,
              height: height,
              color: Colors.blue,
              child: Column(
                mainAxisAlignment: MainAxisAlignment.start,
                children: const [
                  SizedBox(height: 100.0),
                  Expanded(
                    child: Center(
                      child: RotatedBox(
                        quarterTurns: -1,
                        child: Text(
                          'EXAMPLE MENU BAR - PAGE 1',
                          style: TextStyle(
                              fontSize: 20.0, fontWeight: FontWeight.bold, color: Colors.white),
                        ),
                      ),
                    ),
                  ),
                ],
              ),
            ),
          ),
          Padding(
            padding: const EdgeInsets.only(left: 5.0, top: 5.0, right: 4.0),
            child: Row(
              crossAxisAlignment: CrossAxisAlignment.start,
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                fakeButton(),
                Column(
                  children: [
                    fakeButton(),
                    fakeButton(),
                    fakeButton(),
                  ],
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }

  // Fake buttons
  Widget fakeButton() {
    return GestureDetector(
      onTap: () => setState(() => showSidebar = !showSidebar),
      child: SizedBox(
        height: 35,
        width: 35,
        child: Stack(
          children: const [
            Icon(
              Icons.circle,
              color: Colors.green,
              size: 35.0,
            ),
            Align(
              alignment: Alignment.center,
              child: Text(
                'HIDE',
                style: TextStyle(
                  color: Colors.white,
                  fontWeight: FontWeight.bold,
                  fontSize: 9.0,
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

方案说明

  1. AnimatedContainer是通用动画组件,可以完美适配Row的线性布局,不会触发ParentDataWidget错误
  2. 设置和侧边栏完全一致的duration和curve,保证两者动画同步
  3. 透明背景不影响页面视觉,同时为侧边栏预留出对应的布局空间

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 17:30:45