How to create reusable Flutter app bar with dynamic value

Issue

I’m trying to create a reusable app bar that has a dynamic size. I am using dynamic values to adjust the size of icons, padding, text font size, etc in the app and want to do the same with the app bar size. The app bar code below works dynamically and gives me the behavior I want using MediaQuery.

class SamplePage extends StatelessWidget {
  const SamplePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final screenHeight = MediaQuery.of(context).size.height;
    return Scaffold(
      appBar: AppBar(
        actions: const [
          BrandPopUpMenu(),
        ],
        automaticallyImplyLeading: true,
        centerTitle: true,
        title: const AppBarText(
          pageName: PageName.nutrition,
        ),
        toolbarHeight: screenHeight / 15.07,
      ),
      drawer: const SideSheet(),
      body: Container(),
    );
  }
}

When I try to create a reusable app bar from the code above that is when I run into trouble.

class SamplePage extends StatelessWidget {
  const SamplePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final screenHeight = MediaQuery.of(context).size.height;
    return Scaffold(
      appBar: SamplePageDynamicAppBar(screenHeight: screenHeight),
      drawer: const SideSheet(),
      body: Container(),
    );
  }
}

The code below only works with a hard coded preferred size and I am uncertain how to continue to use the dynamic value in the toolBarHeight and not the preferred size in the override.

class SamplePageDynamicAppBar extends StatelessWidget
    implements PreferredSizeWidget {
  const SamplePageDynamicAppBar({
    Key? key,
    required this.screenHeight,
  }) : super(key: key);

  final double screenHeight;

  @override
  Size get preferredSize => const Size.fromHeight(56.0);
  
  @override
  Widget build(BuildContext context) {
    return AppBar(
      actions: const [
        BrandPopUpMenu(),
      ],
      automaticallyImplyLeading: true,
      centerTitle: true,
      title: const AppBarText(
        pageName: PageName.nutrition,
      ),
      toolbarHeight: screenHeight / 15.07,
    );
  }
}

Any help will be greatly appreciated. Thanks

Solution

Since all you’re doing is overriding toolbarHeight property of AppBar, see if this works. It extends AppBar instead creating a new widget. https://dartpad.dev/?id=d15b4d91168e13b89e86267da4311683

class SamplePageDynamicAppBar extends AppBar {
  SamplePageDynamicAppBar({Key? key, required double screenHeight}) :
    super(
      actions: const [
        BrandPopUpMenu(),
      ],
      automaticallyImplyLeading: true,
      centerTitle: true,
      title: const AppBarText(
        pageName: PageName.nutrition,
      ),
      toolbarHeight: screenHeight / 15.07,
    );
}

Alternatively you can use the code you’ve written by changing your implementation of the perferredSize getter. https://dartpad.dev/?id=758db4b7a7b2908b166a6a29d766045d

class SamplePageDynamicAppBar extends StatelessWidget implements PreferredSizeWidget {
  const SamplePageDynamicAppBar({
    Key? key,
    required double screenHeight,
  }) : 
    toolbarHeight = screenHeight / 15.07,    
    super(key: key);

  final double toolbarHeight;

  @override
  Size get preferredSize => Size.fromHeight(toolbarHeight);
 
  @override
  Widget build(BuildContext context) {
    return AppBar(
      actions: const [
        BrandPopUpMenu(),
      ],
      automaticallyImplyLeading: true,
      centerTitle: true,
      title: const AppBarText(
        pageName: PageName.nutrition,
      ),
      toolbarHeight: toolbarHeight,
    );
  }
}

Answered By – user2301346

Answer Checked By – Dawn Plyler (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *