image


В версии Dart 2.7 нам представили расширения, позволяющие разработчикам добавлять новые функциональные возможности в уже существующие типы. Расширения могут быть отличным помощником не только, когда мы пишем бизнес-логику, но и когда у нас есть другие задачи! Примером такой задачи может служить работа с виджетами.


Исходя из своего опыта разработки под iOS, вдохновившись ViewModifier из SwiftUI, я захотел разобраться в том, как использовать Dart расширения аналогичным образом, чтобы уменьшить визуальный беспорядок, который получается при большой вложенности дерева виджетов.


Давайте рассмотрим пример!


Вариант с вложенными виджетам


Ниже представлен MyWidget виджет c текстом внутри Padding (из стандартного примера с dartpad.dev).


class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return
      Padding(
        padding: const EdgeInsets.all(16),
        child: Text('Hello, World!', style: Theme.of(context).textTheme.headline4)
      );
  }
}

Теперь давайте разберёмся, как мы можем сделать то же самое с помощью Dart расширений.


Вариант с раширениями


Создаем расширение для класса Widget c методом padding. При вызове данного метода объект будет обернут в Padding:


extension WidgetModifier on Widget {
  Widget padding([EdgeInsetsGeometry value = const EdgeInsets.all(16)]) {
    return Padding(
      padding: value,
      child: this,
    );
  }
}

С новым расширением мы можем обновить MyWidget следующим образом:


class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Text('Hello, World!', style: Theme.of(context).textTheme.headline4)
            .padding();
  }
}

Пусть пример совсем не большой, но я надеюсь, что вы уловили суть! Мы используем метод расширения в качестве синтаксического сахара для компоновки, вместо того, чтобы вкладывать виджеты друг в друга.


Точно так же мы можем добавить в наше расширение еще функции и с их помощью создать более сложные пользовательские интерфейсы:


extension WidgetModifier on Widget {

  // ...

  Widget background(Color color) { // заливка
    return DecoratedBox(
      decoration: BoxDecoration(
        color: color,
      ),
      child: this,
    );
  }

  Widget cornerRadius(BorderRadiusGeometry radius) { // закругление углов
    return ClipRRect(
      borderRadius: radius,
      child: this,
    );
  }

  Widget align([AlignmentGeometry alignment = Alignment.center]) { // выравнивание
    return Align(
      alignment: alignment,
      child: this,
    );
  }
}

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Text('Hello, World!', style: Theme.of(context).textTheme.headline4)
            .padding()
            .background(Colors.lightBlue)
            .cornerRadius(BorderRadius.all(Radius.circular(8.0)))
            .padding(EdgeInsets.symmetric(horizontal: 8, vertical: 16))
            .background(Colors.purple);
  }
}


Посмотреть на dartpad.dev

Разве это не прекрасно? Теперь у нас есть чистый и элегантный виджет, который мы можем легко понять! Представьте себе, сколько уровней вложенных виджетов вам придется использовать, чтобы воссоздать это представление без расширений.


Заключение


В этой статье мы рассмотрели альтернативный подход к формированию дерева виджетов во Flutter проекте, применив концепцию, аналогичную ViewModifier из SwiftUI. При таком подходе мы можем упрощать деревья виджетов, уменьшая их вложенность. И я продемонстрировал лишь несколько примеров таких расширений, но по такому же принципу можно создать много новых для других случаев, где они будут так же полезны.


Спасибо за внимание! Надеюсь, что вы найдете этот пост полезным. Если у вас есть какие-либо вопросы или комментарии по поводу данного материала, не стесняйтесь обращаться ко мне в Twitter!


До следующего раза!