-
Notifications
You must be signed in to change notification settings - Fork 26.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Buttons don't splash when hovered, turning black for one frame if 'unhovered'. #110266
Comments
I have migrated the code to null safety and I can reproduce this issue. Reproducible on
InfoCode Sampleimport 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
static const String _title = 'Flutter Code Sample';
@override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: Scaffold(
appBar: AppBar(title: const Text(_title)),
body: const MyStatefulWidget(),
),
);
}
}
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({Key? key}) : super(key: key);
@override
State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
bool inFocus = false;
@override
Widget build(BuildContext context) {
ButtonStyle buttonStyle = ButtonStyle(
overlayColor: MaterialStateProperty.resolveWith<Color?>(
(Set<MaterialState> states) {
if (states.contains(MaterialState.focused)) {
return Colors.white;
}
if (states.contains(MaterialState.hovered)) {
return Colors.orange;
}
if (states.contains(MaterialState.pressed)) {
return Colors.yellowAccent;
}
return null; // Defer to the widget's default.
},
),
);
return Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
color: Colors.blue,
child: SizedBox(
height: 100,
width: 100,
child: TextButton(
onPressed: () {},
style: buttonStyle,
child: const Text(
"Hi",
style: TextStyle(color: Colors.black),
),
),
),
),
],
),
);
}
} Flutter Doctor
|
This is related to 180566f |
The flash appears to be due the fact that the button's grey default hover color is inherited from ThemeData which defines it unconditionally. It looks like you can workaround the problem by having the ButtonStyle overlayColor return Colors.transparent instead of the null. |
@Wissperwind Is the solution proposed above suitable for your use case? @HansMuller Is this intended or still considered a bug? If it's intended, would it make sense to document this behavior? |
About the splash not showing, it is related to this change
When the InkWell is focused and pressed, statesController.value contains both MaterialState.hovered and MaterialState.pressed so if the resolveWith’s callback checks for MaterialState.hovered before MaterialState.pressed , the hover color is always returned.
While waiting for a fix in the framework, a workaround is to reorder the Updated code sample with splash workaroundimport 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
static const String _title = 'Flutter Code Sample';
@override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: Scaffold(
appBar: AppBar(title: const Text(_title)),
body: const MyStatefulWidget(),
),
);
}
}
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({Key? key}) : super(key: key);
@override
State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
bool inFocus = false;
@override
Widget build(BuildContext context) {
ButtonStyle buttonStyle = ButtonStyle(
overlayColor: MaterialStateProperty.resolveWith<Color?>(
(Set<MaterialState> states) {
if (states.contains(MaterialState.pressed)) {
return Colors.yellowAccent;
}
if (states.contains(MaterialState.focused)) {
return Colors.white;
}
if (states.contains(MaterialState.hovered)) {
return Colors.orange;
}
return null; // Defer to the widget's default.
},
),
);
return Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
color: Colors.blue,
child: SizedBox(
height: 100,
width: 100,
child: TextButton(
onPressed: () {},
style: buttonStyle,
child: const Text(
"Hi",
style: TextStyle(color: Colors.black),
),
),
),
),
],
),
);
}
}
|
Changing the return null to a return Colors.transparent does not change anything as far as I observe. |
@Wissperwind - this flaw isn't easy to see since hovering in and out of a brightly colored button creates a bit of an optical illusion around the button's color. I was watching the return value of getHighlightColorForType() (material/ink_well.dart) and it appeared that returning the default grey correlated with the flashing you've brought up. Does @bleroux 's workaround work for you? #110266 (comment) @exaby73 - this is still a bug. |
@HansMuller Thanks for the clarification :) |
@bleroux - (#110266 (comment)), the original test case did not show the pressed (yellow) overlay color because - as you pointed out - the button's state is @Wissperwind - I'm not really sure what failure mode you're reporting. You said "I experienced that the flash on a button click has some black glitches" but you were "not able to reproduce the exact behaviour" (in a small test case). To fix the problem you've run into we really need a test case, a description of the failure mode, and the interaction needed to reproduce the problem. |
Ok, let's just fix the problems that were reproducable in the code Example I provided. The one that someone migrated to null saftety:
|
The test case below demos the problem. If you quickly slide the mouse in and out of the square on top there does appear to be a black flash in between frames. However the button on the bottom is configured in the same way, except that the background and overlay colors have alpha=0.25. In that case I don't see any black flash (or any flash at all). Is the black flash just an optical illusion? hover test caseimport 'package:flutter/material.dart';
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
color: Colors.blue,
child: SizedBox(
height: 100,
width: 100,
child: TextButton(
style: ButtonStyle(
overlayColor: MaterialStateProperty.resolveWith<Color?>(
(Set<MaterialState> states) {
if (states.contains(MaterialState.hovered)) {
return Colors.orange;
}
return Colors.transparent;
},
),
),
onPressed: () {},
child: const Text('Hello', style: TextStyle(color: Colors.black)),
),
),
),
SizedBox(height: 16),
Container(
color: Colors.blue.withOpacity(0.25),
child: SizedBox(
height: 100,
width: 100,
child: TextButton(
style: ButtonStyle(
overlayColor: MaterialStateProperty.resolveWith<Color?>(
(Set<MaterialState> states) {
if (states.contains(MaterialState.hovered)) {
return Colors.orange.withOpacity(0.25);
}
return Colors.transparent;
}
),
),
onPressed: () {},
child: const Text('Hello', style: TextStyle(color: Colors.black)),
),
),
),
],
),
),
);
}
}
void main() {
runApp(MaterialApp(home: Home()));
}
|
No, it is not. I will post a video tomorrow morning. |
I'd appreciate that. I've tried running the test case on Chrome/macOS and if there's a flash it's not obvious. |
Here's a version of the test case with hover test case with timeDilation=10import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart' show timeDilation;
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
color: Colors.blue,
child: SizedBox(
height: 100,
width: 100,
child: TextButton(
style: ButtonStyle(
overlayColor: MaterialStateProperty.resolveWith<Color?>(
(Set<MaterialState> states) {
if (states.contains(MaterialState.hovered)) {
return Colors.orange;
}
return null;
},
),
),
onPressed: () {},
child: const Text('Hello', style: TextStyle(color: Colors.black)),
),
),
),
SizedBox(height: 16),
Container(
color: Colors.blue.withOpacity(0.25),
child: SizedBox(
height: 100,
width: 100,
child: TextButton(
style: ButtonStyle(
overlayColor: MaterialStateProperty.resolveWith<Color?>(
(Set<MaterialState> states) {
if (states.contains(MaterialState.hovered)) {
return Colors.orange.withOpacity(0.25);
}
return null;
}
),
),
onPressed: () {},
child: const Text('Hello', style: TextStyle(color: Colors.black)),
),
),
),
],
),
),
);
}
}
void main() {
timeDilation = 10;
runApp(MaterialApp(home: Home()));
} |
This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of |
Hi,
I just updated flutter to the curret version (3.1.0-0.0.pre.2481) and checked my flutter web application if everything is still fine.
Unfortunately it is not. In the real application I experienced that the splash on a button click has some black glitches. So I hover, I click, it splashes, but the "outside area of the splash" is black. Or lets say a darker color than bevore the update. Can't tell for sure it is back.
I tried to produce a minimal working example but was not able to reproduce the exact behaviour.
But there are till some strange things. Here is my code:
So if I move the mouse on to the button the collor changes. Fine BUT:
Maybe solving these problems solves also the problem in my main application.
The text was updated successfully, but these errors were encountered: