Основы создания приложений на Flutter

Основы создания приложений на Flutter

Пример простого приложения во флаттер который просто выводит введенные цифры.

Во Flutter обычно всё приложение состоит из Widget'ов, в которых сгруппированы другие виджеты. Есть два типа виджетов с состоянием и без.

Пример StatelessWidget

class UserBar extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Text('Привет, Александр!');
  }
}

Данный виджет просто выведет на экран Привет, Александр!

Функция build будет вызвана при перерисовке верхнего элемента. Чтобы не тратить лишние ресурсы нужно разбивать приложение так, чтобы не перерисовывать элементы которые этого не требуют.

Ниже показан чуть более функциональный вариант, для демонстрации основ.

class UserBar extends StatelessWidget {
  final String role;
  final String userName;
  final String _text = 'Привет';

  UserBar(this.role, {Key key, this.userName}): super(key: key);

  String get currentUser => userName ?? 'без имени';

  @override
  Widget build(BuildContext context) {
    return _bar();
  }

  Widget _bar() => Padding(
    padding: const EdgeInsets.all(20.0),
    child: Text("$_text, $currentUser");
); }

Все параметры StatelessWidget должны быть объявлены как final, то есть мы не можем их менять. Приватные члены класса начинаются со знака подчеркивания _text.

Виджеты имеют параметр Key, это ключ, нужен для правильной перерисовки дерева виджетов. На практике я использую их достаточно редко и заслуживает отдельной статьи для углубления. В данном примере я объявил его в конструкторе, чтобы показать как передать этот параметр в родителя.

Запись типа this.userName

UserBar({this.userName})

в конструкторе, означает что вызвав конструктор UserBar(userName: 'Александр'), переменной userName будет присвоено то, что мы передали.

Конструктор приведенный ниже

UserBar(this.role, {Key key, this.userName})

Принимает первым параметром неименованный аргумент role, который передается в порядке очереди. И два именованных аргумента.

Так как userName и role у нас объявлены как final, мы должны инициализировать переменные либо сразу при объявлении либо в конструкторе. Если не передать какой либо аргумент, значение будет null.

В Dart есть гетеры и сеттеры. Пример getter:

String get currentUser => userName ?? 'без имени';

Оператор ?? смотрит значение слева, и если оно не null то возвращает его, если userName == null то вернет то, что справа. Это аналог userName ? userName : 'без имени'.

Хотя язык Dart и типизированный, вы можете использовать тип dynamic если переменная может принимать данные различных типов. Не обязательно указывать тип возвращаемых данных из функции, вы можете написать просто

  _bar() => Padding(
    padding: const EdgeInsets.all(20.0),
    child: Text(content);
  );

Также вы могли заметить сокращенную запись для функций() => expr вместо () { return expr; }

Виджеты часто имеют параметр child, который принимает другой виджет для отрисовки внутри себя.

class UserBar extends StatelessWidget {
  final Widget child;

  UserBar({this.child});

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(20.0),
      child: child; // тут выводим наш виджет переданный в конструктор
    );
  }
}

Пример StatefulWidget

Если нужно перерисовать виджет, можно использовать StatefulWidget. Данный виджет состоит из двух связанных частей.

class Calc extends StatefulWidget {
  final int initState;

  Calc({Key key, this.initState}): super(key: key);

  @override
  State<StatefulWidget> createState() => CalcState();
}

class CalcState extends State<Calc> {
  int _weight;

  @override
  void initState() {
    super.initState();
    _weight = widget.initState ?? 0;
  }

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(20.0),
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          Text('Введите Ваш вес'),
          TextField(
            onChanged: (value) {
              setState(() {
                _weight = value.isNotEmpty ? int.parse(value) : 0;
              });
            },
          ),
          Visibility(
            visible: _weight > 0,
            child: Text("Ваш вес: $_weight")
          ),
        ],
      ),
    );
  }
}

Функция build перекочевала в наследника State. В состоянии уже разрешено использовать переменные не помеченные как final.

Перед первой отрисовкой виджета вызывается метод initState в котором вы можете инициализировать переменные. К переменным из виджета Calc можно получить доступ через свойство widget. Таким образом мы инициализировали нашу переменную _weight значением переданным в конструктор виджета Calc или 0 если оно не было передано или было передано null.

Если просто менять значение переменной _weight когда виджет уже отрисован, мы не увидим изменений, это связано с тем, что виджет не перерисовывается каждый кадр, и нам нужно сообщить, что мы хотим перерисовку. Для этого служит метод setState() который принимает калбек функцию которая будет вызвана сразу же синхронно и уведомит Flutter, что компонент необходимо перерисовать. На этом пожалуй все.

Небольшая демонстрация создания простого приложения на Flutter

При копировании материалов ссылка на https://terraideas.ru/ обязательна

Комментарии к статье: Основы создания приложений на Flutter

Нет ни одного комментария. Будьте первым!