You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter/Dart应用实现多账户登录及切换、增删功能的方案

实现Flutter/Dart多账户功能(类似Instagram)

1. 定义账户数据模型

先创建UserAccount类,封装账户核心信息,支持序列化用于本地存储:

class UserAccount {
  final String id;
  final String username;
  final String avatarUrl;
  final String authToken; // 接口请求令牌

  UserAccount({
    required this.id,
    required this.username,
    required this.avatarUrl,
    required this.authToken,
  });

  // 序列化/反序列化方法
  Map<String, dynamic> toJson() => {
        'id': id,
        'username': username,
        'avatarUrl': avatarUrl,
        'authToken': authToken,
      };

  factory UserAccount.fromJson(Map<String, dynamic> json) => UserAccount(
        id: json['id'],
        username: json['username'],
        avatarUrl: json['avatarUrl'],
        authToken: json['authToken'],
      );
}

2. 本地存储账户数据

用shared_preferences实现账户的持久化存储,封装读写删操作:

import 'package:shared_preferences/shared_preferences.dart';
import 'dart:convert';

class AccountStorage {
  static const String _accountsKey = 'saved_accounts';
  static const String _currentAccountIdKey = 'current_account_id';

  // 保存所有账户
  static Future<void> saveAccounts(List<UserAccount> accounts) async {
    final prefs = await SharedPreferences.getInstance();
    final accountsJson = accounts.map((acc) => jsonEncode(acc.toJson())).toList();
    await prefs.setStringList(_accountsKey, accountsJson);
  }

  // 读取所有账户
  static Future<List<UserAccount>> getAccounts() async {
    final prefs = await SharedPreferences.getInstance();
    final accountsString = prefs.getStringList(_accountsKey);
    if (accountsString == null || accountsString.isEmpty) return [];
    return accountsString
        .map((str) => UserAccount.fromJson(jsonDecode(str)))
        .toList();
  }

  // 保存当前选中账户ID
  static Future<void> saveCurrentAccountId(String accountId) async {
    final prefs = await SharedPreferences.getInstance();
    await prefs.setString(_currentAccountIdKey, accountId);
  }

  // 获取当前选中账户ID
  static Future<String?> getCurrentAccountId() async {
    final prefs = await SharedPreferences.getInstance();
    return prefs.getString(_currentAccountIdKey);
  }

  // 删除指定账户
  static Future<void> deleteAccount(String accountId) async {
    final accounts = await getAccounts();
    final updatedAccounts = accounts.where((acc) => acc.id != accountId).toList();
    await saveAccounts(updatedAccounts);
    
    // 处理当前账户被删除的情况
    final currentId = await getCurrentAccountId();
    if (currentId == accountId) {
      if (updatedAccounts.isNotEmpty) {
        await saveCurrentAccountId(updatedAccounts.first.id);
      } else {
        await prefs.remove(_currentAccountIdKey);
      }
    }
  }
}

3. 全局状态管理(Provider)

用ChangeNotifier封装账户状态,提供切换、添加、删除的核心逻辑:

import 'package:flutter/material.dart';

class AccountProvider extends ChangeNotifier {
  List<UserAccount> _accounts = [];
  UserAccount? _currentAccount;

  List<UserAccount> get accounts => _accounts;
  UserAccount? get currentAccount => _currentAccount;

  // 初始化加载本地账户数据
  Future<void> init() async {
    _accounts = await AccountStorage.getAccounts();
    final currentId = await AccountStorage.getCurrentAccountId();
    if (currentId != null) {
      _currentAccount = _accounts.firstWhere((acc) => acc.id == currentId);
    }
    notifyListeners();
  }

  // 添加新账户
  Future<void> addAccount(UserAccount newAccount) async {
    if (!_accounts.any((acc) => acc.id == newAccount.id)) {
      _accounts.add(newAccount);
      await AccountStorage.saveAccounts(_accounts);
      // 首次添加自动设为当前账户
      if (_currentAccount == null) {
        await switchAccount(newAccount.id);
      }
      notifyListeners();
    }
  }

  // 切换账户
  Future<void> switchAccount(String accountId) async {
    _currentAccount = _accounts.firstWhere((acc) => acc.id == accountId);
    await AccountStorage.saveCurrentAccountId(accountId);
    notifyListeners();
    // 这里可添加切换后的逻辑,比如重置API客户端、清空缓存等
    // await ApiClient.resetToken(_currentAccount!.authToken);
  }

  // 删除账户
  Future<void> removeAccount(String accountId) async {
    await AccountStorage.deleteAccount(accountId);
    _accounts = await AccountStorage.getAccounts();
    final currentId = await AccountStorage.getCurrentAccountId();
    _currentAccount = currentId != null
        ? _accounts.firstWhere((acc) => acc.id == currentId)
        : null;
    notifyListeners();
  }
}

