簡體   English   中英

Flutter BottomNavigationBar 與 AnimatedContainer - 是什么導致 RenderFlex 溢出錯誤?

[英]Flutter BottomNavigationBar with AnimatedContainer - what is causing a RenderFlex overflow error?

我的 Flutter 應用程序使用包裝在 AnimatedContainer 中的 BottomNavigationBar。 當動畫發生(通過滾動列表激活)時,會發生 RenderFlex 溢出錯誤。 我無法弄清楚導致這種情況發生的原因。

我已經將項目簡化為基本代碼,希望有人可以嘗試並找出問題所在。

主要類:

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

  @override
  State<TestMain> createState() => _TestMain();
}

class BottomNavBarItemData {
  String label;Icon icon;Widget screen;
  BottomNavBarItemData({required this.label,required this.icon,required this.screen});
}

late ScrollController mainScrollController;

class _TestMain extends State<TestMain> {
  int _selectedIndex = 0;
  bool _isVisible = true;

  @override
  void initState() {
    _isVisible = true;
    mainScrollController = ScrollController();
    mainScrollController.addListener(() {
      if (mainScrollController.position.userScrollDirection == ScrollDirection.reverse) {
        setState(() {
          _isVisible = false;
        });
      }
      if (mainScrollController.position.userScrollDirection == ScrollDirection.forward) {
        setState(() {
          _isVisible = true;
        });
      }
    });
    super.initState();
  }

  final List<BottomNavBarItemData> screens = [
    BottomNavBarItemData(
      icon: const Icon(Icons.home, size: 25.0, color: Colors.red),
      label: 'Page1',
      screen: const Screen1(),
    ),
    BottomNavBarItemData(
      icon: const Icon(Icons.home, size: 25.0, color: Colors.red),
      label: 'Page2',
      screen: const Screen2(),
    ),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      extendBody: true,
      body: SafeArea(
        child: IndexedStack(
          index: _selectedIndex,
          children: [
            ...screens.map((e) => e.screen).toList(),
          ],
        ),
      ),
      bottomNavigationBar: AnimatedContainer(
        duration: const Duration(milliseconds: 400),
        height: _isVisible ? 70 : 0.0,
        child: SizedBox(
          child: BottomNavigationBar(
            type: BottomNavigationBarType.fixed,
            backgroundColor: Colors.orange,
            currentIndex: _selectedIndex,
            selectedIconTheme: IconThemeData(color: Colors.white),
            selectedItemColor: Colors.white,
            selectedFontSize: 14,
            unselectedFontSize: 14,
            unselectedIconTheme: const IconThemeData(
              color: Colors.lightBlueAccent,
            ),
            unselectedItemColor: Colors.lightBlueAccent,
            onTap: _onItemTapped,
            items: screens.map((e) => BottomNavigationBarItem(
                    label: e.label,
                    icon: e.icon,
                  ),
                ).toList(),
          ),
        ),
      ),
    );
  }

  void _onItemTapped(int index) {
    setState(() {
      _selectedIndex = index;
    });
  }
}

主類調用的兩個屏幕:

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

  @override
  State<Screen1> createState() => _Screen1();
}

class _Screen1 extends State<Screen1> {

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.white,
      child: SingleChildScrollView(
        controller: mainScrollController,
        physics: const AlwaysScrollableScrollPhysics(),
        child: Column(children: [
          Container(height: 150, color: Colors.blue),
          Container(height: 150, color: Colors.white),
          Container(height: 150, color: Colors.blue),
          Container(height: 150, color: Colors.white),
          Container(height: 150, color: Colors.blue),
          Container(height: 150, color: Colors.white),
        ],),
      ),
    );
  }
}

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

  @override
  State<Screen2> createState() => _Screen2();
}

class _Screen2 extends State<Screen2> {
  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.white,
    );
  }
}

容器溢出是因為內部項目空間大於動畫大小,就像在 35 上它會顯示溢出。 您可以使用不同的動畫,但差別不大。

您可以在這種情況下使用SizeTransition

class _TestMain extends State<TestMain> with SingleTickerProviderStateMixin {
  int _selectedIndex = 0;
  bool _isVisible = true;

  late final AnimationController _controller = AnimationController(
    duration: const Duration(milliseconds: 400),
    vsync: this,
  )..forward();
  late final Animation<double> _animation = CurvedAnimation(
    parent: _controller,
    curve: Curves.fastOutSlowIn,
  );

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

  @override
  void initState() {
    _isVisible = true;
    mainScrollController = ScrollController();
    mainScrollController.addListener(() {
      if (mainScrollController.position.userScrollDirection ==
          ScrollDirection.reverse) {
        _controller.reverse();
        setState(() {
          _isVisible = false;
        });
      }
      if (mainScrollController.position.userScrollDirection ==
          ScrollDirection.forward) {
        _controller.forward();
        setState(() {
          _isVisible = true;
        });
      }
    });
    super.initState();
  }

  final List<BottomNavBarItemData> screens = [
    BottomNavBarItemData(
      icon: const Icon(Icons.home, size: 25.0, color: Colors.red),
      label: 'Page1',
      screen: const Screen1(),
    ),
    BottomNavBarItemData(
      icon: const Icon(Icons.home, size: 25.0, color: Colors.red),
      label: 'Page2',
      screen: const Screen2(),
    ),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      extendBody: true,
      body: SafeArea(
        child: IndexedStack(
          index: _selectedIndex,
          children: [
            ...screens.map((e) => e.screen).toList(),
          ],
        ),
      ),
      bottomNavigationBar: SizeTransition(
        sizeFactor: _animation,
        child: SizedBox(
          child: BottomNavigationBar(
            type: BottomNavigationBarType.fixed,
            backgroundColor: Colors.orange,
            currentIndex: _selectedIndex,
            selectedIconTheme: IconThemeData(color: Colors.white),
            selectedItemColor: Colors.white,
            selectedFontSize: 14,
            unselectedFontSize: 14,
            unselectedIconTheme: const IconThemeData(
              color: Colors.lightBlueAccent,
            ),
            unselectedItemColor: Colors.lightBlueAccent,
            onTap: _onItemTapped,
            items: screens
                .map(
                  (e) => BottomNavigationBarItem(
                    label: e.label,
                    icon: e.icon,
                  ),
                )
                .toList(),
          ),
        ),
      ),
    );
  }

  void _onItemTapped(int index) {
    setState(() {
      _selectedIndex = index;
    });
  }
}

或者

 bottomNavigationBar: AnimatedScale(
        duration: const Duration(milliseconds: 400),
        scale: _isVisible ? 1 : 0.0,
        alignment: Alignment.bottomCenter,

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM