В предыдущей статье мы подключили Flutter SDK и создали hello world приложение. Сейчас создадим простое приложение где реализуем экран авторизации, простой механизм валидации логина и пароля и если валидация пройдёт успешно, то осуществить переход на следующий экран:

animation_flutter

Создадим новый проект как было описано в предыдущей статье. Заменим содержимое файл \lib\main.dart на представленный ниже код:

  import 'package:flutter/material.dart';
  
  void main() => runApp(
        new MyApp(),
      );
  
  class MyApp extends StatelessWidget {
    @override
    Widget build(BuildContext context) {
      return new MaterialApp(home: new Scaffold());
    }
  }

Как и в Java у Dart есть точка входа с которой начинается запуск программы - это метод main(). Нотация => предназначена для более наглядного представления вызова функций. Функция runApp предназначена для создания и вывода на экран виджета, который мы создаём и передаём в качестве параметра.

Класс MyApp наследуется от StatelessWidget тем самым получает свойства неизменяемого виджета. При наследовании нужно переопределить метод создания виджета build(BuildContext context). MaterialApp - создаёт приложение которое, реализует принципы material design. В качестве маршрута по умолчанию в параметре home передадим класс Scaffold(), который реализует основную структура макета.

Если запустить этот код, то на экране будет отображён пустой белый экран с пометкой debug в правом верхнем углу:

Теперь разместим визуальные компоненты на экране. Как мы помним из первой стать во flutter все визуальные компоненты являются виджетами. Благодаря взаимовложенности виджетов друг в друга и строиться графический интерфейс.

Сейчас у нас есть пустой экран, создадим два поля для ввода текста и кнопку login.

class MyApp extends StatelessWidget {
  final _sizeTextBlack = const TextStyle(fontSize: 20.0, color: Colors.black);
  final _sizeTextWhite = const TextStyle(fontSize: 20.0, color: Colors.white);

  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      home: new Scaffold(
        body: new Center(
            child: new Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                new Container(
                  child: new TextFormField(
                    decoration: new InputDecoration(labelText: "Email"),
                    keyboardType: TextInputType.emailAddress,
                    style: _sizeTextBlack,
                  ),
                  width: 400.0,
                ),
                new Container(
                  child: new TextFormField(
                    decoration: new InputDecoration(labelText: "Password"),
                    obscureText: true,
                    style: _sizeTextBlack,
                  ),
                  width: 400.0,
                  padding: new EdgeInsets.only(top: 10.0),
                ),
                new Padding(
                  padding: new EdgeInsets.only(top: 25.0),
                  child: new MaterialButton(
                    color: Theme
                        .of(context)
                        .accentColor,
                    height: 50.0,
                    minWidth: 150.0,
                    child: new Text(
                      "LOGIN",
                      style: _sizeTextWhite,
                    ),
                  ),
                )
              ],
            )
        ),
      ),
    );
  }
}

Для того что бы выронить все элементы по центру экрана воспользуемся классом Center (строка 9). Для расположения все элементы в один столбец необходимо использовать класс Column в котором для выравнивания дочерних элементов по центру задаём значение параметра mainAxisAlignment: MainAxisAlignment.center (строки 10-11).

В класс Column можно передать массив виджетов которые будут отображаться внутри него в вертикальном порядке друг под другом (строка 12). Каждое полу ввода нужно ограничить по ширине, поэтому необходимо “завернуть” всё это в ещё один класс Container. У которого уже можно задать нужный параметр width (строка 19). В качестве параметров стиля для текста создадим две переменные _sizeTextBlack и _sizeTextWhite (строки 2-3).

Для поля ввода Email зададим параметр типа клавиатуры TextInputType.emailAddress, а для поля пароля выставим obscureText в true (строка 16 и 24).

Для отображение кнопки нам понадобиться отступ который мы сможем задать через класс Padding (строка 30).

В итоге у нас получиться следующий результат:

Далее реализуем простую логику валидации почты и пароля. Для хранения и передачи данных создадим в классе MyApp две переменные _email и _password:

class MyApp extends StatelessWidget {
    String _email;
    String _password;
    ...

У виджета TextFormField есть метод onSaved который возвращает значение поля ввода при изменениях. Это значение сохраняем в переменные _email и _password соответственно. Так же есть функция validator в которой можно реализовать логику отображения подсказки в случае если валидация не пройдена.

child: new TextFormField(
  ...
  onSaved: (val) => _email = val,
  validator: (val) =>
      !val.contains("@") ? 'Not a valid email.' : null,
      ...
),

Обработаем событие нажатие на кнопку. В виджет MaterialButton есть функция onPressed который вызывается после нажатие кнопки. Для лаконичности кода вынесем обработку нажатия в отдельный метод submit.

child: new MaterialButton(
  onPressed: submit,
  ...
),

Для того что бы провалидировать сразу все поля нужно создать дополнительный виджет Form. У него есть тип key, который создаёт контейнер для полей формы. Его будем хранить в поле formKey.

class MyApp extends StatelessWidget {
  ...
  final formKey = new GlobalKey<FormState>();
  
  ...
  body: new Center(
          child: new Form(
              key: formKey,
              child: new Column(
  ...
}

Реализуем метод submit(). В нём выполняется получение полей ввода и вызова метода validate():

void submit() {
    final form = formKey.currentState;
    if (form.validate()) {
      form.save();
      performLogin();
    }
  }

  void performLogin() {
    hideKeyboard();
    Navigator.push(
        _context,
        new MaterialPageRoute(
            builder: (context) => new SecondScreen(_email, _password)));
  }

  void hideKeyboard() {
    SystemChannels.textInput.invokeMethod('TextInput.hide');
  }

После успешной валидации скрываем клавиатуру и открываем экран в который передадим значение логина и пароля:

Весь код проекта можно посмотреть по ссылке.