4. UI实现示例

账户切换面板(类似Instagram的头像弹窗)

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

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

  @override
  Widget build(BuildContext context) {
    return Consumer<AccountProvider>(
      builder: (context, provider, child) {
        return PopupMenuButton<UserAccount>(
          icon: CircleAvatar(
            backgroundImage: NetworkImage(provider.currentAccount?.avatarUrl ?? 'https://picsum.photos/200'),
          ),
          itemBuilder: (context) {
            return [
              // 添加新账户选项
              const PopupMenuItem(
                value: null,
                child: Row(
                  children: [
                    Icon(Icons.add),
                    SizedBox(width: 8),
                    Text("添加账户"),
                  ],
                ),
              ),
              const PopupMenuDivider(),
              // 已保存账户列表
              ...provider.accounts.map((account) {
                return PopupMenuItem<UserAccount>(
                  value: account,
                  child: Row(
                    children: [
                      CircleAvatar(
                        backgroundImage: NetworkImage(account.avatarUrl),
                      ),
                      const SizedBox(width: 8),
                      Text(account.username),
                      if (account.id == provider.currentAccount?.id)
                        const Padding(
                          padding: EdgeInsets.only(left: 8),
                          child: Icon(Icons.check, color: Colors.blue),
                        ),
                    ],
                  ),
                );
              }),
              const PopupMenuDivider(),
              // 删除账户选项
              PopupMenuItem(
                onTap: () => _showDeleteDialog(context, provider),
                child: const Row(
                  children: [
                    Icon(Icons.delete, color: Colors.red),
                    SizedBox(width: 8),
                    Text("删除账户", style: TextStyle(color: Colors.red)),
                  ],
                ),
              ),
            ];
          },
          onSelected: (account) {
            if (account != null) {
              provider.switchAccount(account.id);
            } else {
              Navigator.push(context, MaterialPageRoute(builder: (_) => const AddAccountPage()));
            }
          },
        );
      },
    );
  }

  void _showDeleteDialog(BuildContext context, AccountProvider provider) {
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: const Text("删除账户"),
        content: const Text("确定要删除当前账户吗?"),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(context),
            child: const Text("取消"),
          ),
          TextButton(
            onPressed: () {
              if (provider.currentAccount != null) {
                provider.removeAccount(provider.currentAccount!.id);
              }
              Navigator.pop(context);
            },
            child: const Text("删除", style: TextStyle(color: Colors.red)),
          ),
        ],
      ),
    );
  }
}

添加账户页面(示例登录页)

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

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

  @override
  State<AddAccountPage> createState() => _AddAccountPageState();
}

class _AddAccountPageState extends State<AddAccountPage> {
  final _usernameController = TextEditingController();

  Future<void> _login() async {
    // 模拟登录接口请求,替换为真实逻辑
    final newAccount = UserAccount(
      id: DateTime.now().millisecondsSinceEpoch.toString(),
      username: _usernameController.text,
      avatarUrl: "https://picsum.photos/200/200?random=${_usernameController.text}",
      authToken: "token_${_usernameController.text}",
    );

    await Provider.of<AccountProvider>(context, listen: false).addAccount(newAccount);
    Navigator.pop(context);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("登录新账户")),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          children: [
            TextField(
              controller: _usernameController,
              decoration: const InputDecoration(labelText: "用户名"),
            ),
            TextField(
              decoration: const InputDecoration(labelText: "密码"),
              obscureText: true,
            ),
            const SizedBox(height: 24),
            ElevatedButton(
              onPressed: _login,
              child: const Text("登录"),
            ),
          ],
        ),
      ),
    );
  }
}

5. 全局初始化配置

在main函数中初始化Provider和账户数据:

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

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(
    ChangeNotifierProvider(
      create: (context) => AccountProvider()..init(),
      child: const MyApp(),
    ),
  );
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Consumer<AccountProvider>(
            builder: (context, provider, child) {
              return Text(provider.currentAccount?.username ?? "未登录");
            },
          ),
          actions: const [AccountSwitcher()],
        ),
        body: Center(
          child: Consumer<AccountProvider>(
            builder: (context, provider, child) {
              return Text(
                provider.currentAccount != null
                    ? "当前账户:${provider.currentAccount!.username}"
                    : "请登录账户",
                style: const TextStyle(fontSize: 18),
              );
            },
          ),
        ),
      ),
    );
  }
}

内容的提问来源于stack exchange,提问作者Mohammed Hussein

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 13:52:51