Search code examples
androidiosflutterdartdrag-and-drop

How to specify drag target for a certain widget Flutter (Single Draggable Being Dropped Into 3 Drag Targets Instead Of 1)


Here is the problem that I am facing:

I start off with a list of emoji's which I want to drop into these 3 Drop Targets

(I want to be able to select each emoji which goes into each of these drop targets) enter image description here

When I drag one of these emojis (only one, which is in this case, the first one, it automatically drops into all the drag targets instead of only the first one).

This results in the same emoji populating all the drag targets unintentionally like this which is unexpected behavior:

enter image description here

My question is, how can I change my code so that I can make sure that, when I drag on emoji into the first, second, or third Drag target, only that respective drag target gets filled instead of all of them? Thanks a lot and I really appreciate your help!

Code For DragBox:

class DragBox extends StatefulWidget {
  DragBox({this.animatedAsset, this.width});
  final LottieBuilder animatedAsset;
  final double width;
  @override
  _DragBoxState createState() => _DragBoxState();
}

class _DragBoxState extends State<DragBox> {
  @override
  Widget build(BuildContext context) {
    return Draggable(
      feedback: Container(
        width: 50,
        height: 50,
        child: widget.animatedAsset,
      ),
      child: Container(
        child: widget.animatedAsset,
        width: widget.width,
        height: 50,
      ),
      childWhenDragging: Container(),
      data: widget.animatedAsset,
    );
  }
}

Code For Emoji Picker :

class AnimatedEmojiPicker extends StatefulWidget {
  @override
  _AnimatedEmojiPickerState createState() => _AnimatedEmojiPickerState();
}

class _AnimatedEmojiPickerState extends State<AnimatedEmojiPicker> {
  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.only(left: 10.0, right: 10.0),
      child: Container(
        width: MediaQuery.of(context).size.width,
        height: 60,
        decoration:
            BoxDecoration(color: Colors.grey.shade400.withOpacity(0.5), borderRadius: BorderRadius.circular(20.0)),
        child: ListView(
          scrollDirection: Axis.horizontal,
          children: <Widget>[
            Container(
              width: 15,
            ),
            DragBox(
              animatedAsset: Lottie.asset('Assets/blushing.json'),
            ),
            Container(
              width: 15,
            ),
            DragBox(
              animatedAsset: Lottie.asset('Assets/cooldude.json'),
            ),
            Container(
              width: 15,
            ),
            DragBox(
              animatedAsset: Lottie.asset('Assets/zipmouth.json'),
            ),
            //More drag boxes like this one
          ],
        ),
      ),
    );
  }
}

My Drag targets:

                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  DragTarget(
                    onAccept: (LottieBuilder animation) {
                      setState(() {
                        widget.caughtAnimation = animation;
                      });
                    },
                    builder: (BuildContext context, List<dynamic> candidateData, List<dynamic> rejectedData) {
                      return Center(
                        child: Container(
                          height: 60,
                          width: 60,
                          decoration: BoxDecoration(
                              color: Colors.grey.shade400.withOpacity(0.5), borderRadius: BorderRadius.circular(20.0)),
                          child: widget.caughtAnimation,
                        ),
                      );
                    },
                  ),
                  Padding(
                    padding: const EdgeInsets.all(8.0),
                    child: DragTarget(
                      onAccept: (LottieBuilder animation) {
                        setState(() {
                          widget.caughtAnimation = animation;
                        });
                      },
                      builder: (BuildContext context, List<dynamic> candidateData, List<dynamic> rejectedData) {
                        return Center(
                          child: Container(
                            height: 60,
                            width: 60,
                            decoration: BoxDecoration(
                                color: Colors.grey.shade400.withOpacity(0.5),
                                borderRadius: BorderRadius.circular(20.0)),
                            child: widget.caughtAnimation,
                          ),
                        );
                      },
                    ),
                  ),
                  DragTarget(
                    onAccept: (LottieBuilder animation) {
                      setState(() {
                        widget.caughtAnimation = animation;
                      });
                    },
                    builder: (BuildContext context, List<dynamic> candidateData, List<dynamic> rejectedData) {
                      return Center(
                        child: Container(
                          height: 60,
                          width: 60,
                          decoration: BoxDecoration(
                              color: Colors.grey.shade400.withOpacity(0.5), borderRadius: BorderRadius.circular(20.0)),
                          child: widget.caughtAnimation,
                        ),
                      );
                    },
                  ),
                ],
              ),

Again, thanks for any help!


Solution

  • This is happening because on each DragTarget you are building the same widget.caughtAnimation that you set on any onAccept callback.

    Consider structuring your widget state model in a way that you can individually modify each DragTarget, this can be done with a List/array or a map.

    List<LottieBuilder> caughtAnimations;
    

    then

                    mainAxisAlignment: MainAxisAlignment.center,
                    children: <Widget>[
                      DragTarget(
                        onAccept: (LottieBuilder animation) {
                          setState(() {
                            caughtAnimations[0] = animation;
                          });
                        },
                        builder: (BuildContext context, List<dynamic> candidateData, List<dynamic> rejectedData) {
                          return Center(
                            child: Container(
                              height: 60,
                              width: 60,
                              decoration: BoxDecoration(
                                  color: Colors.grey.shade400.withOpacity(0.5), borderRadius: BorderRadius.circular(20.0)),
                              child: caughtAnimations[0],
                            ),
                          );
                        },
                      ),
                      Padding(
                        padding: const EdgeInsets.all(8.0),
                        child: DragTarget(
                          onAccept: (LottieBuilder animation) {
                            setState(() {
                              caughtAnimations[1] = animation;
                            });
                          },
                          builder: (BuildContext context, List<dynamic> candidateData, List<dynamic> rejectedData) {
                            return Center(
                              child: Container(
                                height: 60,
                                width: 60,
                                decoration: BoxDecoration(
                                    color: Colors.grey.shade400.withOpacity(0.5),
                                    borderRadius: BorderRadius.circular(20.0)),
                                child: caughtAnimations[1],
                              ),
                            );
                          },
                        ),
                      ),
                      DragTarget(
                        onAccept: (LottieBuilder animation) {
                          setState(() {
                            caughtAnimations[2] = animation;
                          });
                        },
                        builder: (BuildContext context, List<dynamic> candidateData, List<dynamic> rejectedData) {
                          return Center(
                            child: Container(
                              height: 60,
                              width: 60,
                              decoration: BoxDecoration(
                                  color: Colors.grey.shade400.withOpacity(0.5), borderRadius: BorderRadius.circular(20.0)),
                              child: caughtAnimations[2],
                            ),
                          );
                        },
                      ),
                    ],
                  ),