8

I would like to know if there is a way to dock a floating action button in a CupertinoTabBar. I would like to get the results as in the picture below

enter image description here

My screen is organized as follow

  • CupertinoTabScaffold
    • CupertinoTabView
      • CupertinoPageScaffold
        • CupertinoNavigationBar
        • Scaffold
    • CupertinoTabBar

I have tried to add the following code to my Scaffold but the result is not what I want. I understand the issue is that the TabBar is not inside the scaffold hence it is not docked however I am wondering if there is a way to put the floating button somewhere else to get to the result I want

Here is the code

child: Scaffold(
        floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
        floatingActionButton: FloatingActionButton.extended(
          backgroundColor: kColorAccent,
          onPressed: () {},
          label: Text('To my Favorites!'),
          icon: Icon(Icons.favorite),
        ),

And here is the result I get...

enter image description here

Shayan Shafiq
  • 1,447
  • 5
  • 18
  • 25
M4trix Dev
  • 1,828
  • 3
  • 23
  • 48

3 Answers3

4

like everyone, I spent some time looking for an optimal answer to this problem, and after carefully analyzing the code I found a solution and I share them below, this is a fragment of the project in which I work, but it can be of use general

import 'package:app_example/floatingAction.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

class HomePage extends StatefulWidget {
 @override
 _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {

@override
initState() {
  super.initState();

}

@override
Widget build(BuildContext context) {

return Scaffold(
  floatingActionButtonLocation: FloatingActionButtonLocation.endTop,
  floatingActionButton: FloatingAction(),

  bottomNavigationBar: CupertinoTabScaffold(
    
      tabBar: CupertinoTabBar(
          activeColor: Colors.red,
          inactiveColor: Colors.grey,
          items: [
            BottomNavigationBarItem(
              icon: Icon(
                Icons.loyalty_outlined,
              ),
              label: "Productos",
            ),
            BottomNavigationBarItem(
              icon: Icon(
                Icons.people,
              ),
              label: 'Clientes',
            ),
            BottomNavigationBarItem(
              icon: Icon(
                Icons.shopping_cart_outlined,
              ),
              label: 'Ventas',
            ),
            BottomNavigationBarItem(
              icon: Icon(
                Icons.timeline,
              ),
              label: "Historial",
            ),
          ]),
      tabBuilder: (BuildContext contex, int index) {
        
        switch (index) {
          case 0:
            return CupertinoTabView(
              builder: (BuildContext context) => ProductScreen(),
            );
            break;
          case 1:
            return CupertinoTabView(
              builder: (BuildContext context) => ClientScreen(),
            );
            break;
          case 2:
            return CupertinoTabView(
              builder: (BuildContext context) => MarketScreen(),
            );
            break;
          case 3:
            return CupertinoTabView(
              builder: (BuildContext context) => HistoryScreen(),
            );
            break;
        }
        return null;
      }),
  );
 }
 }

class FloatingAction extends StatelessWidget {
@override
Widget build(BuildContext context) {
 return Column(
   mainAxisAlignment: MainAxisAlignment.end,
  children: [
    Container(
              margin: EdgeInsets.only(bottom:70),
              child: FloatingActionButton(
              onPressed: () {
                print('click en botton');
                Navigator.of(context).push(
                  MaterialPageRoute(builder: (context) =>NewMarket()),
                );
              },
              child: Icon(Icons.queue),
              backgroundColor: Colors.red,
            ),
    ),
  ],
);
 }
}

Separating the floatingActionButton into an independent class, FloatingAction, allows us to give more features to the widget, in this case within an Column, with a mainAxisAlignment: MainAxisAlignment.end, which allows us to do an alignment to the bottom of the widget, and with the floatingActionButtonLocation: FloatingActionButtonLocation.endTop,,allows us to have a location defined on the edge of the screen, in that sense, it only remains to locate the preferred height of the button with the margin: EdgeInsets.only ( bottom: 70), of container

To center the button, we simply change the margin: EdgeInsets.only (bottom: 70, right: MediaQuery.of (context) .size.width / 2 - 45), the bottom will indicate the height, the right the location in reference to the center.

Doing this process inside a Column will allow us to add more floating buttons in the future if needed.

image

image

now it is possible to work a floatingActionButton with a CupertinoTapBar

RyosukeOK
  • 686
  • 1
  • 9
  • 22
ArmandoHackCode
  • 311
  • 2
  • 6
0

For some of you looking for a code snippet, I'll give you a working example.

class Home extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return HomeState();
  }
}

class HomeState extends State<Home> {
  int _index = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.add),
        onPressed: () {
          Navigator.of(context).push(
              // this can also be `MaterialPageRoute`
              CupertinoPageRoute(
                fullscreenDialog: true,
                // typical full screen dialog behavior
                builder: (_) => ModalPage(),
              )
          );
        },
      ),
      floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
      bottomNavigationBar: CupertinoTabBar(
        currentIndex: _index,
        onTap: (newIndex) {
          setState(() {
            _index = newIndex;
          });
        },
        items: const <BottomNavigationBarItem>[
          BottomNavigationBarItem(
            icon: Icon(Icons.today),
            title: Text("today"),
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.timeline),
            title: Text("stats"),
          ),
        ],
      ),
      /**
       * You can use switch here,
       * for the sake of brevity, I only used two tabs
       */
      body: _index == 0 ? Page1() : Page2(),
    );
  }
}

Point is

  1. use scaffold. If you use CupertinoTabScaffold, then you'll not be able to use FloatingActionbutton.

  2. you can move FAB into whatever position using floatingActionButtonLocation.

  3. you need StatefulWidget or something similar to that to handle index change.

Gompro
  • 2,247
  • 1
  • 16
  • 26
-1

You can wrap a CupertinoTabScaffold inside a Scaffold, like

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: buildYourScafold(context),
        floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
        floatingActionButton: FloatingActionButton(
          onPressed: () {},
          child: Icon(
            Icons.add,
          ),
        ));
  }
Jidong Chen
  • 450
  • 6
  • 9