Notch in BottomAppBar for custom FAB

2019-05-21 12:23发布

问题:

I'm using UnicornDialer from the unicorndial package to create a Material speed dial experience on the home page of my app, but if I set the shape property to define a notch, then notch is not painted correctly:

I noticed on another package (flutter_speed_dial) that this was explicitly mentioned as not working:

The SpeedDial widget is built to be placed in the floatingActionButton parameter of the Scaffold widget. It's not possible to set its position with the Scaffold.floatingActionButtonLocation parameter though. The use with the Scaffold.bottomNavigationBar is possible but the floating button will be placed above the bar, without the possibility to be placed with a notch.

In the case of UnicornDialer the widget returned by the build method is a standard FloatingActionButton and having trawled through the code for Scaffold and BottomAppBar I can't work out why the notch is corrupted like that.

I had tried using a standard FAB (but transparent) to create the notch, then wrapping the Scaffold and UnicornDialer in a Stack to position everything, which worked fine, but then when you show a SnackBar the UnicornDialer doesn't move, so I'm back to needing BottomAppBar to treat the custom FAB properly for notch calculation. Any ideas?

回答1:

You need to wrap UnicornDialer by a container and control the notch margin , please note that notchMargin can take negative value,

it seems that the renderer of the notch of the bottomAppBar are not able to calculate the Besier curves correctly from the raw UnicornDialer .

you can use the following code as a guide. it is working well

import 'package:flutter/material.dart';
import 'package:unicorndial/unicorndial.dart';

void main() =>
    runApp(new MaterialApp(debugShowCheckedModeBanner: false, home: Example()));

class Example extends StatefulWidget {
  _Example createState() => _Example();
}

class _Example extends State<Example> {
  @override
  Widget build(BuildContext context) {
    var childButtons = List<UnicornButton>();

    childButtons.add(UnicornButton(
        hasLabel: true,
        labelText: "Choo choo",
        currentButton: FloatingActionButton(

          heroTag: "train",
          backgroundColor: Colors.redAccent,
          mini: true,
          child: Icon(Icons.train),
          onPressed: () {},
        )));

    childButtons.add(UnicornButton(
        currentButton: FloatingActionButton(
            heroTag: "airplane",
            backgroundColor: Colors.greenAccent,
            mini: true,
            child: Icon(Icons.airplanemode_active))));

    childButtons.add(UnicornButton(
        currentButton: FloatingActionButton(
            heroTag: "directions",
            backgroundColor: Colors.blueAccent,
            mini: true,
            child: Icon(Icons.directions_car))));

    return Scaffold(

      floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
      bottomNavigationBar: new BottomAppBar(
        shape: CircularNotchedRectangle(),


        notchMargin: -10.0,

        color: Colors.blue,
        child: new Row(
          mainAxisSize: MainAxisSize.max,
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: <Widget>[
            IconButton(
              icon: Icon(Icons.menu),
              onPressed: () {},
            ),
            IconButton(
              icon: Icon(Icons.search),
              onPressed: () {},
            ),
          ],
        ),
      ),
      //floatingActionButton: FloatingActionButton(onPressed: (){}),
      floatingActionButton: Container(
        width: 100.0,
        height: 100.0,
        child: UnicornDialer(
            hasNotch: true,
            //hasBackground: false,
            backgroundColor: Color.fromRGBO(255, 255, 255, 0.0),
            parentButtonBackground: Colors.redAccent,
            orientation: UnicornOrientation.VERTICAL,
            parentButton: Icon(Icons.add),
            childButtons: childButtons),
      ),
      appBar: AppBar(),
      body: Container(

        child: Center(
          child: RaisedButton(
            onPressed: () {
              setState(() {});
            },
          ),
        ),
      ),
    );
  }
}