👐
GestureDetector使ってみた
Motivation
図形を触って動かす、みたいに自由度の高くて直感的な操作で遊べたら楽しそうだなぁ
Action
-
そもそもどうやったら実現出来るんだ?
⇨画面を触っている位置が分かれば、それに合わせて都度図形の位置を更新すれば良いのか
⇨画面を触っている位置を取得するには?
⇨調べたらGestureDetectorが出てきた! -
どうやって実装するんだ?
以下を参照https://flutter.salon/widget/gesturedetector/
タップ、ズーム、スワイプ、ドラッグと色々出来るんだぁ💡
公式も確認
https://api.flutter.dev/flutter/widgets/GestureDetector-class.html
Youtubeだと、以下のようにmaxを使用←何で?
Positioned( top: _top, left: _left, child: GestureDetector( onPanUpdate: (details) { _top = max(0, _top + details.delta.dy); // Why? _left = max(0, _left + details.delta.dx); setState(() => {}); } ), child: yourWidget(), ), -
いざ実装
import 'package:flutter/material.dart';
class ShapeMovePage extends StatefulWidget {
const ShapeMovePage({super.key});
_ShapeMovePageState createState() => _ShapeMovePageState();
}
class _ShapeMovePageState extends State<ShapeMovePage> {
Offset position = Offset(0, 0);
void _onPanUpdate(DragUpdateDetails details, Size widgetSize) {
final double xPos = position.dx + details.delta.dx;
final double yPos = position.dx + details.delta.dx;
setState(() {
position = Offset(
xPos <= widgetSize.width ? xPos : position.dx,
yPos <= widgetSize.height ? yPos : position.dy,
);
});
}
Widget build(BuildContext context) {
final Size widgetSize = MediaQuery.of(context).size;
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text('Shape move'),
),
body: Stack(
children: [
Positioned(
left: position.dx,
top: position.dy,
child: GestureDetector(
onPanUpdate: (details) => _onPanUpdate(details, widgetSize),
child: Container(
width: 100,
height: 100,
color: Colors.blue,
child: Center(
child: Text(
'Drag me',
style: TextStyle(color: Colors.white, fontSize: 16),
),
),
),
),
),
],
),
);
}
}
これだと画面外にめり込む
⇨max(0, x or y)でpositionが画面上 or 左にいかないようにする(なるほどそれでね)
⇨Containerのwidth, height分条件を追加する
修正版
import 'package:flutter/material.dart';
class ShapeMovePage extends StatefulWidget {
const ShapeMovePage({super.key});
_ShapeMovePageState createState() => _ShapeMovePageState();
}
class _ShapeMovePageState extends State<ShapeMovePage> {
Offset position = Offset(0, 0);
+ static const double headerMargin = 80;
- void _onPanUpdate(DragUpdateDetails details, Size widgetSize) {
+ void _onPanUpdate(
+ DragUpdateDetails details,
+ Size widgetSize,
+ double shapeWidth,
+ shapeHeight,
) {
- final double xPos = position.dx + details.delta.dx;
- final double yPos = position.dx + details.delta.dx;
+ final double xPos = max(0, position.dx + details.delta.dx);
+ final double yPos = max(0, position.dy + details.delta.dy);
setState(() {
position = Offset(
- xPos <= widgetSize.width ? xPos : position.dx,
- yPos <= widgetSize.height ? yPos : position.dy,
+ xPos + shapeWidth <= widgetSize.width ? xPos : position.dx,
+ yPos + shapeHeight + headerMargin <= widgetSize.height
+ ? yPos
+ : position.dy,
);
});
}
Widget build(BuildContext context) {
final Size widgetSize = MediaQuery.of(context).size;
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text('Shape move'),
),
body: Stack(
children: [
Positioned(
left: position.dx,
top: position.dy,
child: GestureDetector(
- _onPanUpdate: (details) => _onPanUpdate(details, widgetSize),
+ _onPanUpdate(details, widgetSize, 100, 100),
child: Container(
width: 100,
height: 100,
color: Colors.blue,
child: Center(
child: Text(
'Drag me',
style: TextStyle(color: Colors.white, fontSize: 16),
),
),
),
),
),
],
),
);
}
}
めり込まずに動かせた!
Question
- ヘッダー部分のサイズは、取得して使う方が変更に強くなるよねー。
- 図形増やしていったらどうやって管理しよう?
Zaregoto
- Markdown記法に則ってDiff手動で追加したけど、面倒だったな。Gitいつもありがとう。
- qiitaとZennでdiffのMarkdown記法微妙に違うんかい
Discussion