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:
@@ -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,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user