Flutter: Using Hover Widget not working on Touch Input devices

Issue

I made a widget that consists of an image (profile picture), That when you hover over it, you can select a file to be used as the new profile picture.
For an odd reason, some PNG files would not work. So, I convert PNG to JPG before showing it. It’s working fine on Desktop platforms and Desktop Web. When using touch, it wouldn’t work, and trying to wrap it with gesture control would not work either. So that gives us an unusable widget on touch-based devices on the web. I use a different page for Web and Desktop platforms since File picker does not work on the web.

on Desktop:

HoverWidget(
                hoverChild: Container(
                  height: sy(68),
                  width: sy(68),
                  decoration: BoxDecoration(
                    shape: BoxShape.circle,
                    border: Border.all(
                      color: Colors.white,
                      width: 0.1,
                    ),
                  ),
                  child: CircleAvatar(
                    radius: sy(68),
                    backgroundColor: Colors.white,
                    backgroundImage: Img.FileImage(filee),
                    child: ClipRRect(
                      borderRadius:
                          BorderRadius.all(Radius.circular(sy(68))),
                      child: BackdropFilter(
                        filter: ImageFilter.blur(sigmaX: 4, sigmaY: 4),
                        child: Container(
                          alignment: Alignment.center,
                          color: Colors.grey.withOpacity(0.1),
                          child: Center(
                              child: Material(
                            elevation: 5.0,
                            borderRadius: BorderRadius.circular(30.0),
                            color: const Color(0xff1f59b6),
                            child: ElevatedButton(
                              child: Container(
                                  height: sy(16),
                                  width: sy(42),
                                  child: Center(
                                      child: Text(
                                    "Choose Image",
                                    style: TextStyle(
                                        fontSize: sy(6),
                                        fontWeight: FontWeight.bold),
                                  ))),
                              onPressed: () {
                                _selectFile(context);
                              },
                            ),
                          )),
                        ),
                      ),
                    ),
                  ),
                ),
                onHover: (event) {
                  setState(() {
                    hovered = true;
                  });
                },
                child: Container(
                  height: sy(68),
                  width: sy(68),
                  decoration: BoxDecoration(
                    shape: BoxShape.circle,
                    border: Border.all(
                      color: Colors.white,
                      width: 0.1,
                    ),
                  ),
                  child: CircleAvatar(
                    radius: sy(68),
                    backgroundColor: Colors.white,
                    backgroundImage: Img.FileImage(filee),
                  ),
                ),
              ),

On Web:

HoverWidget(
                                    hoverChild: Container(
                                      height: sy(68),
                                      width: sy(68),
                                      decoration: BoxDecoration(
                                        shape: BoxShape.circle,
                                        border: Border.all(
                                          color: Colors.white,
                                          width: 0.1,
                                        ),
                                      ),
                                      child: CircleAvatar(
                                        radius: sy(68),
                                        backgroundColor: Colors.white,
                                        backgroundImage:
                                            Image.network(img).image,
                                        child: ClipRRect(
                                          borderRadius: BorderRadius.all(
                                              Radius.circular(sy(68))),
                                          child: BackdropFilter(
                                            filter: ImageFilter.blur(
                                                sigmaX: 4, sigmaY: 4),
                                            child: Container(
                                              alignment: Alignment.center,
                                              color:
                                                  Colors.grey.withOpacity(0.1),
                                              child: Center(
                                                  child: Material(
                                                elevation: 5.0,
                                                borderRadius:
                                                    BorderRadius.circular(30.0),
                                                color: const Color(0xff1f59b6),
                                                child: ElevatedButton(
                                                  child: Container(
                                                      height: sy(16),
                                                      width: sy(42),
                                                      child: Center(
                                                          child: Text(
                                                        "Choose Image",
                                                        style: TextStyle(
                                                            fontSize: sy(6),
                                                            fontWeight:
                                                                FontWeight
                                                                    .bold),
                                                      ))),
                                                  onPressed: () async {
                                                    var image =
                                                        await ImagePicker()
                                                            .pickImage(
                                                                source:
                                                                    ImageSource
                                                                        .gallery);
                                                    provider.setImage(image);
                                                    img = provider.image.path;
                                                  },
                                                ),
                                              )),
                                            ),
                                          ),
                                        ),
                                      ),
                                    ),
                                    onHover: (event) {
                                      setState(() {
                                        hovered  = true;
                                      });
                                    },
                                    child: Container(
                                      height: sy(68),
                                      width: sy(68),
                                      decoration: BoxDecoration(
                                        shape: BoxShape.circle,
                                        border: Border.all(
                                          color: Colors.white,
                                          width: 0.1,
                                        ),
                                      ),
                                      child: CircleAvatar(
                                        radius: sy(68),
                                        backgroundColor: Colors.white,
                                        backgroundImage:
                                            Image.network(img).image,
                                      ),
                                    ),
                                  ),

