Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
101 changes: 94 additions & 7 deletions packages/flutter/lib/src/widgets/animated_scroll_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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
Expand Down Expand Up @@ -176,6 +206,7 @@ class AnimatedListState extends _AnimatedScrollViewState<AnimatedList> {
itemBuilder: widget.itemBuilder,
initialItemCount: widget.initialItemCount,
),
widget.scrollDirection,
);
}
}
Expand All @@ -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
Expand Down Expand Up @@ -353,6 +416,7 @@ class AnimatedGridState extends _AnimatedScrollViewState<AnimatedGrid> {
itemBuilder: widget.itemBuilder,
initialItemCount: widget.initialItemCount,
),
widget.scrollDirection,
);
}
}
Expand Down Expand Up @@ -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,
Expand All @@ -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 ],
);
}
}
Expand Down
39 changes: 39 additions & 0 deletions packages/flutter/test/widgets/animated_grid_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
36 changes: 36 additions & 0 deletions packages/flutter/test/widgets/animated_list_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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));
});
}


Expand Down