我已经为容器实现了Scale手势。另外,我添加了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,
),
)
,
),
),
],
);
}
}
我想在红色子视图中移动并随比例旋转。
答案 0 :(得分:1)
我们可以使用ScaleUpdateDetails对象的focusPoint字段,该对象在onScaleUpdate函数中作为参数获取。
与以上示例有关的解决方案: 我们需要更新onScaleUpdate方法。
onScaleUpdate: (scaleUpdates) {
lastRotation += scaleUpdates.rotation;
var offset = scaleUpdates.focalPoint;
xOffset = offset.dx;
yOffset = offset.dy;
setState(() => _scale = _previousScale * scaleUpdates.scale);
}
在上述代码中更改“定位的小部件”的“ rect”字段。
rect: Rect.fromPoints(Offset(xOffset - 125.0, yOffset - 50.0),
Offset(xOffset + 250.0, yOffset + 100.0))
答案 1 :(得分:0)
默认GestureRecognizer
不支持同时识别平移/拖动和缩放。我认为这是错误,应该修复。要实现这种行为-您需要基于RawGestureDetector
手势构建自己的消雾器ImmediateMultiDragGestureRecognizer
。
我已经在这里实现了PanAndScalingGestureRecognizer
类:https://gist.github.com/comm1x/8ffffd08417053043e079878b4bd8d03
因此您可以看到完整的示例,也可以复制粘贴并使用。
答案 2 :(得分:0)
我使用Pointer Listener来实现我的自定义手势检测器。
对于遇到相同问题的任何人,只需看看软件包gesture_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;
});
}
}
答案 3 :(得分:0)
在与 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
。