Unverified Commit 14f1e13e authored by Hans Muller's avatar Hans Muller Committed by GitHub

Reland Fix AnimatedList & AnimatedGrid doesn't apply MediaQuery padding #129556 (#129860)

Reland https://github.com/flutter/flutter/pull/129556/ which had failed
an internal test (see Google internal link b/288993600) and was reverted
in https://github.com/flutter/flutter/pull/129645.

This PR must be landed with G3 Fix cl/543755631
parent f37a4d05
......@@ -6,6 +6,7 @@ import 'package:flutter/foundation.dart';
import 'basic.dart';
import 'framework.dart';
import 'media_query.dart';
import 'scroll_controller.dart';
import 'scroll_delegate.dart';
import 'scroll_physics.dart';
......@@ -30,6 +31,35 @@ import 'ticker_provider.dart';
/// ** See code in examples/api/lib/widgets/animated_list/animated_list.0.dart **
/// {@end-tool}
///
/// By default, [AnimatedList] will automatically pad the limits of the
/// list's scrollable to avoid partial obstructions indicated by
/// [MediaQuery]'s padding. To avoid this behavior, override with a
/// zero [padding] property.
///
/// {@tool snippet}
/// The following example demonstrates how to override the default top and
/// bottom padding using [MediaQuery.removePadding].
///
/// ```dart
/// Widget myWidget(BuildContext context) {
/// return MediaQuery.removePadding(
/// context: context,
/// removeTop: true,
/// removeBottom: true,
/// child: AnimatedList(
/// initialItemCount: 50,
/// itemBuilder: (BuildContext context, int index, Animation<double> animation) {
/// return Card(
/// color: Colors.amber,
/// child: Center(child: Text('$index')),
/// );
/// }
/// ),
/// );
/// }
/// ```
/// {@end-tool}
///
/// See also:
///
/// * [SliverAnimatedList], a sliver that animates items when they are inserted
......@@ -176,6 +206,7 @@ class AnimatedListState extends _AnimatedScrollViewState<AnimatedList> {
itemBuilder: widget.itemBuilder,
initialItemCount: widget.initialItemCount,
),
widget.scrollDirection,
);
}
}
......@@ -196,6 +227,38 @@ class AnimatedListState extends _AnimatedScrollViewState<AnimatedList> {
/// ** See code in examples/api/lib/widgets/animated_grid/animated_grid.0.dart **
/// {@end-tool}
///
/// By default, [AnimatedGrid] will automatically pad the limits of the
/// grid's scrollable to avoid partial obstructions indicated by
/// [MediaQuery]'s padding. To avoid this behavior, override with a
/// zero [padding] property.
///
/// {@tool snippet}
/// The following example demonstrates how to override the default top and
/// bottom padding using [MediaQuery.removePadding].
///
/// ```dart
/// Widget myWidget(BuildContext context) {
/// return MediaQuery.removePadding(
/// context: context,
/// removeTop: true,
/// removeBottom: true,
/// child: AnimatedGrid(
/// gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
/// crossAxisCount: 3,
/// ),
/// initialItemCount: 50,
/// itemBuilder: (BuildContext context, int index, Animation<double> animation) {
/// return Card(
/// color: Colors.amber,
/// child: Center(child: Text('$index')),
/// );
/// }
/// ),
/// );
/// }
/// ```
/// {@end-tool}
///
/// See also:
///
/// * [SliverAnimatedGrid], a sliver which animates items when they are inserted
......@@ -353,6 +416,7 @@ class AnimatedGridState extends _AnimatedScrollViewState<AnimatedGrid> {
itemBuilder: widget.itemBuilder,
initialItemCount: widget.initialItemCount,
),
widget.scrollDirection,
);
}
}
......@@ -529,7 +593,35 @@ abstract class _AnimatedScrollViewState<T extends _AnimatedScrollView> extends S
_sliverAnimatedMultiBoxKey.currentState!.removeAllItems(builder, duration: duration);
}
Widget _wrap(Widget sliver) {
Widget _wrap(Widget sliver, Axis direction) {
EdgeInsetsGeometry? effectivePadding = widget.padding;
if (widget.padding == null) {
final MediaQueryData? mediaQuery = MediaQuery.maybeOf(context);
if (mediaQuery != null) {
// Automatically pad sliver with padding from MediaQuery.
final EdgeInsets mediaQueryHorizontalPadding =
mediaQuery.padding.copyWith(top: 0.0, bottom: 0.0);
final EdgeInsets mediaQueryVerticalPadding =
mediaQuery.padding.copyWith(left: 0.0, right: 0.0);
// Consume the main axis padding with SliverPadding.
effectivePadding = direction == Axis.vertical
? mediaQueryVerticalPadding
: mediaQueryHorizontalPadding;
// Leave behind the cross axis padding.
sliver = MediaQuery(
data: mediaQuery.copyWith(
padding: direction == Axis.vertical
? mediaQueryHorizontalPadding
: mediaQueryVerticalPadding,
),
child: sliver,
);
}
}
if (effectivePadding != null) {
sliver = SliverPadding(padding: effectivePadding, sliver: sliver);
}
return CustomScrollView(
scrollDirection: widget.scrollDirection,
reverse: widget.reverse,
......@@ -538,12 +630,7 @@ abstract class _AnimatedScrollViewState<T extends _AnimatedScrollView> extends S
physics: widget.physics,
clipBehavior: widget.clipBehavior,
shrinkWrap: widget.shrinkWrap,
slivers: <Widget>[
SliverPadding(
padding: widget.padding ?? EdgeInsets.zero,
sliver: sliver,
),
],
slivers: <Widget>[ sliver ],
);
}
}
......
......@@ -646,6 +646,45 @@ void main() {
expect(tester.widget<CustomScrollView>(find.byType(CustomScrollView)).clipBehavior, clipBehavior);
});
testWidgets('AnimatedGrid applies MediaQuery padding', (WidgetTester tester) async {
const EdgeInsets padding = EdgeInsets.all(30.0);
EdgeInsets? innerMediaQueryPadding;
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: MediaQuery(
data: const MediaQueryData(
padding: EdgeInsets.all(30.0),
),
child: AnimatedGrid(
initialItemCount: 6,
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
),
itemBuilder: (BuildContext context, int index, Animation<double> animation) {
innerMediaQueryPadding = MediaQuery.paddingOf(context);
return const Placeholder();
},
),
),
),
);
final Offset topLeft = tester.getTopLeft(find.byType(Placeholder).first);
// Automatically apply the top padding into sliver.
expect(topLeft, Offset(0.0, padding.top));
// Scroll to the bottom.
await tester.drag(find.byType(AnimatedGrid), const Offset(0.0, -1000.0));
await tester.pumpAndSettle();
final Offset bottomRight = tester.getBottomRight(find.byType(Placeholder).last);
// Automatically apply the bottom padding into sliver.
expect(bottomRight, Offset(800.0, 600.0 - padding.bottom));
// Verify that the left/right padding is not applied.
expect(innerMediaQueryPadding, const EdgeInsets.symmetric(horizontal: 30.0));
});
}
class _StatefulListItem extends StatefulWidget {
......
......@@ -649,6 +649,42 @@ void main() {
expect(tester.widget<CustomScrollView>(find.byType(CustomScrollView)).shrinkWrap, true);
});
testWidgets('AnimatedList applies MediaQuery padding', (WidgetTester tester) async {
const EdgeInsets padding = EdgeInsets.all(30.0);
EdgeInsets? innerMediaQueryPadding;
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: MediaQuery(
data: const MediaQueryData(
padding: EdgeInsets.all(30.0),
),
child: AnimatedList(
initialItemCount: 3,
itemBuilder: (BuildContext context, int index, Animation<double> animation) {
innerMediaQueryPadding = MediaQuery.paddingOf(context);
return const Placeholder();
},
),
),
),
);
final Offset topLeft = tester.getTopLeft(find.byType(Placeholder).first);
// Automatically apply the top padding into sliver.
expect(topLeft, Offset(0.0, padding.top));
// Scroll to the bottom.
await tester.drag(find.byType(AnimatedList), const Offset(0.0, -1000.0));
await tester.pumpAndSettle();
final Offset bottomLeft = tester.getBottomLeft(find.byType(Placeholder).last);
// Automatically apply the bottom padding into sliver.
expect(bottomLeft, Offset(0.0, 600.0 - padding.bottom));
// Verify that the left/right padding is not applied.
expect(innerMediaQueryPadding, const EdgeInsets.symmetric(horizontal: 30.0));
});
}
......
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