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
This commit is contained in:
parent
f37a4d05a4
commit
14f1e13edb
@ -6,6 +6,7 @@ import 'package:flutter/foundation.dart';
|
|||||||
|
|
||||||
import 'basic.dart';
|
import 'basic.dart';
|
||||||
import 'framework.dart';
|
import 'framework.dart';
|
||||||
|
import 'media_query.dart';
|
||||||
import 'scroll_controller.dart';
|
import 'scroll_controller.dart';
|
||||||
import 'scroll_delegate.dart';
|
import 'scroll_delegate.dart';
|
||||||
import 'scroll_physics.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 **
|
/// ** See code in examples/api/lib/widgets/animated_list/animated_list.0.dart **
|
||||||
/// {@end-tool}
|
/// {@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:
|
/// See also:
|
||||||
///
|
///
|
||||||
/// * [SliverAnimatedList], a sliver that animates items when they are inserted
|
/// * [SliverAnimatedList], a sliver that animates items when they are inserted
|
||||||
@ -176,6 +206,7 @@ class AnimatedListState extends _AnimatedScrollViewState<AnimatedList> {
|
|||||||
itemBuilder: widget.itemBuilder,
|
itemBuilder: widget.itemBuilder,
|
||||||
initialItemCount: widget.initialItemCount,
|
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 **
|
/// ** See code in examples/api/lib/widgets/animated_grid/animated_grid.0.dart **
|
||||||
/// {@end-tool}
|
/// {@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:
|
/// See also:
|
||||||
///
|
///
|
||||||
/// * [SliverAnimatedGrid], a sliver which animates items when they are inserted
|
/// * [SliverAnimatedGrid], a sliver which animates items when they are inserted
|
||||||
@ -353,6 +416,7 @@ class AnimatedGridState extends _AnimatedScrollViewState<AnimatedGrid> {
|
|||||||
itemBuilder: widget.itemBuilder,
|
itemBuilder: widget.itemBuilder,
|
||||||
initialItemCount: widget.initialItemCount,
|
initialItemCount: widget.initialItemCount,
|
||||||
),
|
),
|
||||||
|
widget.scrollDirection,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -529,7 +593,35 @@ abstract class _AnimatedScrollViewState<T extends _AnimatedScrollView> extends S
|
|||||||
_sliverAnimatedMultiBoxKey.currentState!.removeAllItems(builder, duration: duration);
|
_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(
|
return CustomScrollView(
|
||||||
scrollDirection: widget.scrollDirection,
|
scrollDirection: widget.scrollDirection,
|
||||||
reverse: widget.reverse,
|
reverse: widget.reverse,
|
||||||
@ -538,12 +630,7 @@ abstract class _AnimatedScrollViewState<T extends _AnimatedScrollView> extends S
|
|||||||
physics: widget.physics,
|
physics: widget.physics,
|
||||||
clipBehavior: widget.clipBehavior,
|
clipBehavior: widget.clipBehavior,
|
||||||
shrinkWrap: widget.shrinkWrap,
|
shrinkWrap: widget.shrinkWrap,
|
||||||
slivers: <Widget>[
|
slivers: <Widget>[ sliver ],
|
||||||
SliverPadding(
|
|
||||||
padding: widget.padding ?? EdgeInsets.zero,
|
|
||||||
sliver: sliver,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -646,6 +646,45 @@ void main() {
|
|||||||
|
|
||||||
expect(tester.widget<CustomScrollView>(find.byType(CustomScrollView)).clipBehavior, clipBehavior);
|
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 {
|
class _StatefulListItem extends StatefulWidget {
|
||||||
|
@ -649,6 +649,42 @@ void main() {
|
|||||||
|
|
||||||
expect(tester.widget<CustomScrollView>(find.byType(CustomScrollView)).shrinkWrap, true);
|
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));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user