skip to Main Content

enter image description here

I made a custom NavBar but it doesn’t look natural. It should look like the Nav bar is in front of the drink card but instead It looks like it has its own block section. Is there a way for me to remove the SafeAre around the Nav Bar?

Here is the code:

Widget commonTabScene(String tabName){
  return Container(
    alignment: Alignment.center,
    child: Text(tabName, style: const TextStyle(fontSize: 28),),
  );
}

class HomeScreen extends StatefulWidget {
  const HomeScreen({super.key});

  @override
  State<HomeScreen> createState() => _RiveAppHomeState();
}

class _RiveAppHomeState extends State<HomeScreen> {
  Widget _tabBody = Container(color: RiveAppTheme.background);
  final List<Widget> _screens = [
    const CategoriesScreen(),
    commonTabScene('Search'),
    commonTabScene('Timer'),
    commonTabScene('Bell'),
    commonTabScene('User'),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body:_tabBody,
      bottomNavigationBar: CustomTabBar(
        onTabChange: (tabIndex) {
          setState(() {
            _tabBody = _screens[tabIndex];
          });
        },
      ),
    );
  }
}

Here Is the Custom Nav code.

custom_nav_bar:*

class CustomTabBar extends StatefulWidget {
  const CustomTabBar({super.key, required this.onTabChange});

  final Function(int tabIndex) onTabChange;

  @override
  State<CustomTabBar> createState() => _CustomTabBarState();
}

class _CustomTabBarState extends State<CustomTabBar> {
  final List<TabItem> _icons = TabItem.tabItemsList;

  int _selectedTab = 0;

  void _onRiveIconInit(Artboard artboard, index) {
    final controller = StateMachineController.fromArtboard(
        artboard, _icons[index].stateMachine);
    artboard.addController(controller!);

    _icons[index].status = controller.findInput<bool>('active') as SMIBool;
  }

  void onTabPress(int index) {
    if (_selectedTab != index){
      setState(() {
      _selectedTab = index;
    });
    widget.onTabChange(index);

    // Starts Animation
    _icons[index].status!.change(true);
    // Stops Animation
    Future.delayed(const Duration(seconds: 1), () {
      _icons[index].status!.change(false);
    });
    }

  }

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Container(
        margin: const EdgeInsets.fromLTRB(24, 0, 24, 8),
        padding: const EdgeInsets.all(1),
        decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(24),
          gradient: LinearGradient(colors: [
            Colors.white.withOpacity(0.5),
            Colors.white.withOpacity(0),
          ]),
        ),
        child: Container(
          decoration: BoxDecoration(
              color: RiveAppTheme.background2.withOpacity(0.8),
              borderRadius: BorderRadius.circular(24),
              boxShadow: [
                BoxShadow(
                  color: RiveAppTheme.background2.withOpacity(0.3),
                  blurRadius: 20,
                  offset: const Offset(0, 20),
                )
              ]),
          child: Row(
            mainAxisAlignment: MainAxisAlignment.spaceAround,
            children: List.generate(_icons.length, (index) {
              TabItem icon = _icons[index];

              return Expanded(
                key: icon.id,
                
                child: CupertinoButton(
                  padding: const EdgeInsets.all(12),
                  // Makes the widget smaller
                  child: AnimatedOpacity(
                    opacity: _selectedTab == index ? 1 : 0.5,
                    duration: const Duration(milliseconds: 200),
                    child: Stack(
                      clipBehavior: Clip.none,
                      alignment: Alignment.center,
                      children: [
                        Positioned(
                          top: -4,
                          child: AnimatedContainer(
                            duration: const Duration(milliseconds: 200),
                            height: 4,
                            width: _selectedTab == index ? 20 : 0,
                            decoration: BoxDecoration(
                              color: RiveAppTheme.accentColor,
                              borderRadius: BorderRadius.circular(2)
                            ),
                          ),
                        ),
                        SizedBox(
                          height: 36,
                          width: 36,
                          child: RiveAnimation.asset(
                            'assets/samples/ui/rive_app/rive/iconss.riv',
                            // How to get specific Icon
                            stateMachines: [icon.stateMachine],
                            artboard: icon.artboard,
                            onInit: (artboard) {
                              _onRiveIconInit(artboard, index);
                            },
                          ),
                        ),
                      ],
                    ),
                  ),
                  onPressed: () {
                    onTabPress(index);
                  },
                ),
              );
            }),
          ),
        ),
      ),
    );
  }
}

I’ve looked almost every where But I cannot find a specific answer for this question.

2

Answers


  1. You can use stack with your nav bar on main screen widget instead of bottomNavigationBar property of scaffold, for example

      return Scaffold(
          body: const BaseScreen(),
        );
    

    where BaseScreen is a common widget for your scenes

    final class BaseScreen extends StatefulWidget {
      ///
      const BaseScreen({super.key});
    
      ///
      @override
      State<BaseScreen> createState() => BaseScreenState();
    }
    
    final class BaseScreenState extends State<BaseScreen> {
      Widget _tabBody = Container(color: RiveAppTheme.background);
      final List<Widget> _screens = [
        const CategoriesScreen(),
        commonTabScene('Search'),
        commonTabScene('Timer'),
        commonTabScene('Bell'),
        commonTabScene('User'),
      ];
    
      ///
      @override
      Widget build(BuildContext context) 
        return Stack(
          children: [
            _tabBody,
            Align(
              alignment: Alignment.bottomCenter,
              child: CustomTabBar(
                onTabChange: (tabIndex) {
                  setState(() {
                    _tabBody = _screens[tabIndex];
                  });
                },
              ),
            ),
          ],
        );
      }
    }
    
    

    Or smth like this.

    But it’s better to create each screen as full screen with changing via navigator, not only one screen with different bodies.

    Login or Signup to reply.
  2. You just have to use extendBody: true on the Scaffold.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search