TimePickerDialog: Đặt Giờ Chuẩn Gen Z trong Flutter!
Flutter

TimePickerDialog: Đặt Giờ Chuẩn Gen Z trong Flutter!

Author

Admin System

@root

Ngày xuất bản

22 Mar, 2026

Lượt xem

2 Lượt

"TimePickerDialog"

Chào các homies Gen Z mê code! Hôm nay, anh Creyt sẽ dẫn mấy đứa đi khám phá một cái “đồng hồ báo thức” cực xịn trong Flutter, đó là TimePickerDialog. Nghe tên thì hơi học thuật nhưng thực ra nó là ông hoàng của việc chọn giờ trong app, giúp app mình trông chuyên nghiệp và dễ dùng hơn rất nhiều.

TimePickerDialog là gì mà "chill" thế?

Thực ra, TimePickerDialog nó như một cái bảng điều khiển thời gian mini, bật lên cái là cho người dùng chọn giờ và phút một cách trực quan, nhanh gọn lẹ. Thay vì phải gõ tay từng số, từng chữ số 0, hay loay hoay với format 12h/24h, thì anh bạn này sẽ show ra một giao diện đẹp đẽ, chuẩn Material Design để người dùng chỉ việc "chạm và chọn".

Để làm gì ư? Đơn giản là để app của mấy đứa có thể hỏi người dùng "Mấy giờ bạn muốn đặt lịch?", "Mấy giờ bạn muốn hẹn giờ báo thức?", hay "Mấy giờ ship đồ ăn đến nhà?". Nó là mảnh ghép không thể thiếu cho các ứng dụng có yếu tố thời gian, giúp trải nghiệm người dùng mượt mà như lướt TikTok vậy.

Code Ví Dụ: Gọi "Thần Đèn" TimePickerDialog ra sao?

Để triệu hồi TimePickerDialog, chúng ta sẽ dùng hàm showTimePicker. Nó là một Future, nên kết quả trả về sẽ là một TimeOfDay? (có thể là null nếu người dùng hủy bỏ).

Cứ hình dung thế này: mấy đứa bấm nút "Chọn Giờ", Flutter sẽ hỏi "Mấy giờ?". Người dùng chọn xong, Flutter sẽ trả lại cái giờ đó cho mình xử lý. Easy peasy!

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'TimePicker Demo của Creyt',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: const TimePickerScreen(),
    );
  }
}

class TimePickerScreen extends StatefulWidget {
  const TimePickerScreen({super.key});

  @override
  State<TimePickerScreen> createState() => _TimePickerScreenState();
}

class _TimePickerScreenState extends State<TimePickerScreen> {
  TimeOfDay? _selectedTime; // Biến để lưu giờ đã chọn

