Flutter 如何实现可扩展的底部导航栏

时间:2021-04-08 06:27:37

标签: flutter dart flutter-layout flutter-dependencies

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

在底部导航栏的中间,我想添加一个按钮,用半圆扩展底部导航栏,并显示更多按钮。

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

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

非常感谢

2 个答案:

答案 0 :(得分: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;
}

结果:
enter image description here

答案 1 :(得分:0)

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