flutter / flutter/flutter

`FloatingActionButton` automatically gets positioned according to `MediaQuery.viewPadding` instead of using `MediaQuery.padding` like the `ListView` does

Open
#145,680 6 comments 0 reactions 0 assignees View on GitHub
found in release: 3.19 found in release: 3.21 has reproducible steps p: material_ui P2 package team-design triaged-design
Dominant language
Dart
Stars
179k
Forks
31.1k
PR merge metrics
PR metrics pending

Description

### Steps to reproduce

1. Run `flutter create --sample=material.NavigationBar.3 mysample`
2. Set `extendBody: true` on the main Scaffold
3. Give a RootView's Scaffold a FAB
(4. Replace the RootView's Scaffold Body with a ListView)

### Expected results

I expect the FAB to not be covered by the NavBar, but to be placed above it. Sure, one can solve it with a padding but there already exists a mechanism that the main Scaffold calculates the Navbar size and adds that size to `MediaQuery.padding` so that the ListView in the body has enough scroll space for all items to be visible. I found out that the FAB uses `MediaQuery.viewPadding` instead, so copying the `MediaQuery.padding` (which contains the calculated navbar size) of the main Scaffold body to `MediaQuery.viewPadding` achieves the desired effect. So I'm wondering if that is even advisable and why the FAB doesnt use `MediaQuery.padding` like the `ListView` does.

### Actual results

The FAB doesnt use `MediaQuery.padding` to prevent obscuration by the navbar.

### Code sample

Code sample

```dart
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

/// Flutter code sample for [NavigationBar] with nested [Navigator] destinations.
/// `flutter create --sample=material.NavigationBar.3 mysample`

void main() {
WidgetsFlutterBinding.ensureInitialized();
// make navigation bar transparent
SystemChrome.setSystemUIOverlayStyle(
const SystemUiOverlayStyle(
systemNavigationBarColor: Colors.transparent,
),
);
// make flutter draw behind navigation bar
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
runApp(const MaterialApp(home: Home()));
}

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

@override
State createState() => _HomeState();
}

class _HomeState extends State with TickerProviderStateMixin {
static const List allDestinations = [
Destination(0, 'Teal', Icons.home, Colors.teal),
Destination(1, 'Cyan', Icons.business, Colors.cyan),
Destination(2, 'Orange', Icons.school, Colors.orange),
Destination(3, 'Blue', Icons.flight, Colors.blue),
];

late final List> navigatorKeys;
late final List destinationViews;
int selectedIndex = 0;

@override
void initState() {
super.initState();

navigatorKeys = List>.generate(
allDestinations.length,
(int index) => GlobalKey(),
).toList();

destinationViews = allDestinations.map(
(Destination destination) {
return DestinationView(
destination: destination,
navigatorKey: navigatorKeys[destination.index],
);
},
).toList();
}

@override
Widget build(BuildContext context) {
return NavigatorPopHandler(
onPop: () {
final NavigatorState navigator = navigatorKeys[selectedIndex].currentState!;
navigator.pop();
},
child: Scaffold(
extendBody: true,
body: Builder(builder: (bodyContext) {
return MediaQuery(
// This is important to make the nested FAB work. If this is removed, the FAB will be hidden behind the navigation bar.
data: MediaQuery.of(bodyContext).copyWith(viewPadding: MediaQuery.of(bodyContext).padding),
child: Stack(
fit: StackFit.expand,
children: allDestinations.map(
(Destination destination) {
final int index = destination.index;
final Widget view = destinationViews[index];
if (index == selectedIndex) {
return Offstage(offstage: false, child: view);
} else {
return Offstage(child: view);
}
},
).toList(),
),
);
}),
bottomNavigationBar: NavigationBar(
backgroundColor: Colors.white.withOpacity(0.7),
selectedIndex: selectedIndex,
onDestinationSelected: (int index) {
setState(() {
selectedIndex = index;
});
},
destinations: allDestinations.map(
(Destination destination) {
return NavigationDestination(
icon: Icon(destination.icon, color: destination.color),
label: destination.title,
);
},
).toList(),
),
),
);
}
}

class Destination {
const Destination(this.index, this.title, this.icon, this.color);
final int index;
final String title;
final IconData icon;
final MaterialColor color;
}

class RootPage extends StatelessWidget {
const RootPage({super.key, required this.destination});

final Destination destination;

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('${destination.title} RootPage - /'),
backgroundColor: destination.color,
foregroundColor: Colors.white,
),
backgroundColor: destination.color[50],
floatingActionButton:
destination.index == 0 ? FloatingActionButton(onPressed: () {}, child: const Icon(Icons.add)) : null,
body: ListView.builder(
itemCount: 15, // 0 to 14 should be visible
itemBuilder: (context, index) => ListTile(title: Text(index.toString())),
),
);
}
}

class DestinationView extends StatefulWidget {
const DestinationView({
super.key,
required this.destination,
required this.navigatorKey,
});

final Destination destination;
final Key navigatorKey;

@override
State createState() => _DestinationViewState();
}

class _DestinationViewState extends State {
@override
Widget build(BuildContext context) {
return Navigator(
key: widget.navigatorKey,
onGenerateRoute: (RouteSettings settings) {
return MaterialPageRoute(
settings: settings,
builder: (BuildContext context) {
switch (settings.name) {
case '/':
return RootPage(destination: widget.destination);
}
assert(false);
return const SizedBox();
},
);
},
);
}
}

```

### Screenshots or Video

Screenshots / Video demonstration

This is the base case (without copying any MediaQuery.padding) -> The FAB is hidden behind the Navbar while the ListView automatically has enough padding so that the last item (14) is visible above the navbar.

Here, `MediaQuery.padding` of the main Scaffold body is copied to `MediaQuery.viewPadding`, so the FAB is correctly placed automatically.

### Logs

Logs

```console
[Paste your logs here]
```

### Flutter Doctor output

Doctor output

```console
[✓] Flutter (Channel stable, 3.19.2, on Microsoft Windows [Version 10.0.19045.4170], locale de-DE)
• Flutter version 3.19.2 on channel stable at C:\src\flutter
• Upstream repository https://github.com/flutter/flutter.git
• Framework revision 7482962148 (4 weeks ago), 2024-02-27 16:51:22 -0500
• Engine revision 04817c99c9
• Dart version 3.3.0
• DevTools version 2.31.1

[✓] Windows Version (Installed version of Windows is version 10 or higher)

[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
• Android SDK at C:\Users\janni\AppData\Local\Android\sdk
• Platform android-34, build-tools 34.0.0
• Java binary at: C:\Program Files\Android\Android Studio\jbr\bin\java
• Java version OpenJDK Runtime Environment (build 17.0.6+0-b2043.56-9586694)
• All Android licenses accepted.

[✗] Chrome - develop for the web (Cannot find Chrome executable at .\Google\Chrome\Application\chrome.exe)
! Cannot find Chrome. Try setting CHROME_EXECUTABLE to a Chrome executable.

[✗] Visual Studio - develop Windows apps
✗ Visual Studio not installed; this is necessary to develop Windows apps.
Download at https://visualstudio.microsoft.com/downloads/.
Please install the "Desktop development with C++" workload, including all of its default components

[✓] Android Studio (version 2022.2)
• Android Studio at C:\Program Files\Android\Android Studio
• Flutter plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/9212-flutter
• Dart plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/6351-dart
• Java version OpenJDK Runtime Environment (build 17.0.6+0-b2043.56-9586694)

[✓] VS Code, 64-bit edition (version 1.87.2)
• VS Code at C:\Program Files\Microsoft VS Code
• Flutter extension version 3.84.0

[✓] Connected device (3 available)
• sdk gphone64 x86 64 (mobile) • emulator-5554 • android-x64 • Android 14 (API 34) (emulator)
• Windows (desktop) • windows • windows-x64 • Microsoft Windows [Version 10.0.19045.4170]
• Edge (web) • edge • web-javascript • Microsoft Edge 122.0.2365.92

[✓] Network resources
• All expected network resources are available.

! Doctor found issues in 2 categories.
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.