Flutter несколько текстовых полей электронной почты

Для обучения я пытаюсь сделать клон Gmail, я борюсь с вводом нескольких электронных писем, который у вас есть, когда вы редактируете новое письмо. Мне нужно уметь слушать либо "ENTER", либо "SPACE", чтобы я мог изменять ввод (после проверки) с помощью "блока" электронной почты, например:

Я думаю, что могу работать с тегом onFieldSubmitted для клавиши "ENTER", но как я могу изменить вводимый текст? Я попытался:

controller.text = Container();

но "текст" принимает только String (что кажется логичным).

Цель состоит в том, чтобы создать точно такой же тип inputField, куда вы помещаете "Теги" в Stackru.

Я также нашел EmailInputElement, но не могу понять, как его правильно использовать, похоже, это не виджет.

Если у кого-то есть идея, это будет очень признательно, спасибо.

2 ответа

Решение

Хитрость здесь в том, чтобы показать желаемый пользовательский интерфейс следующим образом: InputDecoration.collapsed() помогает нам сделать TextField минимальный, вы можете добавить Divider() как последний виджет основного столбца, чтобы изобразить, что все это происходит внутри TextField

Я попытался смоделировать поведение, которое вы пытаетесь реализовать. Я проверяю наличие пробелов в конце строки ввода вTextField с помощью onChange метод и для enter кнопка, которую я использую onEditingCompleteфункция. Я наложил ограничения на ряд писем, чтобы они увеличивались только до определенной ширины области просмотра, вы также можете использовать другой макет.

class Test extends StatefulWidget {
  @override
  _TestState createState() => _TestState();
}

class _TestState extends State<Test> {
  List<String> emails = [];
  TextEditingController _emailController;

  @override
  void initState() {
    super.initState();
    _emailController = TextEditingController();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Container(
            child: Center(
          child: Row(
            children: <Widget>[
              Container(
                constraints: BoxConstraints(maxWidth: 200, minWidth: 0),
                child: SingleChildScrollView(
                  scrollDirection: Axis.horizontal,
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.start,
                    mainAxisSize: MainAxisSize.min,
                    crossAxisAlignment: CrossAxisAlignment.center,
                    children: <Widget>[
                      ...emails
                          .map((email) => Chip(label: Text(email)))
                          .toList(),
                    ],
                  ),
                ),
              ),
              Expanded(
                child: TextField(
                  decoration: InputDecoration.collapsed(hintText: 'EMail'),
                  controller: _emailController,
                  onChanged: (String val) {
                    if (val.endsWith(' '))
                      setState(() {
                        emails.add(_emailController.text);
                        _emailController.text = '';
                      });
                  },
                  onEditingComplete: () {
                    setState(() {
                      emails.add(_emailController.text);
                      _emailController.text = '';
                    });
                  },
                ),
              )
            ],
          ),
        )),
      ),
    );
  }
}

Если кто-то придет сюда для тех же функций, о которых я просил, есть мой шаблон, вы можете вставить его в новый файл и просто позвонить EmailInput()где вам это нужно. Вы просто хотите использоватьsetList атрибут с функцией обновления вашего List<String> чтобы вернуть данные в родительский компонент:) Он также проверяет, является ли введенная строка действительным адресом электронной почты или нет.

Это выглядит примерно так:

import 'package:flutter/material.dart';

class EmailInput extends StatefulWidget {
  final Function setList;
  final String hint;
  final List<String> parentEmails;

  const EmailInput({Key key, this.setList, this.hint, this.parentEmails}) : super(key: key);

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

class _EmailInputState extends State<EmailInput> {
  TextEditingController _emailController;
  String lastValue = '';
  List<String> emails = [];
  FocusNode focus = FocusNode();
  @override
  void initState() {
    super.initState();
    _emailController = TextEditingController();

    focus.addListener(() {
      if (!focus.hasFocus) {
        updateEmails();
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Container(
        child: Center(
      child: Column(
        children: <Widget>[
          Container(
            constraints: BoxConstraints(
              minWidth: 0,
            ),
            child: SingleChildScrollView(
              scrollDirection: Axis.horizontal,
              child: Column(
                children: <Widget>[
                  ...emails
                      .map(
                        (email) => Chip(
                          avatar: CircleAvatar(
                            backgroundColor: Colors.black,
                            child: Text(
                              email.substring(0, 1),
                              style: TextStyle(color: Colors.white),
                            ),
                          ),
                          labelPadding: EdgeInsets.all(4),
                          backgroundColor: Color.fromARGB(255, 39, 182, 192),
                          label: Text(
                            email,
                            style: TextStyle(fontSize: 16, color: Colors.white),
                          ),
                          onDeleted: () => {
                            setState(() {
                              emails.removeWhere((element) => email == element);
                            })
                          },
                        ),
                      )
                      .toList(),
                ],
              ),
            ),
          ),
          TextField(
            keyboardType: TextInputType.emailAddress,
            decoration: InputDecoration.collapsed(hintText: widget.hint),
            controller: _emailController,
            focusNode: focus,
            onChanged: (String val) {
              setState(() {
                if (val != lastValue) {
                  lastValue = val;
                  if (val.endsWith(' ') && validateEmail(val.trim())) {
                    if (!emails.contains(val.trim())) {
                      emails.add(val.trim());
                      widget.setList(emails);
                    }
                    _emailController.clear();
                  } else if (val.endsWith(' ') && !validateEmail(val.trim())) {
                    _emailController.clear();
                  }
                }
              });
            },
            onEditingComplete: () {
              updateEmails();
            },
          )
        ],
      ),
    ));
  }

  updateEmails() {
    setState(() {
      if (validateEmail(_emailController.text)) {
        if (!emails.contains(_emailController.text)) {
          emails.add(_emailController.text.trim());
          widget.setList(emails);
        }
        _emailController.clear();
      } else if (!validateEmail(_emailController.text)) {
        _emailController.clear();
      }
    });
  }

  setEmails(List<String> emails) {
    this.emails = emails;
  }
}

bool validateEmail(String value) {
  Pattern pattern =
      r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$';
  RegExp regex = new RegExp(pattern);
  return regex.hasMatch(value);
}

Другие вопросы по тегам