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!


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