openplanning

Khuôn mẫu thiết kế Flutter với các lớp trừu tượng

  1. BaseScreen
  2. ProfileScreen
  3. SecurityScreen
  4. UserSettingsScreen
  5. MainApp
Trong lập trình Flutter, khá thường xuyên bạn phải tạo các trang (màn hình) gần tương tự nhau. Chẳng hạn một ứng dụng với 3 trang ProfileScreen, SecurityScreenUserSettingsScreen dưới đây:
Các vùng được đánh dấu bởi màu đỏ là sự khác biệt giữa 3 trang (màn hình) nói trên.
Trong bài viết này chúng ta sẽ thảo luận cách sử dụng lớp trừu tượng để thiết kế một giao diện người dùng cơ sở bao gồm các phần giống nhau của tất cả các trang nói trên. Phần khác biệt sẽ được thiết kế tại các lớp con.

1. BaseScreen

BaseScreen là một lớp trừu tượng tạo ra giao diện người dùng cơ sở. Phương thức trừu tượng buildMainContent() của nó sẽ tạo ra phần giao diện được đặt tại vùng màu đỏ.
Phương thức trừu tượng buildMainContent() sẽ được triển khai tại các lớp con của BaseScreen.
Widget buildMainContent(BuildContext context);
Phương thức buildMainContent() sẽ tạo ra giao diện tại vùng màu đỏ.
_base_screen.dart
import 'package:flutter/material.dart';

import '_top_menu_section.dart';

abstract class BaseScreen extends StatelessWidget {
  const BaseScreen({super.key, required this.title});

  final String title;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(title),
      ),
      body: _buildBody(context),
      floatingActionButton: FloatingActionButton(
        onPressed: () {},
        tooltip: 'Support',
        child: const Icon(Icons.support_agent),
      ),
    );
  }

  Widget _buildBody(BuildContext context) {
    return SingleChildScrollView(
      child: Column(
        children: [
          const TopMenuSection(),
          const SizedBox(height: 10),
          //
          Container(
            margin: const EdgeInsets.all(5),
            padding: const EdgeInsets.all(20),
            decoration: BoxDecoration(
              border: Border.all(
                color: Colors.indigo.withAlpha(80),
              ),
            ),
            child: ConstrainedBox(
              constraints: const BoxConstraints(minHeight: 300),
              child: buildMainContent(context), // Main Content (***) <=====
            ),
          ),
          //
          const SizedBox(height: 10),
          const Center(child: Text('@Copyright: o7planning')),
        ],
      ),
    );
  }

  // Abstract method to create Main Content Widget. (***) <=====
  Widget buildMainContent(BuildContext context);
}
Lớp TopMenuSection tạo ra một menu với 3 button.
_top_menu_section.dart
import 'package:flutter/material.dart';

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

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 10),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.center,
        mainAxisAlignment: MainAxisAlignment.spaceAround,
        children: [
          TextButton.icon(
            onPressed: () {
              Navigator.of(context).pushNamed('/profile');
            },
            icon: Icon(Icons.account_circle_outlined),
            label: Text("Profile"),
          ),
          TextButton.icon(
            onPressed: () {
              Navigator.of(context).pushNamed('/security');
            },
            icon: Icon(Icons.security),
            label: Text("Security"),
          ),
          TextButton.icon(
            onPressed: () {
              Navigator.of(context).pushNamed('/userSettings');
            },
            icon: Icon(Icons.settings),
            label: Text("Settings"),
          ),
        ],
      ),
    );
  }
}

2. ProfileScreen

ProfileScreen là một lớp con của BaseScreen, nó sẽ triển khai phương thức buildMainContent().
profile_screen.dart
import 'package:flutter/material.dart';
import '_base_screen.dart';

class ProfileScreen extends BaseScreen {
  const ProfileScreen({super.key, required super.title});

  @override
  Widget buildMainContent(BuildContext context) {
    return const Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Center(
          child: Column(
            children: [
              Icon(Icons.person, size: 80, color: Colors.indigo),
              Text(
                'Tom',
                style: TextStyle(color: Colors.indigo),
              ),
            ],
          ),
        ),
        SizedBox(height: 15),
        Text('Full Name: Tom'),
        SizedBox(height: 15),
        Text('Address: American'),
      ],
    );
  }
}

3. SecurityScreen

SecurityScreen là một lớp con của BaseScreen, nó sẽ triển khai phương thức buildMainContent().
security_screen.dart
import 'package:flutter/material.dart';
import '_base_screen.dart';

class SecurityScreen extends BaseScreen {
  const SecurityScreen({super.key, required super.title});

  @override
  Widget buildMainContent(BuildContext context) {
    return const Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text('Full Name: Tom'),
        SizedBox(height: 5),
        Divider(),
        SizedBox(height: 5),
        Text('Change Password:', style: TextStyle(fontWeight: FontWeight.bold)),
        SizedBox(height: 15),
        TextField(
          obscureText: true,
          decoration: InputDecoration(
            label: Text('New Password'),
            border: OutlineInputBorder(),
          ),
        ),
        SizedBox(height: 15),
        TextField(
          obscureText: true,
          decoration: InputDecoration(
            label: Text('Confirm'),
            border: OutlineInputBorder(),
          ),
        ),
      ],
    );
  }
}

4. UserSettingsScreen

UserSettingsScreen là một lớp con của BaseScreen, nó sẽ triển khai phương thức buildMainContent().
user_settings_screent.dart
import 'package:flutter/material.dart';
import '_base_screen.dart';

class UserSettingsScreen extends BaseScreen {
  const UserSettingsScreen({super.key, required super.title});

  @override
  Widget buildMainContent(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text('Full Name: Tom'),
        SizedBox(height: 5),
        Divider(),
        SizedBox(height: 5),
        Text('Payment Method:', style: TextStyle(fontWeight: FontWeight.bold)),
        SizedBox(height: 15),
        Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            RadioListTile<String>(
              contentPadding: EdgeInsets.zero,
              title: Text('Paypal'),
              value: 'paypal',
              groupValue: 'paypal',
              onChanged: (String? value) {},
            ),
            RadioListTile<String>(
              contentPadding: EdgeInsets.zero,
              title: Text('GPay'),
              value: 'gpay',
              groupValue: 'paypal',
              onChanged: (String? value) {},
            ),
            TextButton(onPressed: () {}, child: Icon(Icons.check)),
          ],
        )
      ],
    );
  }
}

5. MainApp

main.dart
import 'package:flutter/material.dart';
import 'user_settings_screen.dart';
import 'security_screen.dart';
import 'profile_screen.dart';

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

var routeMap = {
  "/profile": (BuildContext context) => ProfileScreen(title: 'User Profile'),
  "/security": (BuildContext context) => SecurityScreen(title: 'Security'),
  "/userSettings": (BuildContext context) =>
      UserSettingsScreen(title: 'User Settings'),
};

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      routes: routeMap,
      initialRoute: "/profile",
    );
  }
}

Các hướng dẫn lập trình Flutter

Show More