如何在 ReorderableListView 中使用 BlocBuilder?

How to use BlocBuilder inside ReorderableListView?

当我尝试在 ReorderableListView 中使用 BlocBuilder 时,出现 Could not find the correct Provider<ThemeCubit> above this BlocBuilder<ThemeCubit, ThemeState> Widget 错误。当我在列表中拖动项目时发生错误。

示例:

List<int> _items = List<int>.generate(50, (int index) => index);

ReorderableListView(
      children: <Widget>[
        for (int index = 0; index < _items.length; index += 1)
          Container(
            key: Key(index.toString()),
            child: BlocBuilder<ThemeCubit, ThemeState>(
              builder: (___, ____) {
                return Text('Item ${_items[index]}');
              }
            )
          )
      ],
      onReorder: (int oldIndex, int newIndex) {},
    )

奇怪的是,如果我尝试使用 context.read<ThemeCubit>() 访问 bloc 数据,我不会收到错误消息。


可重现的例子 (main.dart)

当您拖动 列表中的项目时,问题重现。

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

class SimpleCubit extends Cubit<int>
{
  SimpleCubit() : super(0);
}

void main() async {
  runApp(MyTrip());
}

class AppName extends StatelessWidget {
  AppName({super.key});

  final List<int> _items = List<int>.generate(50, (int index) => index);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: MultiBlocProvider(
          providers: [
            BlocProvider<SimpleCubit>(
              create: (_) => SimpleCubit()
            ),
          ],
          child: ReorderableListView(
            children: <Widget>[
              for (int index = 0; index < _items.length; index += 1)
                Container(
                  key: Key(index.toString()),
                  child: BlocBuilder<SimpleCubit, int>(
                    builder: (_, state) {
                      return Text(state.toString());
                    }
                  )
                )
            ],
            onReorder: (int oldIndex, int newIndex) {},
          ),
        ),
      )
    );
  }
}

我无法用上面提供的示例重现该问题。但我可以假设你的问题是什么。

我修改了您的 Reproducible 示例以查看您遇到的相同错误:

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

class SimpleCubit extends Cubit<int> {
  SimpleCubit() : super(0);

  void onPress() {
    print('press');
  }
}

void main() async {
  runApp(MyTrip());
}

class MyTrip extends StatelessWidget {
  MyTrip({super.key});

  final List<int> _items = List<int>.generate(50, (int index) => index);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: MultiBlocProvider(
          providers: [
            BlocProvider<SimpleCubit>(create: (_) => SimpleCubit()),
          ],
          child: ReorderableListView(
            children: <Widget>[
              for (int index = 0; index < _items.length; index += 1)
                Container(
                  key: Key(index.toString()),
                  child: BlocBuilder<SimpleCubit, int>(
                    builder: (_, state) {
                      return GestureDetector(
                        onTap: context.read<SimpleCubit>().onPress,
                        child: Text(state.toString()),
                      );
                    },
                  ),
                ),
            ],
            onReorder: (int oldIndex, int newIndex) {},
          ),
        ),
      ),
    );
  }
}

此错误的解释是,如果您在同一个构建方法中提供此 bloc,则无法调用 bloc 方法,因为您指的是不包含此类 bloc 的上下文:

请查看您的示例的修改版本:

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

class SimpleCubit extends Cubit<int> {
  SimpleCubit() : super(0);

  void onPress() {
    print('press');
  }
}

void main() async {
  runApp(MyTrip());
}

class MyTrip extends StatelessWidget {
  const MyTrip({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: MultiBlocProvider(
          providers: [
            BlocProvider<SimpleCubit>(create: (_) => SimpleCubit()),
          ],
          child: _MyTrip(),
        ),
      ),
    );
  }
}

class _MyTrip extends StatelessWidget {
  _MyTrip({super.key});

  final List<int> _items = List<int>.generate(50, (int index) => index);

  @override
  Widget build(BuildContext context) {
    return ReorderableListView(
      children: <Widget>[
        for (int index = 0; index < _items.length; index += 1)
          Container(
            key: Key(index.toString()),
            child: BlocBuilder<SimpleCubit, int>(
              builder: (_, state) {
                return GestureDetector(
                  onTap: context.read<SimpleCubit>().onPress,
                  child: Text(state.toString()),
                );
              },
            ),
          ),
      ],
      onReorder: (int oldIndex, int newIndex) {},
    );
  }
}

这里我们将区块配置和使用分开。这就是它的设计用途。

只需用 BlocProvider 包装您的 MaterialApp,您的错误表明它没有找到上下文,因为您只将它提供给 ReorderableListView 小部件,因此您最好全局创建您的 bloc,以便任何具有上下文的小部件都可以调用它这样:(但它必须在您的主要 MATERIAL 应用程序中,在 MyTrip() 中)

void main() async {
  runApp(MyTrip());
}

class MyTrip extends StatelessWidget {

 MyTrip({super.key});
    
 @override
  Widget build(BuildContext context) {
    return MultiBlocProvider( //  like this
      providers: [
        BlocProvider<SimpleCubit>(create: (_) => SimpleCubit()),
      ],
      child: MaterialApp(
        [...] // here it has to be your routes, theme, translation, etc...
      ),
    );
  }