Support notched BottomAppbar when Scaffold.bottomNavigationBar == null (#81228)
This commit is contained in:
parent
3533321b1a
commit
3df0f931fa
@ -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 {
|
|||||||
|
|
||||||
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> {
|
|||||||
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> {
|
|||||||
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> {
|
|||||||
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> {
|
|||||||
|
|
||||||
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() {
|
|||||||
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.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user