flutter: 用riverpod分离view层和viewmodel层

一,安装

项目地址:

https://pub.dev/packages/flutter_riverpod

安装:

dependencies:
  flutter:
    sdk: flutter
  go_router: ^17.2.3
  flutter_riverpod: ^3.2.1

二,代码:

main.dart

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:myrouter/router/router.dart';


void main() {
  // 包裹ProviderScope,使整个APP可以使用Riverpod
  runApp(
    const ProviderScope(
      child: MyApp(),
    ),
  );
}


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

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {

    return MaterialApp.router(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      routerConfig: router,
    );
  }

router.dart

import 'package:myrouter/pages/home_page.dart';
import 'package:go_router/go_router.dart';
import 'package:myrouter/views/UserView.dart';

final router = GoRouter(routes: [
  GoRoute(
    path: "/",
    builder: (context, state) => const HomePage(),
  ),
  GoRoute(
    path: '/setting',
    builder: (context, state) {
      // ✨ 核心代码:从 state.uri.queryParameters 中提取参数
      final id = state.uri.queryParameters['id'] ?? 0;
      final name = state.uri.queryParameters['name'] ?? '';
      final idint = int.tryParse(id?.toString() ?? '') ?? 0;

      return UserView(
        id: idint,
        name: name,
      );
    },

  )
]);

UserModel.dart


class UserModel {
  final int id;
  final String name;

  UserModel({required this.id, required this.name});
}

home_page.dart

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

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

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) {
    String name = '苏轼';
    int id = 123;
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: const Text('主页'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              '主页',
              style: TextStyle(fontSize: 40),
            ),
            // 点击跳转到设置页面
            ElevatedButton(
              onPressed: () => GoRouter.of(context).push('/setting?name=${name}&id=${id}'),
              style: ElevatedButton.styleFrom(
                foregroundColor: Theme.of(context).colorScheme.onSecondary,
                backgroundColor: Theme.of(context).colorScheme.secondary,
              ),
              child: const Text('跳转到设置页面'),
            )
          ],
        ),
      ),
    );
  }
}

UserViewModel.dart

import 'package:flutter_riverpod/flutter_riverpod.dart';

import '../models/userModel.dart';

// ViewModel: 负责业务逻辑
class UserViewModel extends Notifier<UserModel?> {

  @override
  UserModel? build() => null; // 初始状态为空

  // 更新用户信息
  void setUser(int id, String name) {
    state = UserModel(id: id, name: name);
  }

  // 模拟修改用户信息的方法
  void updateUserInfo(int newId, String newName) {
    state = UserModel(id: newId, name: newName);
  }
}

// 全局 Provider:让 View 可以访问这个 ViewModel
final userProvider = NotifierProvider<UserViewModel, UserModel?>(() {
  return UserViewModel();
});

UserView.dart

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

import '../viewmodels/UserViewModel.dart';


class UserView extends ConsumerStatefulWidget {
  final int id;
  final String name;
  const UserView({super.key, required this.id, required this.name});

  @override
  ConsumerState<UserView> createState() => _DetailPageState();
}

class _DetailPageState extends ConsumerState<UserView> {
  @override
  void initState() {
    super.initState();
    // 💡 关键点:进入页面时,将路由参数存入 ViewModel
    Future.microtask(() {
      ref.read(userProvider.notifier).setUser(widget.id, widget.name);
    });
  }

  @override
  Widget build(BuildContext context) {
    // 监听 ViewModel 中的数据变化
    final user = ref.watch(userProvider);

    return Scaffold(
      appBar: AppBar(title: const Text('详情页')),
      body: Center(
        child: user == null
            ? const CircularProgressIndicator()
            : Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('ID: ${user.id}', style: const TextStyle(fontSize: 24)),
            Text('姓名: ${user.name}', style: const TextStyle(fontSize: 24)),
            const SizedBox(height: 20),
            ElevatedButton(
              onPressed: () {
                // ✨ 核心:调用 ViewModel 的方法修改数据
                ref.read(userProvider.notifier).updateUserInfo(101, "杨万里");
              },
              child: const Text('更新为杨万里'),
            ),
          ],
        ),
      ),
    );
  }
}

三,测试效果:

image

image

 

posted @ 2026-05-05 19:20  刘宏缔的架构森林  阅读(0)  评论(0)    收藏  举报