aedev.net
  • Trang chủ
  • AI
  • Mobile
  • Flutter
  • React Native
  • Backend
  • DevOps
  • Hướng dẫn
No Result
View All Result
SAVED POSTS
aedev.net
  • Trang chủ
  • AI
  • Mobile
  • Flutter
  • React Native
  • Backend
  • DevOps
  • Hướng dẫn
No Result
View All Result
aedev.net
No Result
View All Result
Minh họa phát triển ứng dụng mobile đa nền tảng với Flutter

TextEditingController trong Flutter: giữ nội dung và con trỏ đúng vòng đời

Suong Nguyen by Suong Nguyen
24/10/2026
in Flutter
0
585
SHARES
3.2k
VIEWS
Summarize with ChatGPTShare to Facebook

Form đang gõ bỗng mất chữ khi một widget cha rebuild. Hoặc nút điền dữ liệu đưa con trỏ về vị trí khó đoán. Với TextEditingController, vấn đề không chỉ là lấy được chuỗi text; bạn còn cần xác định ai sở hữu controller và khi nào được phép thay nội dung người dùng đang sửa.

Bài này xây một màn hình nhỏ có nội dung ban đầu và nút khôi phục mẫu. Tài liệu Flutter được đối chiếu ngày 24/10/2026. SDK lưu tại máy biên tập ghi Flutter 3.47.7, Dart 3.13.5 trong metadata cache; ví dụ chưa được build hoặc chạy widget test trên SDK đó. Hãy xác nhận phiên bản dự án bằng flutter --version trước khi áp dụng.

1. Tách lúc tạo controller khỏi lúc build

TextEditingController giữ cả text, selection và vùng composing của trình nhập. Controller thông báo cho listener khi giá trị thay đổi. Vì vậy, thay text bằng code cũng có thể kích hoạt những listener mà bạn tự đăng ký.

Trong ví dụ, State tạo controller một lần và giải phóng nó khi State bị dispose. build chỉ sử dụng controller đã có. Nếu tạo controller mới trong build, bạn biến một lần dựng lại giao diện thành một lần thay đối tượng giữ trạng thái nhập liệu.

2. Ví dụ một màn hình tự đủ

Đặt mã vào lib/main.dart của một dự án Flutter thử nghiệm. MaterialApp và Scaffold cung cấp cấu trúc Material cho TextField. Đây là form minh họa, chưa có lưu dữ liệu hoặc request mạng.

import 'package:flutter/material.dart';

void main() => runApp(const MaterialApp(home: NotePage()));

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

  @override
  State<NotePage> createState() => _NotePageState();
}

class _NotePageState extends State<NotePage> {
  late final TextEditingController _controller;

  @override
  void initState() {
    super.initState();
    _controller = TextEditingController(text: 'Ghi chú ban đầu');
  }

  void _restoreSample() {
    const sample = 'Ghi chú mới';
    _controller.value = TextEditingValue(
      text: sample,
      selection: TextSelection.collapsed(offset: sample.length),
    );
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Sửa ghi chú')),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            TextField(
              controller: _controller,
              decoration: const InputDecoration(labelText: 'Nội dung'),
            ),
            const SizedBox(height: 16),
            FilledButton(
              onPressed: _restoreSample,
              child: const Text('Khôi phục mẫu'),
            ),
          ],
        ),
      ),
    );
  }
}

Nút thay cả giá trị và selection trong một lần gán. Offset bằng sample.length trỏ tới cuối chuỗi theo cách đánh chỉ số mà API selection sử dụng; đây không phải cách đếm số ký tự người dùng nhìn thấy. Khi cần đếm emoji hay giới hạn số ký tự hiển thị, hãy xử lý grapheme cluster theo hướng dẫn của formatter, không suy ra từ ví dụ đặt con trỏ này.

3. Xác định quyền sở hữu và chính sách cập nhật

State tự tạo controller thì State tự dispose. Nếu một widget nhận controller từ cha, cần thống nhất bên tạo sẽ giải phóng; đừng dispose một controller vẫn còn được cha sử dụng. Trong danh sách dựng lười, controller có thể cần được quản lý ở ancestor có vòng đời phù hợp thay vì tạo mới cho mỗi lần cell xuất hiện.

Nội dung mẫu được thay khi người dùng bấm nút. Với dữ liệu tải từ server, hãy quyết định rõ: có ghi đè nếu người dùng đã gõ không, có cần nút xác nhận không, và record đổi ID thì tạo phiên chỉnh sửa mới hay cập nhật phiên cũ? Không gán _controller.text trong mỗi lần build để “đồng bộ”, vì cách đó dễ xóa phần người dùng vừa sửa.

Gán thuộc tính text sẽ đặt lại selection và composing. Khi thực sự cần thay cả nội dung lẫn con trỏ, cập nhật value giúp bạn mô tả trạng thái mong muốn cùng lúc. Tuy nhiên, thay composing giữa lúc IME đang ghép chữ vẫn cần thận trọng.

4. Đừng sửa text vòng quanh listener

