簡體   English   中英

如何將焦點轉移到 Flutter 中的下一個自定義文本字段?

[英]How to shift focus to next custom textfield in Flutter?

根據: 如何將焦點轉移到 flutter 中的下一個文本字段? ,我使用FocusScope.of(context).nextFocus()來轉移焦點。 但是,當您使用可重用的文本字段 class 時,這不起作用。 僅當您在Column中直接使用TextField class 時才有效。

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final focus = FocusScope.of(context);
    return MaterialApp(
      title: 'Flutter Demo',
      home: Scaffold(
        body: SafeArea(
          child: Column(
            children: <Widget>[
              CustomTextField(
                textInputAction: TextInputAction.next,
                onEditingComplete: () => focus.nextFocus(),
              ),
              const SizedBox(height: 10),
              CustomTextField(
                textInputAction: TextInputAction.done,
                onEditingComplete: () => focus.unfocus(),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

class CustomTextField extends StatelessWidget {
  final TextInputAction textInputAction;
  final VoidCallback onEditingComplete;

  const CustomTextField({
    this.textInputAction = TextInputAction.done,
    this.onEditingComplete = _onEditingComplete,
  });

  static _onEditingComplete() {}

  @override
  Widget build(BuildContext context) {
    return TextField(
      textInputAction: textInputAction,
      onEditingComplete: onEditingComplete,
    );
  }
}

在這段代碼中,如果我在鍵盤上單擊下一步,它不會將焦點轉移到下一個文本字段。 請幫我解決一下這個。

那是因為context沒有任何可以抓住焦點的東西。 用以下代碼替換您的代碼:

void main() => runApp(MaterialApp(home: MyApp()));

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final focus = FocusScope.of(context);
    return Scaffold(
      appBar: AppBar(),
      body: Column(
        children: <Widget>[
          CustomTextField(
            textInputAction: TextInputAction.next,
            onEditingComplete: () => focus.nextFocus(),
          ),
          SizedBox(height: 10),
          CustomTextField(
            textInputAction: TextInputAction.done,
            onEditingComplete: () => focus.unfocus(),
          ),
        ],
      ),
    );
  }
}

您需要使用表單鍵將字段包裝在表單小部件中,並使用 TextFormField 而不是 textField 小部件。 將操作設置為 TextInputAction.next,它應該可以工作。 您還可以使用 TextInput.done 來觸發驗證。

這是一個完整的工作示例:

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

class LogInPage extends StatefulWidget {
  LogInPage({Key key}) : super(key: key);

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

class _LogInPageState extends State<LogInPage> {
  final _formKey = new GlobalKey<FormState>();

  bool isLoading = false;

  String firstName;
  String lastName;
  String password;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      backgroundColor: Colors.black,
      body: body(),
    );
  }

  Widget body() {
    return Form(
      key: _formKey,
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          showInput(
              firstName,
              TextInputType.name,
              Icons.drive_file_rename_outline,
              "FirstName",
              TextInputAction.next,
              onSaved: (value) => firstName = value.trim()),
          showInput(lastName, TextInputType.name,
              Icons.drive_file_rename_outline, "LastName", TextInputAction.next,
              onSaved: (value) => lastName = value.trim()),
          showInput(null, TextInputType.text, Icons.drive_file_rename_outline,
              "Password", TextInputAction.done,
              isPassword: true, onSaved: (value) => password = value),
          Padding(
            padding: EdgeInsets.symmetric(vertical: 10),
          ),
          showSaveButton(),
        ],
      ),
    );
  }

  Widget showInput(String initialValue, TextInputType textInputType,
      IconData icon, String label, TextInputAction textInputAction,
      {@required Function onSaved, bool isPassword = false}) {
    return Padding(
      padding: EdgeInsets.fromLTRB(16.0, 20.0, 16.0, 0.0),
      child: new TextFormField(
        style: TextStyle(color: Theme.of(context).primaryColorLight),
        maxLines: 1,
        initialValue: initialValue,
        keyboardType: textInputType,
        textInputAction: textInputAction,
        autofocus: false,
        obscureText: isPassword,
        enableSuggestions: !isPassword,
        autocorrect: !isPassword,
        decoration: new InputDecoration(
            fillColor: Theme.of(context).primaryColor,
            hintText: label,
            hintStyle: TextStyle(color: Theme.of(context).primaryColorDark),
            filled: true,
            contentPadding: new EdgeInsets.fromLTRB(10.0, 10.0, 10.0, 10.0),
            border: new OutlineInputBorder(
              borderRadius: new BorderRadius.circular(12.0),
            ),
            icon: new Icon(
              icon,
              color: Theme.of(context).primaryColorLight,
            )),
        validator: (value) {
          return value.isEmpty && !isPassword
              ? "You didn't filled this field."
              : null;
        },
        onSaved: onSaved,
        onFieldSubmitted:
            textInputAction == TextInputAction.done ? (value) => save() : null,
      ),
    );
  }

  Widget showSaveButton() {
    return RaisedButton(
      shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.all(Radius.circular(100))),
      color: Theme.of(context).primaryColor,
      padding: EdgeInsets.symmetric(vertical: 12, horizontal: 25),
      child: isLoading
          ? SizedBox(height: 17, width: 17, child: CircularProgressIndicator())
          : Text(
              "Sauvegarder",
              style: TextStyle(color: Theme.of(context).primaryColorLight),
            ),
      onPressed: save,
    );
  }

  void save() async {
    if (_formKey.currentState.validate()) {
      _formKey.currentState.save();
      //TODO
    }
  }
}
FocusNode textSecondFocusNode = new FocusNode();

TextFormField textFirst = new TextFormField(
  onFieldSubmitted: (String value) {
    FocusScope.of(context).requestFocus(textSecondFocusNode);
  },
);

TextFormField textSecond = new TextFormField(
  focusNode: textSecondFocusNode,
);

// render textFirst and textSecond where you want

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM