blob: 0ffa2657071b63620ef27f76cfc8232efc1ff309 [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
void main() {
testWidgets('no overlap with floating action button', (WidgetTester tester) async {
await tester.pumpWidget(
new MaterialApp(
home: const Scaffold(
floatingActionButton: const FloatingActionButton(
onPressed: null,
),
bottomNavigationBar: const ShapeListener(const BottomAppBar()),
),
),
);
final ShapeListenerState shapeListenerState = tester.state(find.byType(ShapeListener));
final RenderBox renderBox = tester.renderObject(find.byType(BottomAppBar));
final Path expectedPath = new Path()
..addRect(Offset.zero & renderBox.size);
final Path actualPath = shapeListenerState.cache.value;
expect(
actualPath,
coversSameAreaAs(
expectedPath,
areaToCompare: (Offset.zero & renderBox.size).inflate(5.0),
)
);
});
// TODO(amirh): test a BottomAppBar with hasNotch=false and an overlapping
// FAB.
//
// Cannot test this before https://github.com/flutter/flutter/pull/14368
// as there is no way to make the FAB and BAB overlap.
}
// The bottom app bar clip path computation is only available at paint time.
// In order to examine the notch path we implement this caching painter which
// at paint time looks for for a descendant PhysicalShape and caches the
// clip path it is using.
class ClipCachePainter extends CustomPainter {
ClipCachePainter(this.context);
Path value;
BuildContext context;
@override
void paint(Canvas canvas, Size size) {
final RenderPhysicalShape physicalShape = findPhysicalShapeChild(context);
value = physicalShape.clipper.getClip(size);
}
RenderPhysicalShape findPhysicalShapeChild(BuildContext context) {
RenderPhysicalShape result;
context.visitChildElements((Element e) {
final RenderObject renderObject = e.findRenderObject();
if (renderObject.runtimeType == RenderPhysicalShape) {
assert(result == null);
result = renderObject;
} else {
result = findPhysicalShapeChild(e);
}
});
return result;
}
@override
bool shouldRepaint(ClipCachePainter oldDelegate) {
return true;
}
}
class ShapeListener extends StatefulWidget {
const ShapeListener(this.child);
final Widget child;
@override
State createState() => new ShapeListenerState();
}
class ShapeListenerState extends State<ShapeListener> {
@override
Widget build(BuildContext context) {
return new CustomPaint(
child: widget.child,
painter: cache
);
}
ClipCachePainter cache;
@override
void didChangeDependencies() {
super.didChangeDependencies();
cache = new ClipCachePainter(context);
}
}