I attempted to detect diagonal swipe direction using GestureDetector
. I used the onPanStart
method to detect the screen's corners.
However, it is not perfect because it only considers the beginning of the gesture.
Right now, if I swipe bottom left to top right in the top right corner or part, it gives me the incorrect top right direction. In this case, the correct direction should be bottom left.
So, how can we identify diagonal swipe direction using GestureDetector
or any other method?
I looked at several other StackOverflow posts, but they only detect top, left, right, and bottom directions.
Here is an example of code.
class _HomePageState extends State<HomePage> {
@override
Widget build(BuildContext context) {
final screenSize = MediaQuery.of(context).size;
String? swipeDirection;
return Scaffold(
body: SafeArea(
child: Scaffold(
backgroundColor: Colors.black,
body: GestureDetector(
child: Container(),
onPanStart: (details) {
final halfScreenWidth = screenSize.width / 2;
final halfScreenHeight = screenSize.height / 2;
final position = details.localPosition;
if ((position.dx < halfScreenWidth) &&
(position.dy < halfScreenHeight)) {
swipeDirection = 'topLeft';
} else if ((position.dx > halfScreenWidth) &&
(position.dy < halfScreenHeight)) {
swipeDirection = 'topRight';
} else if ((position.dx < halfScreenWidth) &&
(position.dy > halfScreenHeight)) {
swipeDirection = 'bottomLeft';
} else {
swipeDirection = 'bottomRight';
}
},
),
),
));
}
}
You can use pan update to find the position of the pointer the same manner you did for pan start and get the starting and ending points. Then on pan end execute with the final results
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: MyHome(),
);
}
}
class MyHome extends StatefulWidget {
const MyHome({Key? key}) : super(key: key);
@override
State<MyHome> createState() => _MyHomeState();
}
class _MyHomeState extends State<MyHome> {
String? swipeStart;
String? swipeEnd;
@override
void initState() {
// TODO: implement initState
super.initState();
}
@override
Widget build(BuildContext context) {
final screenSize = MediaQuery.of(context).size;
return SafeArea(
child: Scaffold(
backgroundColor: Colors.black,
body: GestureDetector(
child: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
color: Colors.grey,
),
onPanStart: (details) {
final halfScreenWidth = screenSize.width / 2;
final halfScreenHeight = screenSize.height / 2;
final position = details.localPosition;
if ((position.dx < halfScreenWidth) &&
(position.dy < halfScreenHeight)) {
swipeStart = 'topLeft';
} else if ((position.dx > halfScreenWidth) &&
(position.dy < halfScreenHeight)) {
swipeStart = 'topRight';
} else if ((position.dx < halfScreenWidth) &&
(position.dy > halfScreenHeight)) {
swipeStart = 'bottomLeft';
} else {
swipeStart = 'bottomRight';
}
// print(swipeStart);
},
onPanUpdate: (details) {
final halfScreenWidth = screenSize.width / 2;
final halfScreenHeight = screenSize.height / 2;
final position = details.localPosition;
if ((position.dx < halfScreenWidth) &&
(position.dy < halfScreenHeight)) {
swipeEnd = 'topLeft';
} else if ((position.dx > halfScreenWidth) &&
(position.dy < halfScreenHeight)) {
swipeEnd = 'topRight';
} else if ((position.dx < halfScreenWidth) &&
(position.dy > halfScreenHeight)) {
swipeEnd = 'bottomLeft';
} else {
swipeEnd = 'bottomRight';
}
//print(swipeEnd);
},
onPanEnd: (details) {
print("Final direction was from $swipeStart to $swipeEnd");
},
),
),
);
}
}
I have printed output like this
flutter: Final direction was from topLeft to bottomRight
flutter: Final direction was from bottomLeft to topRight
EDIT
You can find the offset when the pan starts and updates. Then on pan end calculate the direction like this
import 'dart:math';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: MyHome(),
);
}
}
class MyHome extends StatefulWidget {
const MyHome({Key? key}) : super(key: key);
@override
State<MyHome> createState() => _MyHomeState();
}
class _MyHomeState extends State<MyHome> {
String? horizontalDirection;
String? verticalDirection;
late Offset startPoint;
late Offset endPoint;
@override
void initState() {
// TODO: implement initState
super.initState();
}
@override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
backgroundColor: Colors.black,
body: GestureDetector(
child: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
color: Colors.grey,
),
onPanStart: (details) {
startPoint = details.localPosition;
},
onPanUpdate: (details) {
endPoint = details.localPosition;
},
onPanEnd: (details) {
if (startPoint.dx < endPoint.dx) {
horizontalDirection = "right";
} else {
horizontalDirection = "left";
}
if (startPoint.dy < endPoint.dy) {
verticalDirection = "bottom";
} else {
verticalDirection = "top";
}
print("Final direction was $horizontalDirection$verticalDirection");
},
),
),
);
}
}