如何在 flutter 中的两个屏幕之间导航并显示键盘?

How to navigate between two screens in flutter and show keyboard?

我有一些下一个(简化的)小部件树结构:

- home (stack of widgets)
  - page container
  - editText field

如您所见,编辑文本将始终位于页面顶部,我将与 Navigator.of(context) 事务交换。

问题:当我聚焦editText时键盘出现。当用户开始输入时,有时我需要在 page container 内推送另一个屏幕。当我使用 Navigator.of() 时 - editText 没有焦点并且键盘按下。

需要什么: 我需要以某种方式在 page container 中使用 Navigator 进行转换 (push/pop/replace) 并保持键盘仍然向上 (保持 editText 的焦点)。

你知道怎么做吗?

您的用例看起来很奇怪,但我想您有充分的理由遵循此设置。

无论如何,问题是当调用 Navigator.push 时,TextField 没有聚焦。这不是一个错误,而是一个预期的功能(我认为)是为了防止键盘跟随您进入下一个没有 TextField 的屏幕。但是我知道这对您的用例来说是个问题。

我的解决方案(不是我承认的最漂亮的,但我唯一能做的)是手动强制焦点回到 TextField。您需要两个组件:

  • 一个 FocusNode 关联到您的 TextField 以收听检查您的 TextField 是否从专注变为不专注。如果设置了focusOnNextUnfocus,在unfocus
  • 后应该重新请求focus
  • focusOnNextUnfocus 在推送之前设置为 true 的布尔值,一旦再次请求焦点,它将设置为 false。

这是对您提供的代码的改编:

import 'package:flutter/material.dart';

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, required this.title}) : super(key: key);

  final String title;

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

class _MyHomePageState extends State<MyHomePage> {
  /// Handles the focus state of our text field
  final focusNode = FocusNode();
  
  /// A bool to keep track on whether we should refocus after
  /// unfocus. This will be set to `true` before pushing
  var focusOnNextUnfocus = false;
  
  int _counter = 0;

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

  @override
  void initState() {
    focusNode.addListener(() {
      // If we no longer have the focus and should refocus, we refocus
      if (!focusNode.hasFocus && focusOnNextUnfocus) {
        focusNode.requestFocus();
        focusOnNextUnfocus = false; // Reset to false once it has been processed
      }
    });
    super.initState();
  }
  
  @override
  void dispose() {
    focusNode.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    late BuildContext anotherContext;

    final edit = TextField(
      focusNode: focusNode,
      onChanged: (String value) async {
        if (value.length > 4) {
          // Pop does not unfocus so no worries here
          Navigator.pop(anotherContext);
        } else if (value.length > 3) {
          // Push DOES unfocus, so we need to set focusOnNextUnfocus to true
          focusOnNextUnfocus = true;
          Navigator.of(anotherContext).push(
            MaterialPageRoute(builder: (_) {
              return Builder(builder: (context) {
                return Another();
              });
            }),
          );
        }
      },
    );

    final scaffold = MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
        ),
        body: Builder(
          builder: (context) {
            anotherContext = context;
            return Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  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),
        ),
      ),
    );
    return Scaffold(
      body: Stack(
        children: [
          Positioned(child: scaffold),
          Align(
            alignment: Alignment.center,
            child: Padding(
              padding: EdgeInsets.symmetric(horizontal: 16),
              child: edit,
            ),
          ),
        ],
      ),
    );
  }
}

class Another extends StatelessWidget {
  const Another({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.red,
    );
  }
}