Saya sampai pada titik penerimaan bahwa inilah cara kerja Flutter, tetapi berharap seseorang dapat menjelaskan mengapa tombol tab keyboard fisik membuat satu spasi di TextFormField saat menavigasi ke bidang formulir berikutnya? Saya telah menggunakan RawKeyboardInput untuk menetapkan tab untuk mengalihkan fokus (yang dilakukannya), tetapi masih menciptakan satu ruang di bidang formulir.

enter image description here

Memiliki ruang tunggal ini dapat menyebabkan sejumlah masalah dalam hal penyimpanan data, jadi saya lebih memilih untuk dapat memperbaikinya saat ini daripada melakukan "string.strip()" nanti.

3
Michael Tolsma 13 Maret 2020, 16:53

2 jawaban

Jawaban Terbaik

Saya memiliki masalah yang sama, saat menguji formulir di emulator Android, dan menggunakan TAB untuk pindah ke TextFormField berikutnya.

Solusi saya adalah membungkus TextFormField dalam RawKeyboardListener.

Kode di bawah ini memiliki semua yang Anda butuhkan, Anda dapat mengabaikan hal-hal terkait "LoginStore" karena saya menggunakan manajer negara MobX.

Sampel:

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

class LoginScreen extends StatefulWidget {
  @override
  _LoginScreenState createState() => _LoginScreenState();
}

class _LoginScreenState extends State<LoginScreen> {

  TextEditingController _userNameController = TextEditingController();
  TextEditingController _passwordController = TextEditingController();

  FocusNode _usernameFocusNode;
  FocusNode _passwordKeyboardFocusNode;
  FocusNode _passwordFocusNode;

  LoginStore _loginStore;

  @override
  void initState() {
    super.initState();
    _passwordFocusNode = FocusNode();
    _passwordKeyboardFocusNode = FocusNode();
    _usernameFocusNode = FocusNode();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      primary: true,
      body: Material(
        child: Stack(
          children: <Widget>[
            userNameTextField(),
            SizedBox(height: 12.0),
            passwordTextField(),
            SizedBox(height: 12.0),
            loginButton()
          ]
        )
      )
    );
  }

  Widget userNameTextField() {
    //mobx observer omitted
    return RawKeyboardListener(
      focusNode: _usernameFocusNode,
      child: TextFormField(
        decoration: InputDecoration(
          hintText: "username",
          errorText: _loginStore.formErrorStore.username
        ),
        controller: _userNameController,
        onChanged: (dynamic value) {
          _loginStore.setUserName(_userNameController.text);
        },
        onFieldSubmitted: (dynamic value) {
          FocusScope.of(context).requestFocus(_passwordFocusNode);
        }
      ),
      onKey: (RawKeyEvent event) {
        if (event.isKeyPressed(LogicalKeyboardKey.tab)) {
          var currentText = _userNameController.text;
          var textWithoutTab = currentText.replaceAll("\t", "");
          //update the controller and the store
          _userNameController.text = textWithoutTab;
          _loginStore.setUserName(_userNameController.text);
          //move the focus to the password form
          FocusScope.of(context).requestFocus(_passwordFocusNode);
        }
      }
    );
  }

  Widget passwordTextField() {
    //mobx observer omitted
    return RawKeyboardListener(
      focusNode: _passwordKeyboardFocusNode,
      child: TextFormField(
        decoration: InputDecoration(
          hintText: "password",
          errorText: _loginStore.formErrorStore.password
        ),
        controller: _passwordController,
        onChanged: (dynamic value) {
          _loginStore.setPassword(_passwordController.text);
        }
      ),
      onKey: (RawKeyEvent event) {
        if (event.isKeyPressed(LogicalKeyboardKey.tab)) {
          var currentText = _passwordController.text;
          var textWithoutTab = currentText.replaceAll("\t", "");
          //update the controller and the store
          _passwordController.text = textWithoutTab;
          _loginStore.setPassword(_passwordController.text);
        }
      }
    );
  }

  Widget loginButton() {
    //add a login button as you want ....
  }

  @override
  void dispose() {
    // Clean up the controller when the Widget is removed from the Widget tree
    _userNameController.dispose();
    _passwordController.dispose();
    _passwordKeyboardFocusNode.dispose();
    _passwordFocusNode.dispose();
    _usernameFocusNode.dispose();
    super.dispose();
  }

}

Ingat bahwa menyetel pengontrol teks dengan nilai khusus seperti ini _passwordController.text = textWithoutTab;, tidak memicu panggilan balik onChanged, Anda harus menjaga status tetap sinkron dengan teks yang diperbarui jika Anda melakukan validasi formulir, itu sebabnya saya harus untuk melakukan panggilan lain ke _loginStore.setPassword(_passwordController.text);

4
MatPag 8 Mei 2020, 14:47

Saya menggunakan fungsi trim() dalam contoh TextEditingController() untuk menghapus semua ruang.

final _controllerEmail = TextEditingController();

user.email = _controllerEmail.text.trim();

Untuk referensi lebih lanjut fungsi trim() https://api .dart.dev/stable/2.10.4/dart-core/String/trim.html

0
xciencia 11 Januari 2021, 16:53