รวม Widget สำหรับ Flutter Web/Desktop
สวัสดีเพื่อนๆครับ ผมมีโอกาสได้ลองเล่น Flutter Desktop และ Web จนได้นำมาใช้งานจริง ทำให้ได้เห็นข้อแตกต่างของการพัฒนาแอปในแต่ละ Platform ระหว่าง Mobile และ Desktop-Web ในบทความนี้ ผมจะรวบรวม widgets ต่างๆ library หรือเทคนิคที่น่าสนใจในการทำแอปบน Flutter Desktop ครับ มีอะไรบ้างมาติดตามกัน
Selectable Text
เริ่มจาก widget ตัวแรก พื้นฐานที่สุดนั่นก็คือ Text โดยปกติหากเราใช้ Widget ชื่อว่า Text
มันจะไม่สามารถคลิกเลือกข้อความได้ ซึ่งหารเลือกข้อความ เพื่อ copy หรือ highlight เป็นเรื่องที่ปกติมากในการใช้งานใน web
Text(
"Hello world",
style: TextStyle(fontSize: 28),
)
ให้เราใช้ widget ที่ชื่อว่า SelectableText แทน เท่านี้ก็จะสามารถคลิกที่ข้อความได้แล้ว
SelectableText(
"Hello world",
style: TextStyle(fontSize: 28),
)
สามารถ drag เม้าและคลิกขวา copy ได้เลย
แต่ทว่า หากมี SelectableText หลายตัวแบบนี้ จะไม่สามารถคลิกลากเพื่อเลือกข้อความหลายๆข้อความได้
Column(mainAxisSize: MainAxisSize.min,
children: [
SelectableText(
"Hello world,",
style: TextStyle(fontSize: 28),
),
SelectableText(
"I am developer.",
style: TextStyle(fontSize: 28),
),
SelectableText(
"Coffee is Life.",
style: TextStyle(fontSize: 28),
),
],
)
เราจะต้องใช้ Selectable.rich() แทน
SelectableText.rich(
TextSpan(
text: "Hello world,",
style: TextStyle(fontSize: 28,color: Colors.purple[300]),
children: [
TextSpan(
text: "\nI am developer.",
style: TextStyle(fontSize: 28,color: Colors.red[300]),
),
TextSpan(
text: "\nCoffee is Life.",
style: TextStyle(fontSize: 28,color: Colors.blue[300]),
),
]),
textAlign: TextAlign.center,
)
Mouse Region
Widget ต่อมา เกี่ยวกับการแสดง Cursor (mouse) โดยปกติหากเราใช้ใน mobile เราจะไม่มีเม้าใช่ไหม
แต่ว่าใน Desktop นั้น การใช้งาน cursor เป็นเรื่องปกติ และ cursor จะเปลี่ยนสัญลักษณ์ไปตามที่กำหนด ช่วยให้แอปมี UX ที่ดีขึ้น
วิธีการใช้ คือ นำ MouseRegion ไปเป็น parent ของ Widget ที่ต้องการ และกำหนด field ที่ชื่อว่า cursor ให้มัน
MouseRegion(
cursor: SystemMouseCursors.forbidden,
child: Text(
"Unavailable",
style: TextStyle(fontSize: 28,color: Colors.red[400]),
),
)
Text Hover
เมื่อเรารู้จัก MouseRegion แล้ว เราสามารถนำมาใช้กับ Text เพื่อให้ Text สามารถ Hover ได้ หรือสามารถทำเป็น Link นั่นเอง
สิ่งนี้หากเราเขียน HTML + CSS แต่ใน Flutter เราจะใช้ consept Widget
เริ่มจาก ลองสร้าง Text มา 1 อัน เราจะทำให้ Text อันนี้เป็นสามารถ hover ได้ เสมือนเป็น Link
Text(
"More detail",
style: TextStyle(fontSize: 28, color: Colors.blue[300]),
)
เพิ่มเขียนคลาส TextLink เป็น StatefulWidget โดยใน State จะมี boolean hover
โดยค่านี้เราจะ setState ตาม onEnter / onExit ของ MouseRegion
// text_link.dart
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class TextLink extends StatefulWidget {
final String text;
final Function()? onTap;
TextLink(this.text,{this.onTap});
@override
_TextLinkState createState() => _TextLinkState();
}
class _TextLinkState extends State<TextLink> {
bool isHover = false;
@override
Widget build(BuildContext context) {
return GestureDetector(onTap: widget.onTap,
child: MouseRegion(
cursor: SystemMouseCursors.click,
onEnter: (_) {
setState(() {
isHover = true;
});
},
onExit: (_) {
setState(() {
isHover = false;
});
},
child: Text(
widget.text,
style: TextStyle(
fontSize: 28, color: isHover ? Colors.blue[300] : Colors.grey[700]),
),
),
);
}
}
ขั้นตอนสุดท้าย เราก็เปลี่ยนมาใช้ TextLink ของเรา ก็จะได้ Text ที่สามารถ Hover แล้ว
TextLink(
"More detail",
onTap: (){
//
},
)
โดยการเปิด link จะต้องใช้ Library สำหรับเปิด URL ชื่อว่า url_launcher
https://pub.dev/packages/url_launcher
TextLink(
"Google",
onTap: () async {
String url = "https://www.google.com";
if (await canLaunch(url)) {
await launch(url);
}
})
จะได้แบบนี้
Tooltip
อีก Widget ที่น่าสนใจคือ Tooltip มักพบบ่อยๆใน โปรแกรม desktop และ web app โดยมันจะแสดงข้อความเมื่อเรานำ cursor ไปชี้ที่ widget ที่ต้องการ เพื่อแสดงคำอธิบาย
Tooltip(message: "go to /product/details/123",
child: TextLink(
"More detail",
onTap: (){
//
},
),
)
Tooltip สามารถปรับแต่ง สี และระยะเวลาการแสดงผลได้ด้วย หากอยากให้แสดง tooltip ด้านบน ให้กำหนด preferBelow เป็น false
Tooltip(
message: "Go to /product/details/123",
preferBelow: false,
decoration: BoxDecoration(
color: Colors.green[400],
borderRadius: BorderRadius.circular(16),
),
child: TextLink(
"More detail",
),
)
Keyboard
การทำงานใน Desktop เราสามารถใช้ keyboard แทนคำสั่งการทำงานหลายๆอย่างเป็นทางลัด (Shortcut) ซึ่ง Flutter มี Widget มารองรับเรื่องนี้เล่นกัน สามารถอ่านได้ที่บทความ 2 เรื่องด้านล่างนี้เลย
ตอนที่ 1 สำหรับทำ Keyboard Shortcut แบบดิบๆ เหมาะสำหรับแอปเล็กๆ
ตอนที่ 2 สำหรับทำ Keyboard Shortcut โดยใช้กลไก Shortcuts Widget ของ Flutter เหมาะสำหรับแอปขนาดใหญ่ ที่ต้องการทำระบบ shortcut ภายในแอป
Popup Menu
อีกเมนูที่เราน่าจะเห็นบ่อยๆเวลาที่เราคลิกขวาในแอป Desktop เรียกว่า Popup menu
สามารถอ่านวิธีการทำ Popup Menu ใน Flutter ได้ที่บทความข้างล่างนี้
Gesture Detector
เรื่อง Gesture ต่างๆ ใน Desktop และ Web จะมีส่วนเพิ่มเติมจาก Mobile เพราะมีการใช้ mouse เป็น input
โดย event การคลิกขวา จะเรียกว่า Secondary tap และการกดเม้ากลาง (ลูกกลิ้ง) จะเรียกว่า Teriary tap
GestureDetector(
onTapUp : (v){
// คลิกซ้าย
},
onSecondaryTap : (){
// คลิกขวา
},
onTertiaryTapDown : (v){
// คลิกเม้ากลาง
},
onDoubleTap : (){
// ดับเบิ้ลคลิกซ้าย
},
Draggable
ในบางแอปอาจจะมี interect ที่ซับซ้อนขึ้นไปอีก เช่น การลาก-วาง (กดเม้าค้างแล้วปล่อยในที่ๆต้องการ) ซึ่งสามารถพบเห็นได้บ่อย เช่นกัน เรียกว่า การทำ Draggable ซึ่งใน Flutter ก็มี Widget สำหรับการทำ Draggable อ่านได้จากบล็อกตอนเก่าๆของผมได้เลย
จบแล้ว
ก่อนจะจบ ขอเล่าเรื่องอีกนิด ผมลองเล่น Flutter Desktop & web มาตั้งแต่ Alpha / Beta และลองเล่นมาเรื่อยๆจนถึงวันนี้ (2021) ที่รองรับ Desktop & Web เป็น stable แล้ว ซึ่ง Flutter Team พยายามผลักดันมากให้ Flutter เป็น Cross Platform โดยสมบูรณ์แบบที่สุด ถ้าถามว่ามันพร้อมที่จะใช้งานใน Production จริงหรือยัง ส่วนตัวคิดว่า (ในปี 2021) Flutter Desktop พร้อมแล้วสามารถนำไปใช้งานใน production ได้จริง ส่วน Flutter Web นั้น จริงๆมันพร้อมกับการใช้งานจริงแล้วเช่นกัน เพียงแต่ว่าเทคโนโลยีการพัฒนาเว็บอื่นๆที่เป็น trend ในตอนนี้มันดีกว่ามาก ทำให้ Flutter Web ยังไม่ใช่ตัวเลือกที่ดีเท่าไหร่ หากใช้งานใน Web base ต้องรอดูว่าในปี 2022-2023 Flutter Web จะเป็นอย่างไรต่อไป