【问题标题】:How to change focus to a specific field in a ListView with multiple Text Fields如何将焦点更改为具有多个文本字段的 ListView 中的特定字段
【发布时间】:2021-01-27 09:01:56
【问题描述】:

我有一个 ListView,其中包含一个带有 2 个文本字段的卡片。如果在该行的第二个 TextField 上进行了输入,那么我希望焦点转到下一个 ListView 行上的第二个 TextField(基本上保持在显示的同一“列”中)。目前,如果我使用 TextInputAction.next,焦点将转到下一个 ListView 行的第一个字段。我尝试将 FocusNode 添加到 ListView,但无法将其“链接”到 ListView 中的特定项目。 FocusNode 是正确使用的方法,还是有一种简单的方法可以在执行下一个操作时跳过第一个字段。此外,如果下一行已经包含第二个 TextField 中的值,我希望焦点转到同一“列”中的下一个空 ListView。

这里是精简的sn-p代码:

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

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyHomePage(title: 'Next ListView Item'),
    );
  }
}

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

  final String title;

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

class _MyHomePageState extends State<MyHomePage> {
  //this could include any number of players 
  List<String> players = [
    'Player 1',
    'Player 2',
    'Player 3',
    'Player 4',
    'Player 5',
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
        ),
        body: ListView.builder(
          itemCount: players.length,
          itemBuilder: (context, index) {
            return PlayerCard(
              player: players[index],
            );
          },
        ));
  }
}

class PlayerCard extends StatefulWidget {
  final String player;

  PlayerCard({this.player});

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

class _PlayerCardState extends State<PlayerCard> {
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Card(
        child: Row(children: [
          Expanded(flex: 7, child: Text('${widget.player}')),
          Expanded(
            child: TextField(
              inputFormatters: [
                LengthLimitingTextInputFormatter(2),
                FilteringTextInputFormatter.digitsOnly,
              ],
              textInputAction: TextInputAction.next,
            ),
          ),
          Spacer(),
          Expanded(
              child: TextField(
            inputFormatters: [
              LengthLimitingTextInputFormatter(1),
              FilteringTextInputFormatter.digitsOnly,
            ],
            onChanged: (value) {
              FocusManager.instance.primaryFocus.nextFocus();
            },
            textInputAction: TextInputAction.next,
          )),
        ]),
      ),
    );
  }
}

Perhaps this screen shot will give a better example of what I'm trying to accomplish

【问题讨论】:

    标签: flutter listview


    【解决方案1】:

    我能够调整我找到的另一个答案并在此处应用它。您需要不断移动焦点,直到找到空白文本字段。

    引用:我调整的另一个答案在这里:https://stackoverflow.com/a/63005046/3705348

    class _PlayerCardState extends State<PlayerCard> {
      @override
      Widget build(BuildContext context) {
        return Container(
          child: Card(
            child: Row(children: [
              Expanded(flex: 7, child: Text('${widget.player}')),
              Expanded(
                child: TextField(
                  inputFormatters: [
                    LengthLimitingTextInputFormatter(2),
                    FilteringTextInputFormatter.digitsOnly,
                  ],
                  textInputAction: TextInputAction.next,
                ),
              ),
              Spacer(),
              Expanded(
                  child: TextField(
                inputFormatters: [
                  LengthLimitingTextInputFormatter(1),
                  FilteringTextInputFormatter.digitsOnly,
                ],
                onChanged: (value) {
                  // Call extension method here instead of just moving focus
                  context.nextBlankTextFocus();
                },
                textInputAction: TextInputAction.next,
              )),
            ]),
          ),
        );
      }
    }
    
    extension Utility on BuildContext {
      void nextBlankTextFocus() {
        var startingTextField;
        do {
          // Set starting text field so we can check if we've come back to where we started
          if (startingTextField == null) {
            startingTextField = FocusScope.of(this).focusedChild.context.widget;
          } else if (startingTextField ==
              FocusScope.of(this).focusedChild.context.widget) {
            // Back to where we started - stop as there are no more blank text fields
            break;
          }
    
          FocusScope.of(this).nextFocus();
        } while (FocusScope.of(this).focusedChild.context.widget is EditableText &&
            (FocusScope.of(this).focusedChild.context.widget as EditableText)
                    .controller
                    .text
                    .trim()
                    .length !=
                0);
      }
    }
    

    【讨论】:

    • 干得好!这完美无缺。感谢您的及时回复。我在这里有点新,并且排名“低”,这不允许我将答案标记为有用,但请放心。
    • @ERun - 你在这里问的第一个问题做得很好。感谢您提供易于运行的代码,以便社区可以更轻松地帮助您。
    猜你喜欢
    • 2018-08-30
    • 2020-07-03
    • 1970-01-01
    • 1970-01-01
    • 2019-05-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多