Gran J
Gran J

Reputation: 61

How to change the color of a widget while it is pressed in flutter?

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

Answers (2)

Poudreuse
Poudreuse

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

hewa jalal
hewa jalal

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

Related Questions