Unverified Commit 3df0f931 authored by Hans Muller's avatar Hans Muller Committed by GitHub

Support notched BottomAppbar when Scaffold.bottomNavigationBar == null (#81228)

parent 3533321b
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'bottom_app_bar_theme.dart'; import 'bottom_app_bar_theme.dart';
...@@ -271,6 +272,7 @@ class BottomAppBar extends StatefulWidget { ...@@ -271,6 +272,7 @@ class BottomAppBar extends StatefulWidget {
class _BottomAppBarState extends State<BottomAppBar> { class _BottomAppBarState extends State<BottomAppBar> {
late ValueListenable<ScaffoldGeometry> geometryListenable; late ValueListenable<ScaffoldGeometry> geometryListenable;
final GlobalKey materialKey = GlobalKey();
static const double _defaultElevation = 8.0; static const double _defaultElevation = 8.0;
@override @override
...@@ -285,10 +287,11 @@ class _BottomAppBarState extends State<BottomAppBar> { ...@@ -285,10 +287,11 @@ class _BottomAppBarState extends State<BottomAppBar> {
final NotchedShape? notchedShape = widget.shape ?? babTheme.shape; final NotchedShape? notchedShape = widget.shape ?? babTheme.shape;
final CustomClipper<Path> clipper = notchedShape != null final CustomClipper<Path> clipper = notchedShape != null
? _BottomAppBarClipper( ? _BottomAppBarClipper(
geometry: geometryListenable, geometry: geometryListenable,
shape: notchedShape, shape: notchedShape,
notchMargin: widget.notchMargin, materialKey: materialKey,
) notchMargin: widget.notchMargin,
)
: const ShapeBorderClipper(shape: RoundedRectangleBorder()); : const ShapeBorderClipper(shape: RoundedRectangleBorder());
final double elevation = widget.elevation ?? babTheme.elevation ?? _defaultElevation; final double elevation = widget.elevation ?? babTheme.elevation ?? _defaultElevation;
final Color color = widget.color ?? babTheme.color ?? Theme.of(context).bottomAppBarColor; final Color color = widget.color ?? babTheme.color ?? Theme.of(context).bottomAppBarColor;
...@@ -299,6 +302,7 @@ class _BottomAppBarState extends State<BottomAppBar> { ...@@ -299,6 +302,7 @@ class _BottomAppBarState extends State<BottomAppBar> {
color: effectiveColor, color: effectiveColor,
clipBehavior: widget.clipBehavior, clipBehavior: widget.clipBehavior,
child: Material( child: Material(
key: materialKey,
type: MaterialType.transparency, type: MaterialType.transparency,
child: widget.child == null child: widget.child == null
? null ? null
...@@ -312,6 +316,7 @@ class _BottomAppBarClipper extends CustomClipper<Path> { ...@@ -312,6 +316,7 @@ class _BottomAppBarClipper extends CustomClipper<Path> {
const _BottomAppBarClipper({ const _BottomAppBarClipper({
required this.geometry, required this.geometry,
required this.shape, required this.shape,
required this.materialKey,
required this.notchMargin, required this.notchMargin,
}) : assert(geometry != null), }) : assert(geometry != null),
assert(shape != null), assert(shape != null),
...@@ -320,17 +325,21 @@ class _BottomAppBarClipper extends CustomClipper<Path> { ...@@ -320,17 +325,21 @@ class _BottomAppBarClipper extends CustomClipper<Path> {
final ValueListenable<ScaffoldGeometry> geometry; final ValueListenable<ScaffoldGeometry> geometry;
final NotchedShape shape; final NotchedShape shape;
final GlobalKey materialKey;
final double notchMargin; final double notchMargin;
// Returns the top of the BottomAppBar in global coordinates.
double get bottomNavigationBarTop {
final RenderBox? box = materialKey.currentContext?.findRenderObject() as RenderBox?;
return box?.localToGlobal(Offset.zero).dy ?? 0;
}
@override @override
Path getClip(Size size) { Path getClip(Size size) {
// button is the floating action button's bounding rectangle in the // button is the floating action button's bounding rectangle in the
// coordinate system whose origin is at the appBar's top left corner, // coordinate system whose origin is at the appBar's top left corner,
// or null if there is no floating action button. // or null if there is no floating action button.
final Rect? button = geometry.value.floatingActionButtonArea?.translate( final Rect? button = geometry.value.floatingActionButtonArea?.translate(0.0, bottomNavigationBarTop * -1.0);
0.0,
geometry.value.bottomNavigationBarTop! * -1.0,
);
return shape.getOuterPath(Offset.zero & size, button?.inflate(notchMargin)); return shape.getOuterPath(Offset.zero & size, button?.inflate(notchMargin));
} }
......
...@@ -381,6 +381,40 @@ void main() { ...@@ -381,6 +381,40 @@ void main() {
physicalShape = tester.widget(find.byType(PhysicalShape)); physicalShape = tester.widget(find.byType(PhysicalShape));
expect(physicalShape.clipBehavior, Clip.antiAliasWithSaveLayer); expect(physicalShape.clipBehavior, Clip.antiAliasWithSaveLayer);
}); });
testWidgets('BottomAppBar with shape when Scaffold.bottomNavigationBar == null', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/80878
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.green,
child: const Icon(Icons.home),
onPressed: () {},
),
body: Stack(
children: <Widget>[
Container(
color: Colors.amber,
),
Container(
alignment: Alignment.bottomCenter,
child: BottomAppBar(
color: Colors.green,
shape: const CircularNotchedRectangle(),
child: Container(height: 50),
),
),
],
),
),
),
);
expect(tester.getRect(find.byType(FloatingActionButton)), const Rect.fromLTRB(372, 528, 428, 584));
expect(tester.getSize(find.byType(BottomAppBar)), const Size(800, 50));
});
} }
// The bottom app bar clip path computation is only available at paint time. // The bottom app bar clip path computation is only available at paint time.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment