การจัดการ Gesture ด้วย GestureDetector และ Custom Gestures ใน Flutter
ในบทความก่อนหน้า เราได้สำรวจโลกของ Animation ใน Flutter ทั้งแบบ Implicit และ Explicit ซึ่งช่วยเพิ่มความน่าสนใจให้กับแอปพลิเคชันของเรา ในบทความนี้ เราจะมาเรียนรู้วิธีทำให้แอปพลิเคชันของเราตอบสนองต่อการสัมผัสของผู้ใช้ด้วยการจัดการ Gesture หรือท่าทางสัมผัสต่างๆ โดยใช้ GestureDetector และ Custom Gesture Recognizers
การจัดการ Gesture เป็นสิ่งจำเป็นสำหรับการสร้างแอปพลิเคชันที่ใช้งานง่ายและตอบสนองได้ดี ผู้ใช้คาดหวังว่าจะสามารถโต้ตอบกับแอปพลิเคชันได้โดยการแตะ, ปัด, ซูม หรือทำท่าทางอื่นๆ และ Flutter มีเครื่องมือที่ทรงพลังในการจัดการกับ Gesture เหล่านี้
เริ่มต้นด้วย GestureDetector
GestureDetector คือ Widget พื้นฐานที่ช่วยให้เราตรวจจับและตอบสนองต่อ Gesture ต่างๆ ได้อย่างง่ายดาย Widget นี้มี properties มากมายที่ครอบคลุม Gesture ทั่วไป เช่น:
onTap: เรียกใช้เมื่อ Widget ถูกแตะonDoubleTap: เรียกใช้เมื่อ Widget ถูกแตะสองครั้งติดต่อกันonLongPress: เรียกใช้เมื่อ Widget ถูกกดค้างไว้onVerticalDragStart,onVerticalDragUpdate,onVerticalDragEnd: เรียกใช้เมื่อมีการลากในแนวตั้งonHorizontalDragStart,onHorizontalDragUpdate,onHorizontalDragEnd: เรียกใช้เมื่อมีการลากในแนวนอนonScaleStart,onScaleUpdate,onScaleEnd: เรียกใช้เมื่อมีการซูมหรือหมุน
ลองมาดูตัวอย่างการใช้งาน GestureDetector อย่างง่าย:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'GestureDetector Example',
home: Scaffold(
appBar: AppBar(
title: const Text('GestureDetector Example'),
),
body: Center(
child: GestureDetector(
onTap: () {
print('Tapped!');
},
onDoubleTap: () {
print('Double Tapped!');
},
onLongPress: () {
print('Long Pressed!');
},
child: Container(
width: 200,
height: 100,
color: Colors.blue,
child: const Center(
child: Text(
'Tap Me',
style: TextStyle(color: Colors.white),
),
),
),
),
),
),
);
}
}
ในตัวอย่างนี้ เราได้สร้าง Container ที่มีพื้นหลังสีฟ้าและข้อความ "Tap Me" เมื่อผู้ใช้แตะ, แตะสองครั้ง หรือกดค้างไว้บน Container ข้อความที่เกี่ยวข้องจะถูกพิมพ์ไปยัง Console
Gesture Callbacks ที่สำคัญ: onTap, onDoubleTap, และ onLongPress
ลองมาดู Gesture Callbacks ที่ใช้บ่อยที่สุดอย่างละเอียด:
onTap
onTap ถูกเรียกใช้เมื่อผู้ใช้แตะ Widget อย่างรวดเร็วและปล่อยนิ้วออกมา การใช้งานทั่วไปคือการนำทางไปยังหน้าจออื่น, อัปเดต State หรือเรียกใช้ฟังก์ชันบางอย่าง
onDoubleTap
onDoubleTap ถูกเรียกใช้เมื่อผู้ใช้แตะ Widget สองครั้งติดต่อกันอย่างรวดเร็ว การใช้งานทั่วไปคือการซูมเข้า/ออก, เปลี่ยนโหมดการแสดงผล หรือเปิดใช้งานฟังก์ชันพิเศษ
onLongPress
onLongPress ถูกเรียกใช้เมื่อผู้ใช้กด Widget ค้างไว้ การใช้งานทั่วไปคือการแสดง Context Menu, เปิดใช้งานโหมดแก้ไข หรือแสดงข้อมูลเพิ่มเติม
ตัวอย่างการใช้งาน Gesture Callbacks เหล่านี้:
GestureDetector(
onTap: () {
// ทำบางอย่างเมื่อแตะ
print('onTap triggered');
},
onDoubleTap: () {
// ทำบางอย่างเมื่อแตะสองครั้ง
print('onDoubleTap triggered');
},
onLongPress: () {
// ทำบางอย่างเมื่อกดค้างไว้
print('onLongPress triggered');
},
child: Container(
// ...
),
)
Custom Gesture Recognizers
ในบางครั้ง Gesture ที่ GestureDetector มีให้อาจไม่เพียงพอต่อความต้องการของเรา ในกรณีนี้ เราสามารถสร้าง Custom Gesture Recognizers เพื่อตรวจจับ Gesture ที่ซับซ้อนและเฉพาะเจาะจงได้
การสร้าง Custom Gesture Recognizer นั้นค่อนข้างซับซ้อน แต่ก็คุ้มค่าเมื่อต้องการควบคุมการตรวจจับ Gesture อย่างละเอียด
ขั้นตอนพื้นฐานในการสร้าง Custom Gesture Recognizer คือ:
- สร้าง Class ที่สืบทอดมาจาก
GestureRecognizer - Override method ที่จำเป็น เช่น
handleEvent,acceptGesture, และrejectGesture - ใช้
RawGestureDetectorเพื่อเชื่อมต่อ Custom Gesture Recognizer ของเรากับ Widget
ตัวอย่างการสร้าง Custom Gesture Recognizer ที่ตรวจจับการปัดขึ้น (Swipe Up):
import 'package:flutter/gestures.dart';
import 'package:flutter/widgets.dart';
class SwipeUpGestureRecognizer extends VerticalDragGestureRecognizer {
SwipeUpGestureRecognizer({Object? debugOwner}) : super(debugOwner: debugOwner);
@override
void handleEvent(PointerEvent event) {
if (event is PointerMoveEvent) {
final delta = event.delta.dy;
if (delta < -10) { // Threshold สำหรับการปัดขึ้น
resolve(GestureDisposition.accepted);
onSwipeUp?.call();
} else {
rejectGesture(event.pointer);
}
}
}
GestureTapCallback? onSwipeUp;
}
class MyWidget extends StatelessWidget {
const MyWidget({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return RawGestureDetector(
gestures: {
SwipeUpGestureRecognizer: GestureRecognizerFactoryWithHandlers<SwipeUpGestureRecognizer>(
() => SwipeUpGestureRecognizer(),
(SwipeUpGestureRecognizer instance) {
instance.onSwipeUp = () => print('Swiped Up!');
},
),
},
child: Container(
width: 200,
height: 100,
color: Colors.green,
child: const Center(
child: Text(
'Swipe Up',
style: TextStyle(color: Colors.white),
),
),
),
);
}
}
ในตัวอย่างนี้ เราได้สร้าง SwipeUpGestureRecognizer ที่สืบทอดมาจาก VerticalDragGestureRecognizer และ Override method handleEvent เพื่อตรวจจับการปัดขึ้น เมื่อตรวจจับได้ เราจะเรียกใช้ Callback onSwipeUp ที่เรากำหนดไว้ใน MyWidget
คำอธิบาย Code:
SwipeUpGestureRecognizer: คลาสที่รับผิดชอบในการตรวจจับการปัดขึ้น โดยสืบทอดมาจากVerticalDragGestureRecognizerซึ่งช่วยให้เราตรวจจับการลากในแนวตั้งได้handleEvent: method ที่ถูกเรียกใช้เมื่อมี Pointer Event เกิดขึ้น (เช่น การสัมผัส, การลาก) ภายใน method นี้ เราจะตรวจสอบว่า event นั้นเป็นการลากในแนวตั้งหรือไม่ และทิศทางของการลากนั้นขึ้นบนหรือไม่ ถ้าใช่ เราจะเรียกใช้onSwipeUpRawGestureDetector: Widget ที่ช่วยให้เราเชื่อมต่อ Custom Gesture Recognizer กับ Widget อื่นๆ ใน UI ของเราGestureRecognizerFactoryWithHandlers: คลาสที่ช่วยให้เราสร้าง instance ของ Custom Gesture Recognizer และกำหนดค่าเริ่มต้นให้กับ instance นั้น
ข้อควรระวังในการใช้งาน GestureDetector
- Performance: การใช้
GestureDetectorจำนวนมากใน Widget Tree อาจส่งผลต่อ Performance ของแอปพลิเคชัน ควรใช้เท่าที่จำเป็นและพิจารณาทางเลือกอื่น เช่น การใช้Listenerสำหรับการตรวจจับ Pointer Events โดยตรง - Gesture Conflict: เมื่อมี
GestureDetectorหลายตัวซ้อนกัน อาจเกิด Conflict ระหว่าง Gesture ต่างๆ ควรระมัดระวังในการจัดการ Gesture Priority และใช้Behaviorที่เหมาะสม เช่นHitTestBehavior.opaqueหรือHitTestBehavior.translucent
สรุป
ในบทความนี้ เราได้เรียนรู้วิธีการจัดการ Gesture ใน Flutter โดยใช้ GestureDetector และ Custom Gesture Recognizers เราได้สำรวจ Gesture Callbacks ที่ใช้บ่อย เช่น onTap, onDoubleTap, และ onLongPress และได้เรียนรู้วิธีสร้าง Custom Gesture Recognizer เพื่อตรวจจับ Gesture ที่ซับซ้อนและเฉพาะเจาะจง
การจัดการ Gesture เป็นทักษะที่สำคัญสำหรับการสร้างแอปพลิเคชันที่ใช้งานง่ายและตอบสนองได้ดี หวังว่าบทความนี้จะเป็นประโยชน์ในการเริ่มต้นใช้งาน Gesture ใน Flutter
ในบทความถัดไป เราจะมาเรียนรู้เกี่ยวกับการใช้ ThemeData และ Custom Themes ใน Flutter เพื่อปรับแต่งรูปลักษณ์ของแอปพลิเคชันของเราให้สวยงามและสอดคล้องกับ Brand Identity