ReorderableListView: Khi List của bạn biết 'nhảy múa' theo ý Gen Z!
Flutter

ReorderableListView: Khi List của bạn biết 'nhảy múa' theo ý Gen Z!

Author

Admin System

@root

Ngày xuất bản

20 Mar, 2026

Lượt xem

4 Lượt

"ReorderableListViewState"

Chào các 'dev' Gen Z! Anh Creyt đây. Hôm nay, chúng ta sẽ cùng nhau 'mổ xẻ' một 'siêu năng lực' của Flutter mà chắc chắn các em sẽ mê tít: đó là khả năng biến những danh sách tĩnh thành những vũ công điêu luyện, sẵn sàng 'nhảy múa' theo từng cú kéo thả của người dùng. Từ khóa 'ReorderableListViewState' nghe có vẻ hàn lâm, nhưng thực ra nó là 'linh hồn' đứng sau widget ReorderableListView huyền thoại đó!

1. ReorderableListViewState là gì? Để làm gì? (Theo style Gen Z)

Nói thẳng và thật, ReorderableListViewState không phải là cái tên mà các em sẽ trực tiếp gọi hay tương tác nhiều trong code đâu. Nó giống như 'nhân vật ẩn' đằng sau hậu trường, là cái 'state' nội bộ của widget ReorderableListView – cái 'bộ não' giúp ReorderableListView làm được điều kỳ diệu: cho phép người dùng kéo thả các item để sắp xếp lại thứ tự trong một danh sách!

Thử hình dung thế này: Các em có một playlist nhạc trên Spotify, một danh sách công việc trên Trello, hay đơn giản là các sticker yêu thích trong Zalo. Khi các em kéo một bài hát lên đầu, một task xuống cuối, hay sắp xếp lại thứ tự các sticker, đó chính là lúc ReorderableListView đang 'nhảy múa' đấy! Và ReorderableListViewState chính là người đạo diễn thầm lặng, điều phối mọi chuyển động mượt mà đó.

Nó sinh ra để làm gì ư? Đơn giản là để nâng tầm trải nghiệm người dùng (UX) lên một tầm cao mới. Thay vì phải xóa đi tạo lại, hay dùng các nút 'lên/xuống' cổ lỗ sĩ, giờ đây người dùng có thể tự tay 'mix & match' lại danh sách theo ý mình, một cách trực quan và cực kỳ 'chill'.

2. Code Ví Dụ Minh Họa Rõ Ràng, Chuẩn Kiến Thức

Để ReorderableListView hoạt động, chúng ta cần hai thứ quan trọng:

  1. Một danh sách dữ liệu có thể thay đổi (mutable list): Vì khi kéo thả, thứ tự của dữ liệu sẽ thay đổi.
  2. Một callback onReorder: Đây là nơi 'bộ não' của chúng ta (code của các em) sẽ nhận thông báo khi người dùng kéo thả xong, và chúng ta phải cập nhật lại danh sách dữ liệu dựa trên vị trí mới.
  3. Key cho mỗi item: Cực kỳ quan trọng để Flutter biết chính xác item nào đang được di chuyển.

Đây là ví dụ kinh điển nhất để các em dễ hình dung:

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: 'Reorderable List Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const ReorderableListScreen(),
    );
  }
}

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

  @override
  State<ReorderableListScreen> createState() => _ReorderableListScreenState();
}

class _ReorderableListScreenState extends State<ReorderableListScreen> {
  List<String> _items = [
    'Ăn sáng',
    'Code Flutter',
    'Tập gym',
    'Ăn trưa',
    'Học thuật cùng anh Creyt',
    'Đi chơi với crush',
    'Ngủ '
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('To-do List của Gen Z'),
      ),
      body: ReorderableListView(
        padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
        children: <Widget>[
          for (int index = 0; index < _items.length; index += 1)
            Card(
              key: Key('$index'), // Cực kỳ quan trọng: mỗi item phải có một Key duy nhất!
              elevation: 2.0,
              margin: const EdgeInsets.symmetric(vertical: 4.0),
              child: ListTile(
                leading: CircleAvatar(
                  child: Text('${index + 1}'),
                ),
                title: Text(_items[index]),
                trailing: const Icon(Icons.drag_handle),
              ),
            ),
        ],
        onReorder: (int oldIndex, int newIndex) {
          setState(() {
            if (oldIndex < newIndex) {
              newIndex -= 1; // Điều chỉnh newIndex nếu item bị kéo xuống dưới
            }
            final String item = _items.removeAt(oldIndex); // Xóa item ở vị trí cũ
            _items.insert(newIndex, item); // Chèn item vào vị trí mới
          });
        },
      ),
    );
  }
}

Trong ví dụ trên, _items là danh sách các công việc. Khi người dùng kéo thả, hàm onReorder sẽ được gọi với oldIndex (vị trí ban đầu) và newIndex (vị trí đích). Nhiệm vụ của chúng ta là cập nhật lại _items trong setState để giao diện được vẽ lại theo thứ tự mới. Nhớ kỹ, Key cho mỗi Card là bắt buộc nhé!

Illustration

