Add boundary feature to the drag gesture. (#147521)

Inspired by the review on #146182.

This PR adds boundary feature to the drag gestures, including `MultiDragGestureRecognizer` and `DragGestureRecognizer`. The `GestureDetector` widget will also benefit from this.
This commit is contained in:
yim
2024-10-30 11:01:18 +08:00
committed by GitHub
parent 7ee7fff210
commit c051b69e2a
5 changed files with 289 additions and 0 deletions

View File

@@ -0,0 +1,69 @@
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/material.dart';
void main() {
runApp(const DragBoundaryExampleApp());
}
class DragBoundaryExampleApp extends StatefulWidget {
const DragBoundaryExampleApp({super.key});
@override
State<StatefulWidget> createState() => DragBoundaryExampleAppState();
}
class DragBoundaryExampleAppState extends State<DragBoundaryExampleApp> {
Offset _currentPosition = Offset.zero;
Offset _initialPosition = Offset.zero;
final Size _boxSize = const Size(100, 100);
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Padding(
padding: const EdgeInsets.all(100),
child: DragBoundary(
child: Builder(
builder: (BuildContext context) {
return Stack(
children: <Widget>[
Container(
color: Colors.green,
),
Positioned(
top: _currentPosition.dy,
left: _currentPosition.dx,
child: GestureDetector(
behavior: HitTestBehavior.translucent,
onPanStart: (DragStartDetails details) {
_initialPosition = details.localPosition - _currentPosition;
},
onPanUpdate: (DragUpdateDetails details) {
_currentPosition = details.localPosition - _initialPosition;
final Rect withinBoundary = DragBoundary.forRectOf(context, useGlobalPosition: false).nearestPositionWithinBoundary(
_currentPosition & _boxSize,
);
setState(() {
_currentPosition = withinBoundary.topLeft;
});
},
child: Container(
width: _boxSize.width,
height: _boxSize.height,
color: Colors.red,
),
),
),
],
);
},
),
),
),
),
);
}
}

View File

@@ -0,0 +1,29 @@
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_api_samples/widgets/gesture_detector/gesture_detector.3.dart'
as example;
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('The red box always moves inside the green box', (WidgetTester tester) async {
await tester.pumpWidget(
const example.DragBoundaryExampleApp(),
);
final Finder greenFinder = find.byType(Container).first;
final Finder redFinder = find.byType(Container).last;
final TestGesture drag = await tester.startGesture(tester.getCenter(redFinder));
await tester.pump(kLongPressTimeout);
await drag.moveBy(const Offset(1000, 1000));
await tester.pumpAndSettle();
expect(tester.getBottomRight(redFinder), tester.getBottomRight(greenFinder));
await drag.moveBy(const Offset(-2000, -2000));
await tester.pumpAndSettle();
expect(tester.getTopLeft(redFinder), tester.getTopLeft(greenFinder));
await drag.up();
await tester.pumpAndSettle();
});
}