Một listener đọc text, chuyển chữ thường rồi gán lại controller có thể tự gọi lại chính nó. Với bàn phím đang quản lý vùng composing, vòng phản hồi giữa framework và IME còn khó xử lý hơn. Tài liệu controller nêu cụ thể rủi ro với Gboard.

Nếu cần định dạng khi gõ, xem TextInputFormatter. Tài liệu yêu cầu việc sửa text chỉ diễn ra khi IME đã commit, không can thiệp text còn composing. Ví dụ này cố ý không tự chuẩn hóa chữ khi người dùng nhập; nút khôi phục là một hành động riêng có ý nghĩa rõ ràng.

Kiểm tra kết quả

Trên emulator và thiết bị, nhập một ghi chú, làm widget cha rebuild rồi xác nhận nội dung không đổi. Bấm khôi phục, kiểm tra chuỗi mới và vị trí con trỏ. Tiếp tục thử gõ tiếng Việt, chọn một đoạn, dán emoji, mở rồi đóng màn hình nhiều lần.

Nếu cursor nhảy khi gõ, tìm mọi chỗ ghi vào text hoặc value, kể cả listener và callback nhận dữ liệu. Nếu form giữ nội dung của record trước, rà chính sách khi record ID thay đổi thay vì chỉ thêm setState. Nếu báo dùng sau dispose, kiểm tra controller có bị chia sẻ sang widget sống lâu hơn chủ sở hữu không.

Kết luận

Controller nên có chủ sở hữu rõ ràng và chỉ bị cập nhật vào những thời điểm được thiết kế. Giữ nó ngoài build, thay text cùng selection khi cần và kiểm tra IME thực tế sẽ giúp form ổn định hơn các bản vá chỉ xử lý chuỗi text.

Nguồn tham khảo

  • Flutter: TextEditingController
  • Flutter: TextField
  • Flutter: TextInputFormatter

Tags: FlutterFormTextEditingController
SummarizeShare234
Suong Nguyen

Suong Nguyen

Related Stories

Minh họa phát triển ứng dụng mobile đa nền tảng với Flutter

ValueNotifier trong Flutter: cập nhật list để giao diện nhận đúng thay đổi

by Suong Nguyen
23/10/2026
0

Hiểu cách ValueNotifier dùng phép so sánh bằng, cập nhật list bằng giá trị mới và quản lý vòng đời notifier rõ ràng.

Minh họa phát triển ứng dụng mobile đa nền tảng với Flutter

Tìm kiếm Flutter: debounce và chặn response cũ ghi đè kết quả mới

by Suong Nguyen
22/10/2026
0

Kết hợp Timer, mã phiên truy vấn và kiểm tra mounted để màn hình tìm kiếm không hiển thị nhầm kết quả khi mạng trả về lệch thứ...

Minh họa phát triển ứng dụng mobile đa nền tảng với Flutter

FutureBuilder trong Flutter: đừng tạo Future mới trong build

by Suong Nguyen
21/10/2026
0

Giữ Future ổn định trong State, hiển thị loading, lỗi và dữ liệu rỗng, đồng thời chỉ tải lại khi người dùng yêu cầu.

Minh họa phát triển ứng dụng mobile đa nền tảng với Flutter

Bắt đầu với Flutter: khi nào nên chọn cho dự án mobile?

by admin
02/07/2026
0

Flutter là lựa chọn đáng cân nhắc khi cần phát triển ứng dụng iOS và Android với một codebase, UI nhất quán và tốc độ ra sản phẩm...

0 0 votes
Article Rating
Subscribe
Login
Notify of
guest
guest
0 Comments
Oldest
Newest Most Voted
AE Dev

AE Dev mang đến các bài viết về lập trình, mobile app, backend, frontend, WordPress và công nghệ, phù hợp cho developer muốn học hỏi và cập nhật kiến thức thực tế.

Recent Posts

  • React Native useWindowDimensions: layout đổi chiều và vẫn đọc được chữ lớn
  • Promise.all và allSettled: chờ kết quả không có nghĩa là tự hủy tác vụ
  • Android SavedStateHandle: giữ bộ lọc khi process bị hệ thống tạo lại

Categories

  • AI
  • Backend
  • Đánh giá
  • DevOps
  • Flutter
  • Hướng dẫn
  • Lập trình Mobile
  • Phỏng vấn
  • React Native
  • Uncategorized

Weekly Newsletter

  • Buy JNews
  • Support Forum
  • Pre-sale Question
  • Contact Us

© 2026 AE Dev - Blog công nghệ, lập trình và chia sẻ kiến thức IT.

Welcome Back!

Login to your account below

Forgotten Password?

Retrieve your password

Please enter your username or email address to reset your password.

Log In
No Result
View All Result
  • Trang chủ
  • AI
  • Mobile
  • React Native
  • Backend
  • DevOps
  • Hướng dẫn
  • Flutter

© 2026 AE Dev - Blog công nghệ, lập trình và chia sẻ kiến thức IT.

wpDiscuz
0
0
Would love your thoughts, please comment.x
()
x
| Reply