In my first Flutter app I want to build a responsive view. For state handling I am using the stacked framework. Part of the responsive view will be an AppBar widget which will display (or not) a hamburger menu based on the available screen width. I created a class for the responsive AppBar.
import 'package:flutter/material.dart';
import 'package:chd_stacked/ui/common/ui_helpers.dart';
class AppBarResponsive extends AppBar {
AppBarResponsive({Key? key, this.breakpoint = 600,}) : super(key: key);
final double breakpoint;
@override
Widget build(BuildContext context) {
return AppBar(
automaticallyImplyLeading: false,
leading: screenWidth(context) <= breakpoint ?
const IconButton(icon: Icon(Icons.menu), onPressed: null) : null);
}
}
The screenWidth function is defined in the ui_helpers.dart which is part of the stacked framework:
double screenWidth(BuildContext context) => MediaQuery.of(context).size.width;
Based on what I have read so far, the fact that MediaQuery.of(context).size.width is called inside the build override causes the build function to get called again every time the size changes. At least that's how I understand it.
In the responsive view I am using the AppBarResponsive like below:
import 'package:flutter/material.dart';
import 'package:stacked/stacked.dart';
import 'package:chd_stacked/ui/common/app_colors.dart';
import 'package:chd_stacked/ui/common/ui_helpers.dart';
import 'home_viewmodel.dart';
import 'package:chd_stacked/ui/widgets/common/app_bar_responsive/app_bar_responsive.dart';
class HomeView extends StackedView<HomeViewModel> {
const HomeView({Key? key}) : super(key: key);
@override
Widget builder(
BuildContext context,
HomeViewModel viewModel,
Widget? child,
) {
return Scaffold(
appBar: AppBarResponsive(breakpoint: 600,),
body: ... removed for clarity ...
);
}
@override
HomeViewModel viewModelBuilder(
BuildContext context,
) =>
HomeViewModel();
}
When I run the app the layout is as supposed to be but the menu icon doesn't show up at all regardless of the screen width.
However, when I use an AppBar (instead of an AppBarResponsive) directly in the responsive view:
import 'package:flutter/material.dart';
import 'package:stacked/stacked.dart';
import 'package:chd_stacked/ui/common/app_colors.dart';
import 'package:chd_stacked/ui/common/ui_helpers.dart';
import 'home_viewmodel.dart';
class HomeView extends StackedView<HomeViewModel> {
const HomeView({Key? key}) : super(key: key);
@override
Widget builder(
BuildContext context,
HomeViewModel viewModel,
Widget? child,
) {
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
leading: screenWidth(context) <= 600
? const IconButton(icon: Icon(Icons.menu), onPressed: null)
: null),
body: ... removed for clarity ...
);
}
@override
HomeViewModel viewModelBuilder(
BuildContext context,
) =>
HomeViewModel();
}
The menu icon appears and disappears based on the screen width as expected.
The question is why it doesn't work as a class that extends AppBar but it works when the AppBar widget is used directly into the view? Am I missing something here?
Problem is not the
MediqQouery
, though everything that was said about Mediquery is true.Problem is how you are creating your custom
appear
, you can't extendAppBar
andoverride
thebuild
method, one of the first reason is thatAppBar
isstateful
andAppBar
itself does not have anybuild
method it is implemented in its state widget.Secondly proper way to make custom appear from AppBar is this(Though I prefer to use PreferedSizeWidget when making custom appbars):
Thirdly, you will need to access
context
inside thesuper()
because you need to callscreenWidth
there which depends on context to calculate width, for that you need to pass down the context argument fromAppBarResponsive's
constructor, like so:Note: Or you can pass already calculated
breakpoint
from home page and compare it inside the customappear
, this way you will avoid passingcontext
in contractor(if it is weird for you).Now you have
context
and you can calculate the width during the build, next is to just include it inside the home page like this and you are done:Note: I removed
StackedView
for easy testing, butStackView
does not make any difference here.