mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
Add clipBehavior to InteractiveViewer (#73281)
More intuitive control over whether the child can overflow out of InteractiveViewer, deterring a lot of confusion we were seeing.
This commit is contained in:
parent
2e3d3e6522
commit
2a2e0cf100
@ -19,14 +19,16 @@ import 'ticker_provider.dart';
|
||||
///
|
||||
/// The user can transform the child by dragging to pan or pinching to zoom.
|
||||
///
|
||||
/// By default, InteractiveViewer may draw outside of its original area of the
|
||||
/// screen, such as when a child is zoomed in and increases in size. However, it
|
||||
/// will not receive gestures outside of its original area. To prevent
|
||||
/// InteractiveViewer from drawing outside of its original size, wrap it in a
|
||||
/// [ClipRect]. Or, to prevent dead areas where InteractiveViewer does not
|
||||
/// receive gestures, be sure that the InteractiveViewer widget is the size of
|
||||
/// the area that should be interactive. See
|
||||
/// [flutter-go](https://github.com/justinmc/flutter-go) for an example of
|
||||
/// By default, InteractiveViewer clips its child using [Clip.hardEdge].
|
||||
/// To prevent this behavior, consider setting [clipBehavior] to [Clip.none].
|
||||
/// When [clipBehavior] is [Clip.none], InteractiveViewer may draw outside of
|
||||
/// its original area of the screen, such as when a child is zoomed in and
|
||||
/// increases in size. However, it will not receive gestures outside of its original area.
|
||||
/// To prevent dead areas where InteractiveViewer does not receive gestures,
|
||||
/// don't set [clipBehavior] or be sure that the InteractiveViewer widget is the
|
||||
/// size of the area that should be interactive.
|
||||
///
|
||||
/// See [flutter-go](https://github.com/justinmc/flutter-go) for an example of
|
||||
/// robust positioning of an InteractiveViewer child that works for all screen
|
||||
/// sizes and child sizes.
|
||||
///
|
||||
@ -68,6 +70,7 @@ class InteractiveViewer extends StatefulWidget {
|
||||
/// The [child] parameter must not be null.
|
||||
InteractiveViewer({
|
||||
Key? key,
|
||||
this.clipBehavior = Clip.hardEdge,
|
||||
this.alignPanAxis = false,
|
||||
this.boundaryMargin = EdgeInsets.zero,
|
||||
this.constrained = true,
|
||||
@ -102,6 +105,13 @@ class InteractiveViewer extends StatefulWidget {
|
||||
&& boundaryMargin.left.isFinite)),
|
||||
super(key: key);
|
||||
|
||||
/// If set to [Clip.none], the child may extend beyond the size of the InteractiveViewer,
|
||||
/// but it will not receive gestures in these areas.
|
||||
/// Be sure that the InteractiveViewer is the desired size when using [Clip.none].
|
||||
///
|
||||
/// Defaults to [Clip.hardEdge].
|
||||
final Clip clipBehavior;
|
||||
|
||||
/// If true, panning is only allowed in the direction of the horizontal axis
|
||||
/// or the vertical axis.
|
||||
///
|
||||
@ -1061,15 +1071,20 @@ class _InteractiveViewerState extends State<InteractiveViewer> with TickerProvid
|
||||
);
|
||||
|
||||
if (!widget.constrained) {
|
||||
child = OverflowBox(
|
||||
alignment: Alignment.topLeft,
|
||||
minWidth: 0.0,
|
||||
minHeight: 0.0,
|
||||
maxWidth: double.infinity,
|
||||
maxHeight: double.infinity,
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
|
||||
if (widget.clipBehavior != Clip.none) {
|
||||
child = ClipRect(
|
||||
child: OverflowBox(
|
||||
alignment: Alignment.topLeft,
|
||||
minWidth: 0.0,
|
||||
minHeight: 0.0,
|
||||
maxWidth: double.infinity,
|
||||
maxHeight: double.infinity,
|
||||
child: child,
|
||||
),
|
||||
clipBehavior: widget.clipBehavior,
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -985,6 +985,49 @@ void main() {
|
||||
expect(scale, greaterThan(1.0));
|
||||
expect(transformationController.value.getMaxScaleOnAxis(), greaterThan(1.0));
|
||||
});
|
||||
|
||||
testWidgets('Check if ClipRect is present in the tree', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: Center(
|
||||
child: InteractiveViewer(
|
||||
constrained: false,
|
||||
clipBehavior: Clip.none,
|
||||
minScale: 1.0,
|
||||
maxScale: 1.0,
|
||||
child: const SizedBox(width: 200.0, height: 200.0),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(
|
||||
find.byType(ClipRect),
|
||||
findsNothing,
|
||||
);
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: Center(
|
||||
child: InteractiveViewer(
|
||||
constrained: false,
|
||||
minScale: 1.0,
|
||||
maxScale: 1.0,
|
||||
child: const SizedBox(width: 200.0, height: 200.0),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(
|
||||
find.byType(ClipRect),
|
||||
findsOneWidget,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
group('getNearestPointOnLine', () {
|
||||
|
Loading…
Reference in New Issue
Block a user