expose scaled fab area in ScaffoldGeometry (#14683)
This commit is contained in:
parent
a11da23852
commit
9bc3bc9822
@ -37,9 +37,6 @@ enum _ScaffoldSlot {
|
|||||||
statusBar,
|
statusBar,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Examples can assume:
|
|
||||||
// ScaffoldGeometry scaffoldGeometry;
|
|
||||||
|
|
||||||
/// Geometry information for scaffold components.
|
/// Geometry information for scaffold components.
|
||||||
///
|
///
|
||||||
/// To get a [ValueNotifier] for the scaffold geometry call
|
/// To get a [ValueNotifier] for the scaffold geometry call
|
||||||
@ -49,7 +46,6 @@ class ScaffoldGeometry {
|
|||||||
const ScaffoldGeometry({
|
const ScaffoldGeometry({
|
||||||
this.bottomNavigationBarTop,
|
this.bottomNavigationBarTop,
|
||||||
this.floatingActionButtonArea,
|
this.floatingActionButtonArea,
|
||||||
this.floatingActionButtonScale: 1.0,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/// The distance from the scaffold's top edge to the top edge of the
|
/// The distance from the scaffold's top edge to the top edge of the
|
||||||
@ -62,38 +58,35 @@ class ScaffoldGeometry {
|
|||||||
/// The rectangle in which the scaffold is laying out
|
/// The rectangle in which the scaffold is laying out
|
||||||
/// [Scaffold.floatingActionButton].
|
/// [Scaffold.floatingActionButton].
|
||||||
///
|
///
|
||||||
/// The floating action button might be scaled inside this rectangle, to get
|
|
||||||
/// the bounding rectangle in which the floating action is painted scale this
|
|
||||||
/// value by [floatingActionButtonScale].
|
|
||||||
///
|
|
||||||
/// ## Sample code
|
|
||||||
///
|
|
||||||
/// ```dart
|
|
||||||
/// final Rect scaledFab = Rect.lerp(
|
|
||||||
/// scaffoldGeometry.floatingActionButtonArea.center & Size.zero,
|
|
||||||
/// scaffoldGeometry.floatingActionButtonArea,
|
|
||||||
/// scaffoldGeometry.floatingActionButtonScale
|
|
||||||
/// );
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// This is null when there is no floating action button showing.
|
/// This is null when there is no floating action button showing.
|
||||||
final Rect floatingActionButtonArea;
|
final Rect floatingActionButtonArea;
|
||||||
|
|
||||||
/// The amount by which the [Scaffold.floatingActionButton] is scaled.
|
ScaffoldGeometry _scaleFab(double scaleFactor) {
|
||||||
///
|
if (scaleFactor == 1.0)
|
||||||
/// To get the bounding rectangle in which the floating action button is
|
return this;
|
||||||
/// painted scaled [floatingActionPosition] by this proportion.
|
|
||||||
///
|
if (scaleFactor == 0.0)
|
||||||
/// This will be 0 when there is no [Scaffold.floatingActionButton] set.
|
return new ScaffoldGeometry(bottomNavigationBarTop: bottomNavigationBarTop);
|
||||||
final double floatingActionButtonScale;
|
|
||||||
|
final Rect scaledFab = Rect.lerp(
|
||||||
|
floatingActionButtonArea.center & Size.zero,
|
||||||
|
floatingActionButtonArea,
|
||||||
|
scaleFactor
|
||||||
|
);
|
||||||
|
return new ScaffoldGeometry(
|
||||||
|
bottomNavigationBarTop: bottomNavigationBarTop,
|
||||||
|
floatingActionButtonArea: scaledFab,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ScaffoldGeometryNotifier extends ValueNotifier<ScaffoldGeometry> {
|
class _ScaffoldGeometryNotifier extends ChangeNotifier implements ValueListenable<ScaffoldGeometry> {
|
||||||
_ScaffoldGeometryNotifier(ScaffoldGeometry geometry, this.context)
|
_ScaffoldGeometryNotifier(this.geometry, this.context)
|
||||||
: assert (context != null),
|
: assert (context != null);
|
||||||
super(geometry);
|
|
||||||
|
|
||||||
final BuildContext context;
|
final BuildContext context;
|
||||||
|
double fabScale;
|
||||||
|
ScaffoldGeometry geometry;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
ScaffoldGeometry get value {
|
ScaffoldGeometry get value {
|
||||||
@ -107,7 +100,7 @@ class _ScaffoldGeometryNotifier extends ValueNotifier<ScaffoldGeometry> {
|
|||||||
);
|
);
|
||||||
return true;
|
return true;
|
||||||
}());
|
}());
|
||||||
return super.value;
|
return geometry._scaleFab(fabScale);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _updateWith({
|
void _updateWith({
|
||||||
@ -115,16 +108,12 @@ class _ScaffoldGeometryNotifier extends ValueNotifier<ScaffoldGeometry> {
|
|||||||
Rect floatingActionButtonArea,
|
Rect floatingActionButtonArea,
|
||||||
double floatingActionButtonScale,
|
double floatingActionButtonScale,
|
||||||
}) {
|
}) {
|
||||||
final double newFloatingActionButtonScale = floatingActionButtonScale ?? super.value?.floatingActionButtonScale;
|
fabScale = floatingActionButtonScale ?? fabScale;
|
||||||
Rect newFloatingActionButtonArea;
|
geometry = new ScaffoldGeometry(
|
||||||
if (newFloatingActionButtonScale != 0.0)
|
bottomNavigationBarTop: bottomNavigationBarTop ?? geometry?.bottomNavigationBarTop,
|
||||||
newFloatingActionButtonArea = floatingActionButtonArea ?? super.value?.floatingActionButtonArea;
|
floatingActionButtonArea: floatingActionButtonArea ?? geometry?.floatingActionButtonArea,
|
||||||
|
|
||||||
value = new ScaffoldGeometry(
|
|
||||||
bottomNavigationBarTop: bottomNavigationBarTop ?? super.value?.bottomNavigationBarTop,
|
|
||||||
floatingActionButtonArea: newFloatingActionButtonArea,
|
|
||||||
floatingActionButtonScale: newFloatingActionButtonScale,
|
|
||||||
);
|
);
|
||||||
|
notifyListeners();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -832,10 +832,6 @@ void main() {
|
|||||||
geometry.floatingActionButtonArea,
|
geometry.floatingActionButtonArea,
|
||||||
fabRect
|
fabRect
|
||||||
);
|
);
|
||||||
expect(
|
|
||||||
geometry.floatingActionButtonScale,
|
|
||||||
1.0
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('no floatingActionButton', (WidgetTester tester) async {
|
testWidgets('no floatingActionButton', (WidgetTester tester) async {
|
||||||
@ -849,11 +845,6 @@ void main() {
|
|||||||
final GeometryListenerState listenerState = tester.state(find.byType(GeometryListener));
|
final GeometryListenerState listenerState = tester.state(find.byType(GeometryListener));
|
||||||
final ScaffoldGeometry geometry = listenerState.cache.value;
|
final ScaffoldGeometry geometry = listenerState.cache.value;
|
||||||
|
|
||||||
expect(
|
|
||||||
geometry.floatingActionButtonScale,
|
|
||||||
0.0
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
geometry.floatingActionButtonArea,
|
geometry.floatingActionButtonArea,
|
||||||
null
|
null
|
||||||
@ -878,18 +869,77 @@ void main() {
|
|||||||
),
|
),
|
||||||
)));
|
)));
|
||||||
|
|
||||||
|
final GeometryListenerState listenerState = tester.state(find.byType(GeometryListener));
|
||||||
await tester.pump(const Duration(milliseconds: 50));
|
await tester.pump(const Duration(milliseconds: 50));
|
||||||
|
|
||||||
final GeometryListenerState listenerState = tester.state(find.byType(GeometryListener));
|
ScaffoldGeometry geometry = listenerState.cache.value;
|
||||||
final ScaffoldGeometry geometry = listenerState.cache.value;
|
|
||||||
|
final Rect transitioningFabRect = geometry.floatingActionButtonArea;
|
||||||
|
|
||||||
|
await tester.pump(const Duration(seconds: 3));
|
||||||
|
geometry = listenerState.cache.value;
|
||||||
|
final RenderBox floatingActionButtonBox = tester.renderObject(find.byKey(key));
|
||||||
|
final Rect fabRect = floatingActionButtonBox.localToGlobal(Offset.zero) & floatingActionButtonBox.size;
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
geometry.floatingActionButtonScale,
|
geometry.floatingActionButtonArea,
|
||||||
inExclusiveRange(0.0, 1.0),
|
fabRect
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
geometry.floatingActionButtonArea.center,
|
||||||
|
transitioningFabRect.center
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
geometry.floatingActionButtonArea.width,
|
||||||
|
greaterThan(transitioningFabRect.width)
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
geometry.floatingActionButtonArea.height,
|
||||||
|
greaterThan(transitioningFabRect.height)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
|
testWidgets('change notifications', (WidgetTester tester) async {
|
||||||
|
final GlobalKey key = new GlobalKey();
|
||||||
|
int numNotificationsAtLastFrame = 0;
|
||||||
|
await tester.pumpWidget(new MaterialApp(home: new Scaffold(
|
||||||
|
body: new ConstrainedBox(
|
||||||
|
constraints: const BoxConstraints.expand(height: 80.0),
|
||||||
|
child: new GeometryListener(),
|
||||||
|
),
|
||||||
|
)));
|
||||||
|
|
||||||
|
final GeometryListenerState listenerState = tester.state(find.byType(GeometryListener));
|
||||||
|
|
||||||
|
expect(listenerState.numNotifications, greaterThan(numNotificationsAtLastFrame));
|
||||||
|
numNotificationsAtLastFrame = listenerState.numNotifications;
|
||||||
|
|
||||||
|
await tester.pumpWidget(new MaterialApp(home: new Scaffold(
|
||||||
|
body: new Container(),
|
||||||
|
floatingActionButton: new FloatingActionButton(
|
||||||
|
key: key,
|
||||||
|
child: new GeometryListener(),
|
||||||
|
onPressed: () {},
|
||||||
|
),
|
||||||
|
)));
|
||||||
|
|
||||||
|
expect(listenerState.numNotifications, greaterThan(numNotificationsAtLastFrame));
|
||||||
|
numNotificationsAtLastFrame = listenerState.numNotifications;
|
||||||
|
|
||||||
|
await tester.pump(const Duration(milliseconds: 50));
|
||||||
|
|
||||||
|
expect(listenerState.numNotifications, greaterThan(numNotificationsAtLastFrame));
|
||||||
|
numNotificationsAtLastFrame = listenerState.numNotifications;
|
||||||
|
|
||||||
|
await tester.pump(const Duration(seconds: 3));
|
||||||
|
|
||||||
|
expect(listenerState.numNotifications, greaterThan(numNotificationsAtLastFrame));
|
||||||
|
numNotificationsAtLastFrame = listenerState.numNotifications;
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
class GeometryListener extends StatefulWidget {
|
class GeometryListener extends StatefulWidget {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user