Skip to content

[feature] add onFocusChange in ListTile  #99608

@iMro0t

Description

@iMro0t

Use case

On desktop (or in AndroidTV) when we have ListTile in ListView and the user navigates the items using Arrow Down or Arrow Up buttons it would be nice to have onFocusChange callback so we can change the state based on focus.

Currently the same can be achieved by adding a listener to focusNode but then we had to manage it and dispose it which is not really nice for 100 list items.

Also, it's so common for (almost 9 out of 10) flutter apps having ListTile in ListView. So this will be so convenient.

Proposal

Current Implementation

class MyWidget extends StatefulWidget {
  @override
  State<MyWidget> createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  final List<FocusNode> _nodes = [];
  final StreamController<int> _activeIndex = StreamController();

  
  @override
  void dispose() {
    for (var n in _nodes) {
      n.dispose();
    }
    super.dispose();
  }
   
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        ListView.builder(
          itemCount: 100,
          itemBuilder: (context, index) {
            var _focusNode = FocusNode();
            _focusNode.addListener(() {
              if (_focusNode.hasFocus) {
                _activeIndex.sink.add(index);
              }
            });
            _nodes.add(_focusNode);
            return ListTile(
               focusNode: _focusNode,
               title: Text("Item $index"),
            );
          },
        ),
        // Do stuff with focused item
      ],
    );
  }
}

Proposal

class MyWidget extends StatefulWidget {
  @override
  State<MyWidget> createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  final StreamController<int> _activeIndex = StreamController();

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        ListView.builder(
          itemCount: 100,
          itemBuilder: (context, index) {
            return ListTile(
               onFocusChange: (hasFocus) => hasFocus ? _activeIndex.sink.add(index) : null,
               title: Text("Item $index"),
            );
          },
        ),
        // Do stuff with focused item
      ],
    );
  }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    c: new featureNothing broken; request for a new capabilityf: focusFocus traversal, gaining or losing focusf: material designflutter/packages/flutter/material repository.frameworkflutter/packages/flutter repository. See also f: labels.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions