[英]Flutter: How to implement Rotate and Pan/Move gesture for any container?
我已經為容器實現了縮放手勢。 另外,我添加了 onHorizontalDragUpdate 和 onVerticalDragUpdate。 但是當我嘗試添加兩者時,我收到一個異常,說無法使用 Scale 手勢實現兩者。 即使對於平移手勢,它也會拋出相同的異常。 下面是我的代碼:
import 'package:flutter/material.dart';
import 'package:vector_math/vector_math_64.dart' hide Colors;
import 'dart: math' as math;
class HomeScreen extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return HomeState();
}
}
class HomeState extends State<HomeScreen> {
double _scale = 1.0;
double _previousScale;
var yOffset = 400.0;
var xOffset = 50.0;
var rotation = 0.0;
var lastRotation = 0.0;
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.amber,
body: Stack(
children: <Widget>[
stackContainer(),
],
),
);
}
Widget stackContainer() {
return Stack(
children: <Widget>[
Positioned.fromRect(
rect: Rect.fromPoints( Offset(xOffset, yOffset),
Offset(xOffset+250.0, yOffset+100.0)),
child: GestureDetector(
onScaleStart: (scaleDetails) {
_previousScale = _scale;
print(' scaleStarts = ${scaleDetails.focalPoint}');
},
onScaleUpdate: (scaleUpdates){
//ScaleUpdateDetails
rotation += lastRotation - scaleUpdates.rotation;
lastRotation = scaleUpdates.rotation;
print("lastRotation = $lastRotation");
print(' scaleUpdates = ${scaleUpdates.scale} rotation = ${scaleUpdates.rotation}');
setState(() => _scale = _previousScale * scaleUpdates.scale);
},
onScaleEnd: (scaleEndDetails) {
_previousScale = null;
print(' scaleEnds = ${scaleEndDetails.velocity}');
},
child:
Transform(
transform: Matrix4.diagonal3( Vector3(_scale, _scale, _scale))..rotateZ(rotation * math.pi/180.0),
alignment: FractionalOffset.center,
child: Container(
color: Colors.red,
),
)
,
),
),
],
);
}
}
我想圍繞紅色子視圖移動並隨着比例旋轉。
我們可以使用 ScaleUpdateDetails 對象的 focusPoint 字段,我們將其作為 onScaleUpdate 函數中的參數。
與上述例子相關的解決方案:我們需要更新 onScaleUpdate 方法。
onScaleUpdate: (scaleUpdates) {
lastRotation += scaleUpdates.rotation;
var offset = scaleUpdates.focalPoint;
xOffset = offset.dx;
yOffset = offset.dy;
setState(() => _scale = _previousScale * scaleUpdates.scale);
}
在上面的代碼中更改 Positioned Widget 的 'rect' 字段。
rect: Rect.fromPoints(Offset(xOffset - 125.0, yOffset - 50.0),
Offset(xOffset + 250.0, yOffset + 100.0))
默認GestureRecognizer
不支持搖攝/拖拽和縮放的認可的同時。 我認為這是錯誤,應該修復。 要實現這種行為 - 您需要基於ImmediateMultiDragGestureRecognizer
手勢構建自己的識別器RawGestureDetector
。
我已經在這里實現了類PanAndScalingGestureRecognizer
:https : PanAndScalingGestureRecognizer
所以你可以看到完整的例子或者只是復制粘貼和使用。
我使用指針偵聽器來實現我的自定義手勢檢測器。
對於面臨同樣問題的任何人,只需查看包手勢_x_detector
支持(點擊、雙擊、縮放(開始、更新、結束)、移動(開始、更新、結束)和長按。所有類型可以同時使用。
例子:
import 'package:flutter/material.dart';
import 'package:gesture_x_detector/gesture_x_detector.dart';
void main() {
runApp(
MaterialApp(
home: XGestureExample(),
),
);
}
class XGestureExample extends StatefulWidget {
@override
_XGestureExampleState createState() => _XGestureExampleState();
}
class _XGestureExampleState extends State<XGestureExample> {
String lastEventName = 'Tap on screen';
@override
Widget build(BuildContext context) {
return XGestureDetector(
child: Material(
child: Center(
child: Text(
lastEventName,
style: TextStyle(fontSize: 30),
),
),
),
doubleTapTimeConsider: 300,
longPressTimeConsider: 350,
onTap: onTap,
onDoubleTap: onDoubleTap,
onLongPress: onLongPress,
onMoveStart: onMoveStart,
onMoveEnd: onMoveEnd,
onMoveUpdate: onMoveUpdate,
onScaleStart: onScaleStart,
onScaleUpdate: onScaleUpdate,
onScaleEnd: onScaleEnd,
bypassTapEventOnDoubleTap: false,
);
}
void onScaleEnd() {
setLastEventName('onScaleEnd');
print('onScaleEnd');
}
void onScaleUpdate(changedFocusPoint, scale) {
setLastEventName('onScaleUpdate');
print(
'onScaleUpdate - changedFocusPoint: $changedFocusPoint ; scale: $scale');
}
void onScaleStart(initialFocusPoint) {
setLastEventName('onScaleStart');
print('onScaleStart - initialFocusPoint: ' + initialFocusPoint.toString());
}
void onMoveUpdate(localPos, position, localDelta, delta) {
setLastEventName('onMoveUpdate');
print('onMoveUpdate - pos: ' + localPos.toString());
}
void onMoveEnd(pointer, localPos, position) {
setLastEventName('onMoveEnd');
print('onMoveEnd - pos: ' + localPos.toString());
}
void onMoveStart(pointer, localPos, position) {
setLastEventName('onMoveStart');
print('onMoveStart - pos: ' + localPos.toString());
}
void onLongPress(pointer, localPos, position) {
setLastEventName('onLongPress');
print('onLongPress - pos: ' + localPos.toString());
}
void onDoubleTap(localPos, position) {
setLastEventName('onDoubleTap');
print('onDoubleTap - pos: ' + localPos.toString());
}
void onTap(pointer, localPos, position) {
setLastEventName('onTap');
print('onTap - pos: ' + localPos.toString());
}
void setLastEventName(String eventName) {
setState(() {
lastEventName = eventName;
});
}
}
在與scale
相關的事件中,除了縮放(縮放)之外,您還可以使用focalPoint
來計算平移。 還可以支持在縮放時平移。
演示:
這是用於上述演示的代碼:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: ZoomAndPanDemo(),
);
}
}
class ZoomAndPanDemo extends StatefulWidget {
@override
_ZoomAndPanDemoState createState() => _ZoomAndPanDemoState();
}
class _ZoomAndPanDemoState extends State<ZoomAndPanDemo> {
Offset _offset = Offset.zero;
Offset _initialFocalPoint = Offset.zero;
Offset _sessionOffset = Offset.zero;
double _scale = 1.0;
double _initialScale = 1.0;
@override
Widget build(BuildContext context) {
return GestureDetector(
onScaleStart: (details) {
_initialFocalPoint = details.focalPoint;
_initialScale = _scale;
},
onScaleUpdate: (details) {
setState(() {
_sessionOffset = details.focalPoint - _initialFocalPoint;
_scale = _initialScale * details.scale;
});
},
onScaleEnd: (details) {
setState(() {
_offset += _sessionOffset;
_sessionOffset = Offset.zero;
});
},
child: Transform.translate(
offset: _offset + _sessionOffset,
child: Transform.scale(
scale: _scale,
child: FlutterLogo(),
),
),
);
}
}
旁注:即使像onHorizontalDragUpdate
這樣的事件在與縮放相關的事件一起使用時不會導致運行時異常,它們仍然會導致沖突並導致較差的用戶體驗。
還值得注意的是, InteractiveViewer
是一個內置的 Flutter 小部件,可以滿足您的大部分需求,因此您可能根本不需要使用GestureDetector
和Transform
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.