web analytics

รวม 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 จะเป็นอย่างไรต่อไป