Menu
CoddyTech

Hai màn hình, một mô hình

Thuộc phần Quản lý trạng thái trong hành trình Flutter của Coddy. Bài học 13 trên 27.

Dữ liệu được hai màn hình chia sẻ chính là lúc Provider phát huy tác dụng. Màn hình Settings thay đổi tên, còn màn hình chính hiển thị tên đó, mà hai màn hình không cần truyền dữ liệu cho nhau.

Vị trí đặt provider rất quan trọng. MaterialApp chứa một Navigator, và mỗi màn hình bạn mở sẽ được thêm vào đó bên cạnh home, chứ không nằm bên trong:

ChangeNotifierProvider        <- above MaterialApp: every screen finds it
  MaterialApp
    Navigator
      HomePage
      SettingsScreen          <- pushed next to HomePage

Provider bọc quanh HomePage chỉ tiếp cận được HomePage. Màn hình được mở không nằm bên dưới nó, nên không thể tìm thấy model. Đặt provider phía trên MaterialApp, trong main, để mọi màn hình cùng chia sẻ model đó.

Đừng sửa lỗi bằng cách thêm một ChangeNotifierProvider thứ hai ở màn hình còn lại. Cách đó tạo ra model thứ hai: lỗi biến mất, nhưng các màn hình không còn chia sẻ dữ liệu.

challenge icon

Thử thách

Trung bình

Nhấn vào biểu tượng bánh răng, nhập tên rồi nhấn Save: ứng dụng báo lỗi vì provider chỉ bọc HomePage.

  • Chuyển ChangeNotifierProvider ra khỏi MyApp và đưa vào main, bao quanh MyApp.

Sau đó, lưu Ada sẽ hiển thị Hello, Ada! ở trang chủ.

Tự làm thử

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

class Profile extends ChangeNotifier {
  String _name = 'Guest';

  String get name => _name;

  void rename(String newName) {
    _name = newName;
    notifyListeners();
  }
}

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: ChangeNotifierProvider(
        create: (context) => Profile(),
        child: const HomePage(),
      ),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    final profile = context.watch<Profile>();
    return Scaffold(
      appBar: AppBar(
        title: const Text('Home'),
        actions: [
          IconButton(
            icon: const Icon(Icons.settings),
            onPressed: () {
              Navigator.push(
                context,
                MaterialPageRoute(builder: (context) => const SettingsScreen()),
              );
            },
          ),
        ],
      ),
      body: Center(
        child: Text('Hello, ${profile.name}!', style: const TextStyle(fontSize: 32)),
      ),
    );
  }
}

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

  @override
  State<SettingsScreen> createState() => _SettingsScreenState();
}

class _SettingsScreenState extends State<SettingsScreen> {
  final controller = TextEditingController();

  @override
  Widget build(BuildContext context) {
    final profile = context.watch<Profile>();
    return Scaffold(
      appBar: AppBar(title: const Text('Settings')),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          children: [
            Text('Signed in as ${profile.name}'),
            const SizedBox(height: 16),
            TextField(
              controller: controller,
              decoration: const InputDecoration(labelText: 'Your name'),
            ),
            const SizedBox(height: 16),
            ElevatedButton(
              onPressed: () {
                context.read<Profile>().rename(controller.text);
                Navigator.pop(context);
              },
              child: const Text('Save'),
            ),
          ],
        ),
      ),
    );
  }
}
quiz iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Quản lý trạng thái

Tự luyện tập: Trình biên dịch Flutter online