I have a list that contains a number of Draggables and DragTargets widgets. I want to change the color of the DragTargets when the state of a Draggable widget changes.
- Initially, the color of all DragTargets widgets should be grey but they should change to green when a Draggable widget is pressed.
- The color of all DragTargets widgets should change to grey again when the drag operation is completed or canceled.
I'm trying to achieve it by using flutter_bloc but I'm getting the following error: Error: Could not find the correct Provider<MyBloc> above this _InheritedProviderScope<MyBloc> Widget.
Here is a minimal example:
- ListItemBloc(MyBLoc)
class ListItemBloc extends Bloc<ListItemEvent, ListItemState> {
ListItemBloc() : super(ListItemInitial());
@override
Stream<ListItemState> mapEventToState(
ListItemEvent event,
) async* {
if (event is OnDragStarted) {
yield ListItemUpdated(true, false, false);
} else if (event is OnDragCompleted) {
yield ListItemUpdated(false, true, false);
} else if (event is OnDraggableCanceled) {
yield ListItemUpdated(false, false, true);
}
}
}
- ListItemState
abstract class ListItemState extends Equatable {
@override
List<Object?> get props => [];
}
class ListItemInitial extends ListItemState {}
class ListItemUpdated extends ListItemState {
final bool isOnDragStarted;
final bool isOnDragCompleted;
final bool isOnDraggableCanceled;
ListItemUpdated(
this.isOnDragStarted,
this.isOnDragCompleted,
this.isOnDraggableCanceled,
);
@override
List<Object?> get props => [
isOnDragStarted,
isOnDragCompleted,
isOnDraggableCanceled,
];
}
- ListItemEvent
abstract class ListItemEvent extends Equatable {
@override
List<Object?> get props => [];
}
class OnDragStarted extends ListItemEvent {}
class OnDragCompleted extends ListItemEvent {}
class OnDraggableCanceled extends ListItemEvent {}
- Visual
...
List<String> folders = ['folderA', 'folderB'];
List<String> images = [
'https://images.unsplash.com/photo-1622495805731-eefd22e836f4?ixid=MnwxMjA3fDF8MHxlZGl0b3JpYWwtZmVlZHwxfHx8ZW58MHx8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=900&q=60',
'https://images.unsplash.com/photo-1622472263439-28f6e98d05b7?ixid=MnwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHw0fHx8ZW58MHx8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=900&q=60',
'https://images.unsplash.com/photo-1622497274862-2dd4cd0ddaac?ixid=MnwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHw1fHx8ZW58MHx8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=900&q=60',
'https://images.unsplash.com/photo-1622506614848-65988f1f6b33?ixid=MnwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHwyfHx8ZW58MHx8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=900&q=60',
];
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
...
@override
Widget build(BuildContext context) {
final _length = folders.length + images.length;
return BlocProvider<ListItemBloc>(
create: (context) => context.read<ListItemBloc>(),
child: MaterialApp(
...
home: ListView.builder(
itemCount: _length,
itemBuilder: (context, index) {
if (index < folders.length) {
return MyDragTargetCard(folderName: folders[index]);
}
return MyDraggableCard(
index: index - 2,
imageUrl: images[index - 2],
);
},
),
),
);
}
}
class MyDraggableCard extends StatelessWidget {
final int index;
final String imageUrl;
...
@override
Widget build(BuildContext context) {
print(context.read<ListItemBloc>().state); // error while trying to know the current state
final GlobalKey _draggableKey = GlobalKey();
Image _image = Image.network(imageUrl);
return Draggable<Image>(
dragAnchorStrategy: pointerDragAnchorStrategy,
data: Image.network(imageUrl),
feedback: DraggingCard(
key: Key('_draggingCard$index'),
dragKey: _draggableKey,
image: _image,
),
child: Card(
...
child: _image,
),
onDragStarted: () => print('onDragStarted'),
onDragCompleted: () => print('onDragCompleted'),
onDraggableCanceled: (Velocity velocity, Offset offset) {
print('onDraggableCanceled');
},
);
}
}
class DraggingCard extends StatelessWidget {
final GlobalKey dragKey;
final Image image;
...
@override
Widget build(BuildContext context) {
final GlobalKey _draggableKey = GlobalKey();
return FractionalTranslation(
translation: const Offset(-0.5, -0.5),
child: ClipRRect(
key: _draggableKey,
...
child: SizedBox(
height: 150,
width: 150,
child: Opacity(
opacity: 0.85,
child: image,
),
),
),
);
}
}
class _MyDragTargetCardState extends State<MyDragTargetCard> {
late Color _folderColor;
@override
void initState() {
_folderColor = Colors.grey;
super.initState();
}
@override
Widget build(BuildContext context) {
print(context.read<ListItemBloc>().state); // error while trying to know the current state
return DragTarget<Image>(
builder: (context, candidateData, rejectedData) {
return Card(
color: _folderColor,
child: Center(child: Text(widget.folderName)),
);
},
onWillAccept: (item) => true,
onAccept: (item) => print('onAccept'),
onLeave: (item) => setState(() {
_folderColor = Colors.green;
}),
onMove: (item) => setState(() {
_folderColor = Colors.red;
}),
);
}
}
Any suggestions on how to get the current state of the bloc without getting the mentioned error?