Size and Layout
On the iPhone 8, original buttons have a size of 40x40 points, 16 points margin to the screen edge and 8 points bottom offset. Given that app bar has a height of 44 points on this iPhone it would mean that those buttons have to overlay status bar (the one with signal strength, clock and battery status) and indeed they are:

We can apply those constraints by wrapping our button widgets in Padding and Align.
return Padding(
padding: EdgeInsets.fromLTRB(
position == AppBarPosition.leading ? 16 : 0, 0,
position == AppBarPosition.trailing ? 16 : 0, 8),
child: Align(
alignment: Alignment.topCenter,
child: Container(
width: 40,
height: 40,
(...)

One difference is that the bottom offset is bigger in our implementation and we don’t even overflow status bar. The reason is that the height of our app bar is calculated based on the const double kToolbarHeight = 56.0; constant from the Flutter development framework. There is no explicit way to set app bar height, eg. by constructor parameter, and the class responsible for the app bar layout, which uses this constant, is private (_SliverAppBarDelegate).
This prevents us from using inheritance to override the code responsible for height computation. This delegate is, again, not exposed by the app bar (SliverAppBar), so even if we end up creating our own version, we won’t be able to use it unless we also extend SliverAppBar and override build method from its state.
Since Flutter is open source this could be done in a few minutes, by copy-paste original implementation and tweaking those details, but it’s far from feasible solution as we would have to maintain our version and keep it in sync with improvements made by the Flutter team to the original classes.
It’s worth to take a note, that kToolbarHeight is also used to constraint the width of the leading widget (back button in our case), forcing it to be a square. This is how our app bar looks like with margins increased to 25 points. Notice the shrunken leading button, while trailing is spaced from the screen edge as expected. This limitation has no effect in our case, as designed margin and button size is exactly matching available space.

Highlight Behavior
In the Wolt app when the button is highlighted it changes the opacity of the icon. There is no highlight colour change or splash animation. We can re-create such behaviour by wrapping button in the Opacity widget. To track highlight status we have to introduce an internal state, represented by the _isHighlighted boolean property. That means we have to refactor our widget from stateless to stateful:
enum AppBarPosition {
leading,
trailing,
}
class AppBarButton extends StatefulWidget {
final IconData icon;
final VoidCallback onPressed;
final AppBarPosition position;
const AppBarButton({Key key, this.icon, this.onPressed, this.position}) : super(key: key);
@override
_AppBarButtonState createState() => _AppBarButtonState();
}
class _AppBarButtonState extends State {
bool _isHighlighted = false;
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.fromLTRB(widget.position == AppBarPosition.leading ? 16 : 0, 0,
widget.position == AppBarPosition.trailing ? 16 : 0, 8),
child: Align(
alignment: Alignment.topCenter,
child: Container(
width: 40,
height: 40,
decoration: BoxDecoration(shape: BoxShape.circle, color: Colors.grey[300]),
child: Opacity(
opacity: _isHighlighted ? 0.3 : 1.0,
child: IconButton(
icon: Icon(
widget.icon,
color: Colors.black,
),
onPressed: widget.onPressed,
),
),
),
),
);
}
}
Unfortunately, IconButton we are using is not exposing onHighlightChanged callback — only onPressed, which is not enough for our needs. We have to refactor our code to use more generic button class, like RawMaterialButton where we have more control over callbacks and visual settings.
child: RawMaterialButton(
highlightColor: Colors.transparent,
splashColor: Colors.transparent,
onHighlightChanged: (isHighlighted) => setState(() {
_isHighlighted = isHighlighted;
}),
child: Icon(
widget.icon,
color: Colors.black,
),
onPressed: widget.onPressed,
),
Choose Flutter for Familiar UI & UX on iOS and Android
Flutter allowed us to recreate, very closely, UI and UX of Wolt’s piece of the interface. We were able to achieve the compelling look & feel quickly by composing native widgets, and even if there are certain limitations, due to open-source nature of the Flutter framework, achieving pixel-perfect quality is possible when needed. Flutter's features and ease of development made it a popular tech stack choice among many companies.

Related articles
Supporting companies in becoming category leaders. We deliver full-cycle solutions for businesses of all sizes.