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

Flutter bottom sheet có ô nhập: chừa chỗ cho bàn phím bằng viewInsets

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

Một bottom sheet trông vừa màn hình khi mở, nhưng nút đóng hoặc ô nhập lại bị bàn phím che. Thay vì thêm một khoảng trống cố định theo chiếc điện thoại đang dùng, hãy đọc phần giao diện bị che từ MediaQuery và cho nội dung một đường cuộn khi không còn đủ chỗ.

Bài này dựng form ghi chú ngắn để bạn thử trên dự án Flutter. Mục tiêu là phân biệt quyền sử dụng chiều cao của sheet, khoảng chừa cho bàn phím và vùng cuộn. Ba phần này giải quyết những vấn đề khác nhau.

Điều kiện và giới hạn kiểm chứng

Đối chiếu API Flutter hiện hành ngày 11/11/2026: showModalBottomSheet, MediaQueryData.viewInsets và SingleChildScrollView. Ví dụ đã được rà theo hợp đồng API, nhưng chưa chạy Flutter SDK, analyzer, emulator, thiết bị hoặc kiểm thử trợ năng. Không có kết quả đo bàn phím hay animation được tuyên bố trong bài.

Hãy đặt code vào lib/main.dart của một dự án Flutter tương thích với các API được dẫn. Kiểm tra phiên bản SDK của dự án khi áp dụng; bài không khẳng định mọi dự án Flutter cũ đều hỗ trợ cùng một tập tham số.

1. Một màn hình và một sheet nhỏ

import 'package:flutter/material.dart';

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

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

  void _openSheet(BuildContext context) {
    showModalBottomSheet<void>(
      context: context,
      isScrollControlled: true,
      useSafeArea: true,
      builder: (sheetContext) {
        final keyboard = MediaQuery.of(sheetContext).viewInsets.bottom;
        return Padding(
          padding: EdgeInsets.only(bottom: keyboard),
          child: SingleChildScrollView(
            padding: const EdgeInsets.all(16),
            child: Column(
              mainAxisSize: MainAxisSize.min,
              crossAxisAlignment: CrossAxisAlignment.stretch,
              children: [
                const Text('Ghi chú thử nghiệm'),
                const SizedBox(height: 12),
                const TextField(
                  minLines: 2,
                  maxLines: 4,
                  decoration: InputDecoration(labelText: 'Nội dung'),
                ),
                const SizedBox(height: 12),
                FilledButton(
                  onPressed: () => Navigator.of(sheetContext).pop(),
                  child: const Text('Đóng'),
                ),
              ],
            ),
          ),
        );
      },
    );
  }

  @override
  Widget build(BuildContext context) => Scaffold(
    appBar: AppBar(title: const Text('Bottom sheet demo')),
    body: Center(
      child: FilledButton(
        onPressed: () => _openSheet(context),
        child: const Text('Mở ghi chú'),
      ),
    ),
  );
}

Nút Đóng chỉ đóng ví dụ, không lưu dữ liệu. Không có request, controller hoặc trạng thái ngoài sheet. Nhờ vậy, khi một vùng bị che, bạn có thể tập trung quan sát layout thay vì đồng thời debug việc gửi form.

2. Đọc ba phần của layout

isScrollControlled cho phép route của sheet sử dụng cơ chế chiều cao phù hợp với nội dung có thể cuộn. Nó không phải lệnh tự cộng khoảng cách bằng chiều cao bàn phím vào form. Trong ví dụ, việc chừa phần dưới được thể hiện riêng bằng Padding.

viewInsets.bottom mô tả phần dưới bị system UI che, thường là bàn phím. Code đọc từ sheetContext trong builder thay vì lấy một số cố định khi màn hình đầu tiên được tạo. Khi dữ liệu MediaQuery thay đổi, phần phụ thuộc có thể được build lại theo inset mới.

SingleChildScrollView tạo đường cuộn cho form ngắn khi không gian giảm. Column dùng kích thước chính tối thiểu; không đặt Expanded bên trong vùng cuộn dọc không có giới hạn chiều cao theo cách tùy tiện. Ví dụ chỉ có vài control, không dùng cấu trúc này để dựng hàng nghìn item.

3. Tự kiểm tra trên thiết bị đích

Mở sheet khi bàn phím chưa hiện, chạm ô nhập rồi kiểm tra có cuộn tới nút Đóng được không. Gõ đủ bốn dòng, xoay màn hình và tăng kích thước chữ. Sau đó đóng bàn phím và xem khoảng trống bên dưới có trở về phù hợp không.

Đây là kế hoạch kiểm tra, chưa phải các kết quả đã quan sát. Nên lưu loại thiết bị, phiên bản hệ điều hành, chế độ bàn phím và SDK khi ghi lỗi. Bàn phím nổi hoặc bàn phím ngoài có thể tạo tình huống khác với bàn phím phần mềm gắn dưới màn hình.

Lỗi thường gặp

Thêm một Padding cố định có thể vừa với máy hiện tại nhưng thừa hoặc thiếu ở máy khác. Cộng inset ở nhiều lớp có thể đẩy nội dung lên quá xa. Khi app đã có lớp xử lý bàn phím riêng, hãy kiểm tra tổng khoảng cách trước khi chép thêm đoạn này.

useSafeArea của modal sheet xử lý các vùng xâm lấn theo hợp đồng riêng; không nên coi nó là đồng nghĩa với viewInsets. Ví dụ không đảm bảo toàn bộ layout hệ thống, focus, bàn phím mọi hãng hoặc trợ năng. Hãy kiểm thử các tình huống sản phẩm thực sự hỗ trợ.

Kết luận

Với form ngắn trong bottom sheet, tách rõ chiều cao route, khoảng chừa theo inset và khả năng cuộn. Dùng ví dụ tối thiểu để xác minh trên thiết bị trước khi ghép validation hoặc lưu dữ liệu.

Nguồn tham khảo

  • Flutter: showModalBottomSheet
  • Flutter: viewInsets
  • Flutter: SingleChildScrollView

Tags: Bàn phímBottom SheetFlutter
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

Flutter AnimatedOpacity: opacity bằng 0 chưa tự chặn thao tác chạm

by Suong Nguyen
10/11/2026
0

Tách độ trong suốt, hit testing và semantics khi làm nút biến mất bằng AnimatedOpacity, với cùng một state điều khiển từng phần.

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

Flutter DropdownButton: value cần khớp đúng một item, không phải một nhãn

by Suong Nguyen
09/11/2026
0

Dùng ID ổn định làm value của DropdownButton để hai mục có cùng nhãn vẫn được chọn đúng, kèm cách rà lựa chọn đã hết tồn tại.

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

Flutter TextField: readOnly khác enabled như thế nào với nút suffix?

by Suong Nguyen
08/11/2026
0

Chọn trạng thái TextField khi cần ngăn sửa nội dung, vẫn cho chọn chữ hoặc giữ nút suffix hoạt động, kèm màn hình kiểm tra hai trường.

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

Flutter InkWell: đặt nền và clip ở Material để thấy ripple đúng góc

by Suong Nguyen
07/11/2026
0

Dựng một thẻ tương tác với Material, Ink và InkWell, rồi kiểm tra vị trí vẽ ripple cùng vùng cắt bo góc.

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: thông báo nội dung đổi cho TalkBack bằng accessibilityLiveRegion
  • Promise.finally: return giá trị mới có thay kết quả của chuỗi không?
  • Android TextUtils.isEmpty không loại chuỗi toàn khoảng trắng

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