DogSaysWoof
DogSaysWoof

Reputation: 47

How can I make my GestureDetector clickable when it's the trailing of a ListTile?

I have a ListView with ListTile's and I have my IconToggle which has a GestureDetector in the trailing of my ListTile. But when I try to click the icon I click on the list? Why is this? I want to be able to click my toggle and have it switching the icon to the active icon.

List

return ListTile
(
  title: Text(
    arguments.groups[index],
    style: Theme.of(context).textTheme.body1,
  ),
  onTap: () => onGroupTap(arguments.groups[index]),
  trailing: IconToggle(
    isActive: false,
    active: Icon
    (
      Icons.notifications,
      color: Theme.of(context).iconTheme.color,
    ),
    deactive: Icon
    (
      Icons.notifications_off,
      color: Theme.of(context).accentColor,
    ),
  ),
);

Icon Toggle

import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';

class IconToggle extends StatefulWidget {

  bool isActive = true;
  final Icon active;
  final Icon deactive;
  final Function(bool) onChanged;

  IconToggle({this.isActive,  @required this.active,  @required this.deactive, this.onChanged}) 
  : assert(isActive != null), 
  assert(active != null), 
  assert(deactive != null);

  @override
  _IconToggleState createState() => _IconToggleState();
}

class _IconToggleState extends State<IconToggle> {

  _showIcon()
  {
    return widget.isActive ? widget.active : widget.deactive;
  }

  _toggle()
  {
    setState(() {
      widget.isActive = !widget.isActive;
      if(widget.onChanged != null)
        widget.onChanged(widget.isActive);
    });
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector
    ( 
      child: _showIcon(),
      onTap: _toggle(),
    );
  }
}

Upvotes: 0

Views: 1813

Answers (1)

chunhunghan
chunhunghan

Reputation: 54377

You can copy paste run full code below
Step 1: Move GestureDetector to trailing
Step 2: Put toggle() logic to didUpdateWidget
Step 3: Use local bool isActive not widget.isActive

trailing: GestureDetector(
                    onTap: () {
                      print("trailing ontap");
                      setState(() {

                      });
                    },
                    child: IconToggle(

...
@override
  void didUpdateWidget(IconToggle oldWidget) {
    super.didUpdateWidget(oldWidget);
    print("didUpdateWidget ${isActive}");
    isActive = !isActive;
    if (widget.onChanged != null) widget.onChanged(isActive);
  }

working demo

enter image description here

full code

import 'package:flutter/material.dart';

class IconToggle extends StatefulWidget {
  bool isActive = true;
  final Icon active;
  final Icon deactive;
  final Function(bool) onChanged;

  IconToggle(
      {this.isActive,
      @required this.active,
      @required this.deactive,
      this.onChanged})
      : assert(isActive != null),
        assert(active != null),
        assert(deactive != null);

  @override
  _IconToggleState createState() => _IconToggleState();
}

class _IconToggleState extends State<IconToggle> {
  bool isActive = false;

  _showIcon() {
    print("showIcon");
    return isActive ? widget.active : widget.deactive;
  }

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    isActive = widget.isActive;
  }
  /*_toggle() {
    print("toggle");
    setState(() {
      widget.isActive = !widget.isActive;
      if (widget.onChanged != null) widget.onChanged(widget.isActive);
    });
  }*/

  @override
  void didUpdateWidget(IconToggle oldWidget) {
    super.didUpdateWidget(oldWidget);
    print("didUpdateWidget ${isActive}");
    isActive = !isActive;
    if (widget.onChanged != null) widget.onChanged(isActive);
  }

  @override
  Widget build(BuildContext context) {
    return _showIcon();
  }
}

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            ListTile(
              title: Text(
                "arguments.groups[index]",
                style: Theme.of(context).textTheme.body1,
              ),
              onTap: () => print("onGroupTap(arguments.groups[index])"),
              trailing: GestureDetector(
                onTap: () {
                  print("trailing ontap");
                  setState(() {

                  });
                },
                child: IconToggle(
                  isActive: false,
                  onChanged: (isActive) {
                    print("execute onChange $isActive");
                  },
                  active: Icon(
                    Icons.notifications,
                    color: Theme.of(context).iconTheme.color,
                  ),
                  deactive: Icon(
                    Icons.notifications_off,
                    color: Theme.of(context).accentColor,
                  ),
                ),
              ),
            ),
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

Upvotes: 2

Related Questions