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)