  // Hàm bất đồng bộ để hiển thị TimePickerDialog
  Future<void> _selectTime(BuildContext context) async {
    // Gọi showTimePicker và chờ kết quả
    final TimeOfDay? pickedTime = await showTimePicker(
      context: context, // Context cần thiết để hiển thị dialog
      initialTime: _selectedTime ?? TimeOfDay.now(), // Giờ khởi tạo (nếu chưa chọn thì lấy giờ hiện tại)
      builder: (BuildContext context, Widget? child) {
        // Đây là chỗ để tùy chỉnh theme cho dialog, cho nó 'tone-sur-tone' với app mình
        return Theme(
          data: ThemeData.light().copyWith(
            primaryColor: Colors.teal, // Màu chủ đạo của dialog (phần header)
            colorScheme: const ColorScheme.light(primary: Colors.teal, onPrimary: Colors.white), // Màu sắc cho các thành phần chính
            buttonTheme: const ButtonThemeData(textTheme: ButtonTextTheme.primary), // Màu chữ nút
          ),
          child: child!, // Đừng quên trả về child!
        );
      },
    );

    // Kiểm tra xem người dùng có chọn giờ không (không phải null) và có khác giờ cũ không
    if (pickedTime != null && pickedTime != _selectedTime) {
      setState(() {
        _selectedTime = pickedTime; // Cập nhật lại giờ đã chọn và render lại UI
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Chọn Giờ Cùng Creyt'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              _selectedTime == null
                  ? 'Chưa chọn giờ nào cả, bấm nút đi bro!'
                  : 'Giờ bạn chọn là: ${_selectedTime!.format(context)}',
              style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
              textAlign: TextAlign.center,
            ),
            const SizedBox(height: 30),
            ElevatedButton.icon(
              onPressed: () => _selectTime(context), // Gọi hàm chọn giờ khi nhấn nút
              icon: const Icon(Icons.access_time),
              label: const Text('Chọn Giờ Ngay!', style: TextStyle(fontSize: 18)),
              style: ElevatedButton.styleFrom(
                padding: const EdgeInsets.symmetric(horizontal: 30, vertical: 15),
                shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

Giải thích nhanh:

  • _selectedTime: Biến TimeOfDay? để lưu trữ giờ mà người dùng chọn. Dấu ? có nghĩa là nó có thể null (chưa chọn hoặc người dùng hủy).
  • _selectTime(BuildContext context): Hàm async này sẽ gọi showTimePicker.
  • initialTime: Cái này quan trọng nè. Nó là giờ mặc định khi dialog hiện ra. Nếu _selectedTime đã có giá trị thì dùng nó, không thì lấy TimeOfDay.now() (giờ hiện tại).
  • builder: Đây là "phù thủy" giúp mấy đứa tùy chỉnh theme cho cái dialog, cho nó khớp với màu sắc của app mình. Đừng để nó lạc quẻ nha!
  • setState: Sau khi người dùng chọn giờ và pickedTime không null, chúng ta dùng setState để cập nhật biến _selectedTime và làm mới giao diện.
Illustration

Mẹo của Creyt: Dùng sao cho "đỉnh của chóp"?

  1. Luôn có initialTime hợp lý: Đừng để người dùng phải cuộn mãi mới đến giờ hiện tại. Hãy set initialTime là giờ hiện tại hoặc giờ đã được chọn trước đó.
  2. Kiểm tra null cẩn thận: Kết quả từ showTimePicker có thể là null nếu người dùng nhấn nút "Cancel" hoặc click ra ngoài. Luôn kiểm tra if (pickedTime != null) trước khi xử lý.
  3. Tùy chỉnh Theme qua builder: Như trong ví dụ, dùng builder để đảm bảo TimePickerDialog có màu sắc, font chữ đồng bộ với app. Đừng để nó trông như "con ghẻ" nha!
  4. Localization auto-magic: Hàm _selectedTime!.format(context) rất hay ở chỗ nó sẽ tự động định dạng giờ theo ngôn ngữ và cài đặt của thiết bị (ví dụ: 12h AM/PM ở Mỹ, 24h ở Việt Nam). Khỏi lo vụ đa ngôn ngữ!
  5. Tối ưu UX: Đặt nút gọi TimePickerDialog ở vị trí dễ nhìn, dễ chạm. Đừng bắt người dùng phải tìm kiếm như chơi trốn tìm.

Ứng dụng thực tế: "TimePickerDialog" đi đâu cũng gặp!

Nhìn quanh đi, mấy đứa sẽ thấy TimePickerDialog (hoặc các phiên bản tương tự) xuất hiện khắp nơi:

  • Google Calendar / Lịch của Apple: Khi tạo một sự kiện mới, mấy đứa chọn giờ bắt đầu/kết thúc.
  • Ứng dụng đặt báo thức: Như cái app Đồng Hồ của điện thoại đó, chọn giờ báo thức là y chang.
  • Các app giao đồ ăn / đặt xe: Chọn giờ giao hàng, giờ xe đến đón.
  • Ứng dụng quản lý công việc / nhắc nhở: Set deadline, set thời gian cho một task cụ thể.

Nói chung, cứ cái gì liên quan đến việc "chọn một mốc thời gian" là y như rằng có mặt anh bạn này.

Khi nào nên dùng và khi nào nên "né"?

Nên dùng khi:

  • Mấy đứa cần người dùng chọn một mốc thời gian cụ thể (giờ và phút) mà không cần ngày tháng. Nó sinh ra là để làm việc này mà.
  • Mấy đứa muốn giao diện chọn giờ chuẩn Material Design, nhất quán và đã được tối ưu về UX.
  • Mấy đứa muốn tiết kiệm thời gian, không muốn tự code lại một cái picker phức tạp.

Nên "né" khi:

  • Cần chọn cả ngày và giờ: Lúc này, mấy đứa sẽ cần kết hợp showDatePicker với showTimePicker, hoặc dùng một thư viện bên thứ ba như flutter_datetime_picker để có một dialog chọn cả hai trong một.
  • Cần chọn khoảng thời gian (duration): Ví dụ như "30 phút" hay "1 giờ 15 phút". TimePickerDialog chỉ chọn mốc thời gian, không phải độ dài thời gian.
  • Yêu cầu giao diện quá "dị": Nếu app của mấy đứa có một thiết kế chọn giờ cực kỳ độc đáo, không theo chuẩn Material Design, thì có thể phải tự vẽ (custom widget) hoặc tìm thư viện khác. Nhưng anh Creyt khuyên là hạn chế, vì nó tốn công và dễ phát sinh lỗi.

Kinh nghiệm của anh Creyt: Trong 90% trường hợp, TimePickerDialog của Flutter là đủ và là lựa chọn tốt nhất. Đừng cố gắng "phát minh lại bánh xe" trừ khi có lý do cực kỳ chính đáng. Nó đã được Flutter team tối ưu rất kỹ rồi, cứ thế mà dùng thôi!

Thuộc Series: Flutter

Bài giảng này được tự động xuất bản ngẫu nhiên từ thư viện kiến thức. Đừng quên đón xem các Từ khoá Hướng Dẫn tiếp theo nhé!

#tech #cyberpunk #laravel
Chỉnh sửa bài viết

Bình luận (0)

Vui lòng Đăng Nhập để Bình luận

Hỗ trợ Markdown cơ bản
Nguyễn Văn A
1 ngày trước

Tính năng này đỉnh quá ad ơi, chờ mãi mới thấy một blog Tiếng Việt có UI/UX xịn như vầy!