Flutter 手指放大 平移 旋转 Widget
import 'package:dart_printf/dart_printf.dart';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
double _scale = 1.0;
double _baseScale = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: GestureDetector(
onScaleStart: (ScaleStartDetails scaleStartDetails) {
_baseScale = _scale;
},
onScaleUpdate: (ScaleUpdateDetails scaleUpdateDetails) {
double _ns = _baseScale * scaleUpdateDetails.scale;
printf('[scale]: %f %f', [scaleUpdateDetails.scale, _ns]);
if (_ns <= 1.0) return;
setState(() {
_scale = _ns;
});
},
child: Transform.scale(
scale: _scale,
child: Container(
width: 300,
height: 300,
color: Colors.red,
),
),
),
),
);
}
}
移动它
class _HomePageState extends State<HomePage> {
double _scale = 1.0;
double _baseScale = 0;
Offset _to = Offset(0, 0);
Offset _baseTo = Offset(0, 0);
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: GestureDetector(
onDoubleTap: () {
setState(() {
_scale = 1.0;
_to = Offset(0, 0);
_baseTo = Offset(0, 0);
});
},
onScaleStart: (ScaleStartDetails d) {
_baseScale = _scale;
_baseTo = d.localFocalPoint;
},
onScaleUpdate: (ScaleUpdateDetails d) {
double _ns = _baseScale * d.scale;
if (_ns > 1.0) {
setState(() {
_scale = _ns;
});
}
setState(() {
_to = d.localFocalPoint;
});
},
child: Transform(
transform: Matrix4.identity()
..scale(_scale, _scale, 1.0)
..translate(_to.dx - _baseTo.dx, _to.dy - _baseTo.dy),
alignment: Alignment.center,
child: Container(
width: 200,
height: 200,
color: Colors.red,
),
),
),
),
);
}
}
简单的碰撞检测
class _HomePageState extends State<HomePage> {
double _scale = 1.0;
double _baseScale = 0;
Offset _to = Offset(0, 0);
Offset _baseTo = Offset(0, 0);
GlobalKey stickyKey = GlobalKey();
@override
Widget build(BuildContext context) {
Size window = MediaQuery.of(context).size;
return Scaffold(
body: Center(
child: GestureDetector(
onDoubleTap: () {
setState(() {
_scale = 1.0;
_to = Offset(0, 0);
_baseTo = Offset(0, 0);
});
},
onScaleStart: (ScaleStartDetails d) {
_baseScale = _scale;
_baseTo = d.localFocalPoint;
},
onScaleUpdate: (ScaleUpdateDetails d) {
double _ns = _baseScale * d.scale;
if (_ns > 0.8) {
setState(() {
_scale = _ns;
});
}
Offset lfp = d.localFocalPoint;
var _box = stickyKey.currentContext.findRenderObject() as RenderBox;
Offset _pos = _box.localToGlobal(Offset.zero);
var _boxsize = _box.size * _ns;
if (_boxsize.width <= window.width) {
if (!(_pos.dx <= 0 && lfp.dx < _to.dx ||
_pos.dx + _boxsize.width >= window.width && lfp.dx > _to.dx ||
_pos.dy <= 0 && lfp.dy < _to.dy ||
_pos.dy + _boxsize.height >= window.height &&
lfp.dy > _to.dy)) {
setState(() {
_to = d.localFocalPoint;
});
}
} else {
if (!(_pos.dx >= 0 && lfp.dx > _to.dx ||
_pos.dx + _boxsize.width <= window.width && lfp.dx < _to.dx ||
_pos.dy >= 0 && lfp.dy > _to.dy ||
_pos.dy + _boxsize.width <= window.height &&
lfp.dy < _to.dy)) {
setState(() {
_to = d.localFocalPoint;
});
}
}
},
child: Transform(
transform: Matrix4.identity()
..scale(_scale, _scale)
..translate(_to.dx - _baseTo.dx, _to.dy - _baseTo.dy),
alignment: Alignment.center,
child: Image.network(
'https://i.loli.net/2020/01/14/w1dcNtf4SECG6yX.jpg',
key: stickyKey,
),
),
),
),
);
}
}
Z轴旋转
class _HomePageState extends State<HomePage> {
double _rotation = 0.0;
double _lastRotation = 0.0;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: GestureDetector(
onScaleUpdate: (ScaleUpdateDetails d) {
printf('[rotation] %f', [d.rotation]);
setState(() {
_rotation = d.rotation;
});
},
onScaleEnd: (_) {
_lastRotation += _rotation;
},
child: Transform(
transform: Matrix4.identity()..rotateZ(_lastRotation + _rotation),
alignment: Alignment.center,
child: Image.network(
'https://i.loli.net/2020/01/14/w1dcNtf4SECG6yX.jpg',
),
),
),
),
);
}
}
保存上一次的移动偏移
class _HomePageState extends State<HomePage> {
Offset pos = Offset(0, 0);
Offset basePos = Offset(0, 0);
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: GestureDetector(
onScaleStart: (ScaleStartDetails d) {
basePos = d.localFocalPoint - pos;
},
onScaleUpdate: (ScaleUpdateDetails d) {
setState(() {
pos = d.localFocalPoint - basePos;
});
},
child: Transform(
transform: Matrix4.identity()..translate(pos.dx, pos.dy),
alignment: Alignment.center,
child: Container(
width: 200,
height: 200,
color: Colors.red,
),
),
),
),
);
}
}