Reputation: 61
I have a Widget, and I want to change its background color while the user is pressing it, and when the pressing is finished, it returns to its original color.
I tried to use a GestureDetector, implementing onTapDown and onTapUp functions, but it doesn't work: it takes a long time (~150ms) to change color and, if I tap at normal speed, the color doesn't change.
I am an Android developer, and what I want to do is done in Android using a selector as follows:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="..." android:state_pressed="true" />
<item android:drawable="..." />
</selector>.
But I don't know how to do that with flutter. I hope the piece of code will help to understand what I want to achieve.
Upvotes: 5
Views: 4020
Reputation: 33
Here is how I would do it:
class MyWidget extends StatefulWidget {
@override
_MyWidgetState createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> with SingleTickerProviderStateMixin {
AnimationController _controller;
Color myColor = Colors.blue;
@override
void initState() {
_controller = AnimationController(vsync: this,duration: Duration(milliseconds: 400));
super.initState();
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onTapUp: (_) {
setState(() {
myColor = Colors.blue;
});
},
onTapDown: (_) {
setState(() {
myColor = Colors.red;
});
},
child: AnimatedBuilder(animation: _controller,
builder: (context, child) => Container(
height: 200,
width: 200,
color : myColor,
)),
);
}
}
You can change the duration in the animationController if it's too slow.
Upvotes: 1
Reputation: 963
you was doing it right using GestureDetector
but you used the wrong methods, the one you have used are onLongPressStart
and onLongPressEnd
like the example below:
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
bool _changeColor = false;
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
debugShowCheckedModeBanner: false,
home: GestureDetector(
onLongPressStart: (_) => setState(() => _changeColor = !_changeColor),
onLongPressEnd: (_) => setState(() => _changeColor = !_changeColor),
child: Container(
color: _changeColor ? Colors.red : Colors.yellow,
child: Text('Change color'),
),
),
);
}
}
another way of doing it is by using MaterialStateColor
class as suggested by @pskink
class MyApp extends StatelessWidget {
Color getTextColor(Set<MaterialState> states) {
const Set<MaterialState> interactiveStates = <MaterialState>{
MaterialState.pressed,
MaterialState.hovered,
MaterialState.focused,
};
if (states.any(interactiveStates.contains)) {
// the color to return when button is in pressed, hovered, focused state
return Colors.red;
}
// the color to return when button is in it's normal/unfocused state
return Colors.yellow;
}
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: FlatButton(
child: Text('FlatButton'),
onPressed: () {},
textColor: MaterialStateColor.resolveWith(getTextColor),
),
);
}
}
Upvotes: 1