3. Mẹo (Best Practices) để ghi nhớ hoặc dùng thực tế

  • Key là VUA: Anh Creyt nhắc lại lần nữa, mỗi widget con trong children của ReorderableListView phải có một Key duy nhất. ValueKey, ObjectKey, hoặc đơn giản là Key('$index') nếu danh sách của em không quá phức tạp và các item không trùng lặp là đủ. Nếu không có Key, Flutter sẽ 'đứng hình' không biết item nào đang được di chuyển, dẫn đến lỗi hoặc hành vi không mong muốn.
  • onReorder không tự cập nhật UI: Nó chỉ là một 'tai mắt' báo cho em biết có sự thay đổi. Việc 'xử lý' thay đổi đó (bằng cách cập nhật data source và gọi setState) là trách nhiệm của lập trình viên. Đừng quên setState!
  • Xử lý newIndex: Khi kéo một item xuống dưới, newIndex có thể 'nhảy' một đơn vị. Đoạn if (oldIndex < newIndex) { newIndex -= 1; } trong onReorder là một 'trick' nhỏ để đảm bảo newIndex luôn trỏ đúng vào vị trí thực tế sau khi item bị xóa khỏi vị trí cũ. Hãy nhớ nó!
  • Tối ưu hiệu năng: Với danh sách cực dài, cân nhắc sử dụng ReorderableListView.builder thay vì ReorderableListView thông thường để tối ưu hóa việc xây dựng widget, tương tự như ListView.builder.
  • Phản hồi trực quan: ReorderableListView đã cung cấp sẵn một số hiệu ứng kéo thả mặc định khá mượt. Tuy nhiên, em có thể tùy chỉnh thêm như thay đổi màu nền, tăng elevation của Card khi đang kéo để người dùng biết họ đang thao tác với item nào.

4. Văn phong học thuật sâu của anh Creyt, dạy dễ hiểu tuyệt đối

ReorderableListView là một ví dụ điển hình cho triết lý 'Reactive Programming' của Flutter. Nó không chỉ đơn thuần là một widget hiển thị danh sách, mà là một 'cơ chế' cho phép giao diện người dùng tương tác trực tiếp với dữ liệu một cách linh hoạt. Cái State nội bộ của nó (mà chúng ta gọi là ReorderableListViewState) chịu trách nhiệm lắng nghe các cử chỉ kéo thả (drag gestures), tính toán vị trí mới, và sau đó 'truyền tin' cho chúng ta qua onReorder callback.

Gợi Ý Đọc Tiếp
Hướng dẫn "AnimatedPositionedDirectional" - Flutter

6 Lượt xem

Điều quan trọng ở đây là sự tách biệt rõ ràng giữa UI (User Interface)Data (Dữ liệu). ReorderableListView lo phần UI, làm cho việc kéo thả trông thật 'mượt'. Còn chúng ta, qua onReorder, lo phần Data, đảm bảo rằng khi UI thay đổi, dữ liệu underlying cũng phải được cập nhật tương ứng. Mối quan hệ hai chiều này chính là chìa khóa để xây dựng các ứng dụng mạnh mẽ và có khả năng mở rộng.

5. Ví dụ thực tế các ứng dụng/website đã ứng dụng

Các em dùng hàng ngày mà không để ý đó thôi:

  • Spotify/Apple Music: Sắp xếp lại thứ tự bài hát trong playlist.
  • Trello/Asana/Jira: Kéo thả các thẻ công việc giữa các cột hoặc trong cùng một cột.
  • Google Keep/Evernote: Sắp xếp lại thứ tự các ghi chú, danh sách.
  • Ứng dụng quản lý ảnh/video: Sắp xếp lại thứ tự ảnh/video trong album trước khi xuất bản.
  • Các ứng dụng mua sắm: Đôi khi cho phép người dùng sắp xếp lại các mục yêu thích hoặc trong giỏ hàng.

6. Thử nghiệm đã từng và hướng dẫn nên dùng cho case nào

Anh Creyt ngày xưa cũng từng 'trầy vi tróc vẩy' với việc tự implement kéo thả bằng GestureDetector, Draggable, DragTarget... Thật sự là một cơn ác mộng để làm cho nó mượt mà và xử lý đủ mọi trường hợp (như scroll khi kéo, feedback hình ảnh, v.v.). Khi ReorderableListView ra đời, nó giống như một 'ân huệ' từ Flutter Team vậy!

Nên dùng ReorderableListView khi:

  • Người dùng cần cá nhân hóa: Khi họ muốn tự tay sắp xếp thứ tự các mục theo ý muốn cá nhân (playlist, danh sách yêu thích, thứ tự hiển thị widget).
  • Quản lý tác vụ/nội dung: Các ứng dụng quản lý công việc, ghi chú, danh sách mua sắm, hoặc các ứng dụng cho phép người dùng sắp xếp lại nội dung (ví dụ: các slide trong một bài thuyết trình).
  • Tăng tính tương tác: Khi muốn làm cho ứng dụng của em trở nên 'sống động' và dễ sử dụng hơn, mang lại cảm giác 'nắm quyền kiểm soát' cho người dùng.

Không nên dùng khi:

  • Thứ tự của danh sách được xác định nghiêm ngặt bởi logic nghiệp vụ và người dùng không được phép thay đổi (ví dụ: danh sách kết quả tìm kiếm được sắp xếp theo mức độ liên quan, danh sách sản phẩm theo giá từ thấp đến cao).
  • Danh sách chỉ mang tính hiển thị thông tin một chiều, không cần bất kỳ tương tác sắp xếp nào từ người dùng.

Nhớ nhé, ReorderableListView là một công cụ cực kỳ mạnh mẽ để làm cho ứng dụng của em trở nên thân thiện và 'thông minh' hơn. Hãy luyện tập và áp dụng nó vào các project của mình, các em sẽ thấy sự khác biệt rõ rệt!

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!