Solution

Replace Hover Widget with Gesture Detector, set hovered value to false by default.
Now it works on click. You can use https://pub.dev/packages/platform_detect to detect platfrom and browser to decide when to use hover and when to use click.
I ran into this problem so I wanted to share it with you, Hope it helps!

 GestureDetector(
                                  onTap: () {
                                    setState(() {
                                      hoverd = true;
                                    });
                                    Timer(Duration(seconds: 10), () {
                                      setState(() {
                                        hoverd = false;
                                      });
                                    });
                                  },
                                  child: hoverd == true
                                      ? Container(
                                          height: sy(68),
                                          width: sy(68),
                                          decoration: BoxDecoration(
                                            shape: BoxShape.circle,
                                            border: Border.all(
                                              color: Colors.white,
                                              width: 0.1,
                                            ),
                                          ),
                                          child: CircleAvatar(
                                            radius: sy(68),
                                            backgroundColor: Colors.white,
                                            backgroundImage:
                                                Image.network(img).image,
                                            child: ClipRRect(
                                              borderRadius: BorderRadius.all(
                                                  Radius.circular(sy(68))),
                                              child: BackdropFilter(
                                                filter: ImageFilter.blur(
                                                    sigmaX: 4, sigmaY: 4),
                                                child: Container(
                                                  alignment: Alignment.center,
                                                  color: Colors.grey
                                                      .withOpacity(0.1),
                                                  child: Center(
                                                      child: Material(
                                                    elevation: 5.0,
                                                    borderRadius:
                                                        BorderRadius.circular(
                                                            30.0),
                                                    color:
                                                        const Color(0xff1f59b6),
                                                    child: ElevatedButton(
                                                      child: Container(
                                                          height: sy(16),
                                                          width: sy(42),
                                                          child: Center(
                                                              child: Text(
                                                            "Choose Image",
                                                            style: TextStyle(
                                                                fontSize: sy(6),
                                                                fontWeight:
                                                                    FontWeight
                                                                        .bold),
                                                          ))),
                                                      onPressed: () async {
                                                        var image = await ImagePicker()
                                                            .pickImage(
                                                                source:
                                                                    ImageSource
                                                                        .gallery);
                                                        provider
                                                            .setImage(image);
                                                        img =
                                                            provider.image.path;
                                                        setState(() {
                                                          hoverd = false;
                                                        });
                                                      },
                                                    ),
                                                  )),
                                                ),
                                              ),
                                            ),
                                          ),
                                        )
                                      : Container(
                                          height: sy(68),
                                          width: sy(68),
                                          decoration: BoxDecoration(
                                            shape: BoxShape.circle,
                                            border: Border.all(
                                              color: Colors.white,
                                              width: 0.1,
                                            ),
                                          ),
                                          child: CircleAvatar(
                                            radius: sy(68),
                                            backgroundColor: Colors.white,
                                            backgroundImage:
                                                Image.network(img).image,
                                          ),
                                        ),
                                )

Answered By – Adham Fouad Hussein

Answer Checked By – David Goodson (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *