fluent_ui
fluent_ui copied to clipboard
Allow overwriting the NavigationAppBar Layout
Is your feature request related to a problem? Please describe.
I want to implement some custom layout for the NavigationAppBar.
Describe the solution you'd like
It would be nice if NavigationAppBar would take an optional builder, in order to allow overwriting this behavior:
https://github.com/bdlukaa/fluent_ui/blob/0522bf08d28676619324c3ec5be5405fc93a22d2/lib/src/controls/navigation/navigation_view/view.dart#L889-L925
Describe alternatives you've considered
The NavigationAppBar could also have a build-like method instead of the builder. For building a custom design, one could extend NavigationAppBar and override the build method.
Additional context
I want the design shown in the screenshot.
The MyApp should never overlay the Hamburger Icon and the Close button should fill the corner.
Additionally there should be a DragToMoveArea stacked behind the Row.

The title widget should take the whole app bar. actions, on the other hand, will be drawn on top of the title.
You can perform this layout by providing the desired layout to the title property
I think I tried this and it resulted in a white bar at the right side of the red button.
I'll retry it tomorrow.
TLDR; By using title and action and manually accounting for the actions width, my goal seems to be achievable, but I don't think it's an elegant solution and it still has a limitation.
Using actions
The CommandBarCard is in front of the leading Button. ❌
Code
import 'package:fluent_ui/fluent_ui.dart';
import 'package:flutter_acrylic/flutter_acrylic.dart' as flutter_acrylic;
import 'package:window_manager/window_manager.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await flutter_acrylic.Window.initialize();
await WindowManager.instance.ensureInitialized();
windowManager.waitUntilReadyToShow(
const WindowOptions(
minimumSize: Size(350, 600),
center: true,
titleBarStyle: TitleBarStyle.hidden,
fullScreen: false,
),
() async {
await windowManager.show();
await windowManager.setPreventClose(false);
await windowManager.focus();
},
);
runApp(FluentApp(
debugShowCheckedModeBanner: false,
home: NavigationView(
appBar: NavigationAppBar(
actions: Row(
children: [
Expanded(
child: CommandBarCard(
child: CommandBar(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.center,
primaryItems: [
CommandBarButton(onPressed: () {}, label: Text("Button1")),
CommandBarButton(onPressed: () {}, label: Text("Button2")),
CommandBarButton(onPressed: () {}, label: Text("Button3")),
CommandBarButton(onPressed: () {}, label: Text("Button4")),
]),
)),
SizedBox(
width: 138,
height: 50,
child: WindowCaption(
backgroundColor: Colors.transparent,
),
),
],
)),
pane: NavigationPane(items: []),
),
));
}
Using title
The red close button is not in the corner. ❌
Code
import 'package:fluent_ui/fluent_ui.dart';
import 'package:flutter_acrylic/flutter_acrylic.dart' as flutter_acrylic;
import 'package:window_manager/window_manager.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await flutter_acrylic.Window.initialize();
await WindowManager.instance.ensureInitialized();
windowManager.waitUntilReadyToShow(
const WindowOptions(
minimumSize: Size(350, 600),
center: true,
titleBarStyle: TitleBarStyle.hidden,
fullScreen: false,
),
() async {
await windowManager.show();
await windowManager.setPreventClose(false);
await windowManager.focus();
},
);
runApp(FluentApp(
debugShowCheckedModeBanner: false,
home: NavigationView(
appBar: NavigationAppBar(
title: Row(
children: [
Expanded(
child: CommandBarCard(
child: CommandBar(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.center,
primaryItems: [
CommandBarButton(onPressed: () {}, label: Text("Button1")),
CommandBarButton(onPressed: () {}, label: Text("Button2")),
CommandBarButton(onPressed: () {}, label: Text("Button3")),
CommandBarButton(onPressed: () {}, label: Text("Button4")),
]),
)),
SizedBox(
width: 138,
height: 50,
child: WindowCaption(
backgroundColor: Colors.transparent,
),
),
],
)),
pane: NavigationPane(items: []),
),
));
}
Using title and action
Title and actions are stacked on top of each other. ❌
Code
import 'package:fluent_ui/fluent_ui.dart';
import 'package:flutter_acrylic/flutter_acrylic.dart' as flutter_acrylic;
import 'package:window_manager/window_manager.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await flutter_acrylic.Window.initialize();
await WindowManager.instance.ensureInitialized();
windowManager.waitUntilReadyToShow(
const WindowOptions(
minimumSize: Size(350, 600),
center: true,
titleBarStyle: TitleBarStyle.hidden,
fullScreen: false,
),
() async {
await windowManager.show();
await windowManager.setPreventClose(false);
await windowManager.focus();
},
);
runApp(FluentApp(
debugShowCheckedModeBanner: false,
home: NavigationView(
appBar: NavigationAppBar(
title: Expanded(
child: CommandBarCard(
child: CommandBar(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.center,
primaryItems: [
CommandBarButton(onPressed: () {}, label: Text("Button1")),
CommandBarButton(onPressed: () {}, label: Text("Button2")),
CommandBarButton(onPressed: () {}, label: Text("Button3")),
CommandBarButton(onPressed: () {}, label: Text("Button4")),
]),
)),
actions: SizedBox(
width: 138,
height: 50,
child: WindowCaption(
backgroundColor: Colors.transparent,
),
),
),
pane: NavigationPane(items: []),
),
));
}
Using title and action and manually accounting for the actions width
Actually works, I did not think about this solution earlier, but I don't think this solution is elegant. ✅
Code
import 'package:fluent_ui/fluent_ui.dart';
import 'package:flutter_acrylic/flutter_acrylic.dart' as flutter_acrylic;
import 'package:window_manager/window_manager.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await flutter_acrylic.Window.initialize();
await WindowManager.instance.ensureInitialized();
windowManager.waitUntilReadyToShow(
const WindowOptions(
minimumSize: Size(350, 600),
center: true,
titleBarStyle: TitleBarStyle.hidden,
fullScreen: false,
),
() async {
await windowManager.show();
await windowManager.setPreventClose(false);
await windowManager.focus();
},
);
runApp(FluentApp(
debugShowCheckedModeBanner: false,
home: NavigationView(
appBar: NavigationAppBar(
title: Row(
children: [
Expanded(
child: CommandBarCard(
child: CommandBar(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.center,
primaryItems: [
CommandBarButton(onPressed: () {}, label: Text("Button1")),
CommandBarButton(onPressed: () {}, label: Text("Button2")),
CommandBarButton(onPressed: () {}, label: Text("Button3")),
CommandBarButton(onPressed: () {}, label: Text("Button4")),
]),
)),
SizedBox(width: 138),
],
),
actions: SizedBox(
width: 138,
height: 50,
child: WindowCaption(
backgroundColor: Colors.transparent,
),
),
),
pane: NavigationPane(items: []),
),
));
}

On the native side, the title always go behind the window features (title and actions). But I also agree that there is a "search bar" (or something related) in some native UWP apps
This is a hard problem to solve, because desktop aims adaptability of different window sizes, otherwise it can cause to some weird effects. Here is a screenshot of "Slack" with a small size:
On the other hand, on Task Manager, the "search bar" window feature works differently. If there isn't enough space, the bar is changed to a button:
Differently, Microsoft Store just resizes to the minimum size and keep the search bar functionality:
But, after it all, none of the above is described in the Win UI documentation. In fact, the only option Microsoft provides to add some custom content is either:
AutoSuggestBoxPaneCustomContent, a property that displays some content after the pane items
I like the idea of having a possibility to add a custom functionality to the top bar, but this is not something that can be built-in the package. I will stand the point that the title property can be used to display such things, since a LayoutBuilder can be used to achieve adaptability.
I don't think this can be implemented into the package because there isn't a strict documentation about it, so the developers will need to invent the desired behavior themselves. In fact, not even the window buttons (minimize, maximize/resume, close) are provided by the package, since it's not in the documentation.