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

如何在Flutter中使用Cubit实现跨页面状态更新?

跨路由同步视频点赞状态(Flutter Bloc/Cubit实现方案)

核心解决思路是让所有相关页面共享同一个Cubit实例,这样任意页面触发的状态更新会自动同步到所有监听该Cubit的页面。以下是具体实现步骤:

1. 定义共享的Cubit与状态类

首先创建管理视频状态的Cubit,用Map存储每个视频的点赞数据(以视频ID为key),确保状态更新能被正确检测:

import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:equatable/equatable.dart';

// 单条视频的状态数据
class VideoData extends Equatable {
  final int likeCount;
  final bool isLiked;

  const VideoData({required this.likeCount, required this.isLiked});

  // 生成新状态的拷贝方法
  VideoData copyWith({int? likeCount, bool? isLiked}) {
    return VideoData(
      likeCount: likeCount ?? this.likeCount,
      isLiked: isLiked ?? this.isLiked,
    );
  }

  @override
  List<Object> get props => [likeCount, isLiked];
}

// 全局视频状态
class VideoState extends Equatable {
  final Map<String, VideoData> videoMap;

  const VideoState({required this.videoMap});

  // 初始状态示例
  factory VideoState.initial() {
    return VideoState(
      videoMap: {
        "Video1.mp4": const VideoData(likeCount: 0, isLiked: false),
        // 可添加其他视频初始数据
      },
    );
  }

  @override
  List<Object> get props => [videoMap];
}

// 视频状态管理Cubit
class VideoCubit extends Cubit<VideoState> {
  VideoCubit() : super(VideoState.initial());

  // 点赞/取消点赞操作
  void toggleLike(String videoId) {
    final currentData = state.videoMap[videoId];
    if (currentData == null) return;

    final newIsLiked = !currentData.isLiked;
    final newLikeCount = newIsLiked ? currentData.likeCount + 1 : currentData.likeCount - 1;

    // 更新Map并发送新状态
    final updatedMap = Map<String, VideoData>.from(state.videoMap)
      ..[videoId] = currentData.copyWith(likeCount: newLikeCount, isLiked: newIsLiked);

    emit(VideoState(videoMap: updatedMap));
  }
}

2. 在全局提供Cubit实例

在应用入口处用BlocProvider包裹MaterialApp,让所有路由页面都能访问到同一个VideoCubit实例:

void main() {
  runApp(
    BlocProvider(
      create: (context) => VideoCubit(),
      child: const MyApp(),
    ),
  );
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      routes: {
        '/': (context) => const ScreenA(),
        '/screenB': (context) => const ScreenB(),
        '/screenC': (context) => const ScreenC(),
      },
    );
  }
}

3. 在各页面中监听状态并触发操作

Screen-A 中展示视频与点赞状态

用BlocBuilder监听VideoCubit的状态变化,自动更新UI:

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("视频列表")),
      body: BlocBuilder<VideoCubit, VideoState>(
        builder: (context, state) {
          final videoData = state.videoMap["Video1.mp4"];
          if (videoData == null) return const SizedBox();

          return Column(
            children: [
              // 视频播放组件
              const VideoPlayerWidget(videoId: "Video1.mp4"),
              // 点赞按钮与计数
              Row(
                children: [
                  IconButton(
                    icon: Icon(
                      videoData.isLiked ? Icons.favorite : Icons.favorite_border,
                      color: videoData.isLiked ? Colors.red : null,
                    ),
                    onPressed: () => context.read<VideoCubit>().toggleLike("Video1.mp4"),
                  ),
                  Text("点赞数: ${videoData.likeCount}"),
                  // 跳转到Screen-B的按钮
                  TextButton(
                    onPressed: () => Navigator.pushNamed(context, '/screenB'),
                    child: const Text("查看详情"),
                  ),
                ],
              ),
            ],
          );
        },
      ),
    );
  }
}

Screen-C 中触发点赞操作

同样获取共享的VideoCubit实例,点击按钮时调用toggleLike:

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("单个视频播放")),
      body: Column(
        children: [
          const VideoPlayerWidget(videoId: "Video1.mp4"),
          BlocBuilder<VideoCubit, VideoState>(
            builder: (context, state) {
              final videoData = state.videoMap["Video1.mp4"];
              return IconButton(
                icon: Icon(
                  videoData?.isLiked ?? false ? Icons.favorite : Icons.favorite_border,
                  color: Colors.red,
                ),
                onPressed: () => context.read<VideoCubit>().toggleLike("Video1.mp4"),
              );
            },
          ),
        ],
      ),
    );
  }
}

关键注意事项

  • 确保所有需要同步状态的页面都在BlocProvider的子树中,这样才能获取到同一个Cubit实例。
  • 使用Equatable重写props方法,确保Bloc能正确检测状态变化,避免不必要的UI重建。
  • 如果视频数据是从API动态加载的,可在VideoCubit中添加fetchVideoData方法,初始化或更新视频状态。

内容的提问来源于stack exchange,提问作者Biswas Khayargoli

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 11:01:34