简体   繁体   English

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

[英]How to achieve an expandable bottom navigation bar in Flutter

I am trying to build an app that includes a bottom navigation bar for navigating between screens.我正在尝试构建一个包含用于在屏幕之间导航的底部导航栏的应用程序。

In the middle of the bottom navigation bar, I want to add a button which expands the bottom navigation bar with a semicircle, and revels more buttons.在底部导航栏的中间,我想添加一个按钮,将底部导航栏扩展为一个半圆形,并增加更多按钮。

I've read the documentation of the bottom navigation bar, and searched a lot in pub.dev if there is something similar I can use, but I couldn't find any.我已经阅读了底部导航栏的文档,并在 pub.dev 中搜索了很多我可以使用的类似东西,但我找不到任何东西。

Does anyone know if it's achievable, and if so, how?有谁知道它是否可以实现,如果可以,如何实现?

Thank you very much非常感谢

You can check this simple implementation with showDialog and CustomPainter .您可以使用showDialogCustomPainter检查这个简单的实现。 Basically it involved displaying a showDialog with bottom padding equals the height of BottomNavigationBar , then arrange the items within a Stack .基本上它涉及显示底部填充的showDialog等于BottomNavigationBar的高度,然后在Stack中排列项目。 The half circle is drawn using CustomPainter .半圆是使用CustomPainter绘制的。

Full example app:完整的示例应用程序:

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;
}

Result:结果:
在此处输入图像描述

I think you need to learn about Flutter Animated Radial Menu and how to implement it in your code, you can go with this article and try to implement in your way.我认为您需要了解 Flutter 动画径向菜单以及如何在您的代码中实现它,您可以使用本文go 并尝试以您的方式实现。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM