【问题标题】:How to achieve an expandable bottom navigation bar in Flutter如何在 Flutter 中实现可扩展的底部导航栏
【发布时间】:2021-07-03 23:49:11
【问题描述】:

我正在尝试构建一个包含用于在屏幕之间导航的底部导航栏的应用。

在底部导航栏的中间,我想添加一个按钮,将底部导航栏扩展成一个半圆形,并增加更多按钮。

我已经阅读了底部导航栏的文档,并且在 pub.dev 中搜索了很多我可以使用的类似的东西,但我找不到。

有谁知道它是否可以实现,如果可以,如何实现?

非常感谢

【问题讨论】:

    标签: flutter dart flutter-layout flutter-dependencies


    【解决方案1】:

    您可以使用showDialogCustomPainter 检查这个简单的实现。基本上它涉及显示showDialog,底部填充等于BottomNavigationBar 的高度,然后在Stack 中排列项目。半圆是使用CustomPainter绘制的。

    完整示例应用:

    import 'dart:math' as math;
    
    import 'package:flutter/material.dart';
    
    void main() {
      runApp(MaterialApp(home: MyApp()));
    }
    
    class MyApp extends StatefulWidget {
      @override
      _MyAppState createState() => _MyAppState();
    }
    
    class _MyAppState extends State<MyApp> {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('Test App'),
          ),
          bottomNavigationBar: BottomNavigationBar(
            unselectedItemColor: Colors.grey,
            selectedItemColor: Colors.blue,
            showUnselectedLabels: true,
            selectedFontSize: 14,
            unselectedFontSize: 14,
            type: BottomNavigationBarType.fixed,
            onTap: (index) {
              if (index == 2) {
                final diameter = 200.0;
                final iconSize = 40;
                showDialog(
                  context: context,
                  barrierDismissible: true,
                  barrierColor: Colors.grey.withOpacity(0.1),
                  builder: (context) => Material(
                    color: Colors.transparent,
                    child: Stack(
                      alignment: AlignmentDirectional.bottomCenter,
                      children: [
                        Container(
                          width: diameter + iconSize,
                          height: diameter / 1.5,
                          alignment: Alignment.bottomCenter,
                          margin:
                              EdgeInsets.only(bottom: kBottomNavigationBarHeight),
                          child: Stack(
                            children: [
                              Container(
                                  alignment: Alignment.bottomCenter,
                                  child: MyArc(diameter: diameter)),
                              Positioned(
                                left: 0,
                                bottom: 10,
                                child: _buildButton(),
                              ),
                              Positioned(
                                left: diameter / 4,
                                top: 10,
                                child: _buildButton(),
                              ),
                              Positioned(
                                right: diameter / 4,
                                top: 10,
                                child: _buildButton(),
                              ),
                              Positioned(
                                right: 0,
                                bottom: 10,
                                child: _buildButton(),
                              )
                            ],
                          ),
                        ),
                      ],
                    ),
                  ),
                );
              }
            },
            items: List<BottomNavigationBarItem>.generate(
              5,
              (index) =>
                  BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Home'),
            ),
          ),
        );
      }
    
      _buildButton() {
        return Container(
          constraints: BoxConstraints.tightFor(width: 40, height: 60),
          child: Column(
            children: [
              Text(
                'Title',
                style: TextStyle(fontSize: 12),
              ),
              SizedBox(height: 3),
              CircleAvatar(
                backgroundColor: Colors.white,
                child: Icon(Icons.home),
              ),
            ],
          ),
        );
      }
    }
    
    class MyArc extends StatelessWidget {
      final double diameter;
    
      const MyArc({Key key, this.diameter = 200}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return CustomPaint(
          painter: MyPainter(),
          size: Size(diameter, diameter),
        );
      }
    }
    
    // This is the Painter class
    class MyPainter extends CustomPainter {
      @override
      void paint(Canvas canvas, Size size) {
        final paint = Paint()
          ..shader = RadialGradient(
            colors: [
              Colors.blue,
              Colors.purpleAccent.withOpacity(0.4),
            ],
          ).createShader(Rect.fromCircle(
            center: Offset(size.width / 2, size.height),
            radius: 200,
          ));
        canvas.drawArc(
          Rect.fromCenter(
            center: Offset(size.width / 2, size.height),
            height: size.height * 1.5,
            width: size.width,
          ),
          math.pi,
          math.pi,
          false,
          paint,
        );
      }
    
      @override
      bool shouldRepaint(CustomPainter oldDelegate) => false;
    }
    

    结果:

    【讨论】:

    • 谢谢。这对我来说是一个很好的开始,可以实现我想要的
    【解决方案2】:

    我认为你需要了解 Flutter Animated Radial Menu 以及如何在你的代码中实现它,你可以去with this article 并尝试以你的方式实现。

    【讨论】:

    • 我已经阅读了它,但不幸的是我仍然无法理解它如何应用于底部导航栏
    • 这是我创建底部导航栏的答案,您可以将容器包装在堆栈中并将径向菜单添加为位置小部件 === > stackoverflow.com/questions/66998389/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-08-18
    • 1970-01-01
    • 2021-12-24
    • 1970-01-01
    • 2021-10-21
    • 2020-02-07
    相关资源
    最近更新 更多