[Я пиарюсь, Разработка мобильных приложений, Flutter] Storybook + Flutter = storybook_flutter
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Всем привет! В этой статье я буду бессовестно пиарить рассказывать о своей библиотеке для Flutter'а, которая позволяет создавать истории из изолированных виджетов и/или экранов. Что-то типа Storybook из мира React. Собственно, она так и называется: storybook_flutter.Зачем она нужна?Во-первых, быстрее делать UI. Конечно, у Flutter'а и так есть hot reload, но если виджет зарыт где-то в дебрях приложения, то до него еще надо добраться. А если этот виджет показывается только при определенных условиях, то эти условия надо воспроизвести. Кроме того, hot reload работает не во всех случаях. Поэтому удобнее изолировать виджет, вынести его в отдельную историю, и работать с этой историей. При этом вам придется задуматься над тем, как бы убрать лишние зависимости из этого виджета, так что код в итоге будет чище.Во-вторых, демонстрация виджетов/экранов. Например, мы делаем свою дизайн-библиотеку для Flutter'а, и в документацию мы бы хотели встраивать интерактивную песочницу с виджетами, тем более, что Flutter for Web уже в стабильной ветке.В-третьих, в будущем я хочу добавить (мне эту идею подсказали в issues) возможность автоматически генерировать golden tests для виджетов с разными комбинациями параметров.Может, взять что-то готовое?Наверное, можно. Но, во-первых, какого-то явного фаворита в сообществе пока нет. Во-вторых, синдром NIH никто не отменял. В-третьих, я хочу иметь возможность быстро добавлять те фичи, которые нам нужны.Как она выглядит?Как-то так:
Не очень элегантно, но внешний вид пока не в приоритете. Да и дизайнер из меня – так себе. Кроме того, я пока еще экспериментирую с расположением тулбаров, кнопок и менюшек, поэтому полировать дизайн смысла нет.Что она умеет?
- Навигация по историям с разбивкой по категориям.
- Параметры (knobs) виджетов.
- Переключатель светлой/темной темы.
- Показ истории в отдельном окне без всех элементов интерфейса (в вебе удобно встраивать такую полноэкранную историю в iframe).
- Кастомизация.
- Различные рамки (спасибо пакету device_frame) – в превью версии.
- Плагины – тоже в превью.
Как с ней работать?Добавляем в pubspec.yaml(я использую превью-версию, плагины и рамки пока есть только в ней):
storybook_flutter: ^0.5.0-dev.0
Создаем историю (хорошо звучит). В самом простом случае будет что-то такое:
import 'package:flutter/material.dart';
import 'package:storybook_flutter/storybook_flutter.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) => Storybook(
children: [
Story.simple(
name: 'Button',
child: ElevatedButton(
onPressed: () {},
child: const Text('Push me'),
),
),
],
);
}
Запускаем, смотрим, радуемся:
Добавим несколько параметров. Для этого меняем simple конструктор на обычный, и используем builder вместо child:
Story(
name: 'Button',
builder: (context, k) => ElevatedButton(
onPressed:
k.boolean(label: 'Enabled', initial: true) ? () {} : null,
child: Text(k.text(label: 'Text', initial: 'Push me')),
),
),
Запускаем, радуемся еще больше:
Если надо добавить секцию, просто добавляем параметр section:
Story(
name: 'Button',
section: 'Buttons',
builder: (context, k) => ElevatedButton(
onPressed:
k.boolean(label: 'Enabled', initial: true) ? () {} : null,
child: Text(k.text(label: 'Text', initial: 'Push me')),
),
),
Все истории с одинаковым параметром section будут автоматически сгруппированы.Как кастомизировать?У каждой Story есть параметры paddingи background отвечающие, как ни странно, за отступы и фоновый цвет каждой истории:
Story(
name: 'Button',
section: 'Buttons',
padding: const EdgeInsets.all(8),
background: Colors.red,
builder: (context, k) => ElevatedButton(
onPressed:
k.boolean(label: 'Enabled', initial: true) ? () {} : null,
child: Text(k.text(label: 'Text', initial: 'Push me')),
),
),
Но это слишком просто. Гораздо интереснее использовать параметр wrapperBuilder у Story, который позволяет обернуть каждую историю в кастомный виджет:
Story(
name: 'Button',
section: 'Buttons',
wrapperBuilder: (context, story, child) => Container(
decoration: BoxDecoration(border: Border.all()),
margin: const EdgeInsets.all(16),
child: Center(child: child),
),
builder: (context, k) => ElevatedButton(
onPressed:
k.boolean(label: 'Enabled', initial: true) ? () {} : null,
child: Text(k.text(label: 'Text', initial: 'Push me')),
),
),
Этот же билдер можно передать в качестве параметра storyWrapperBuilder в Storybook, тогда каждая история будет обернута в этот виджет.Нужно больше кастомизаций!Если же одних билдеров, врапперов и параметров недостаточно, можно взять CustomStorybook и сделать все своими руками:
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final decoration = BoxDecoration(
border: Border(
right: BorderSide(color: Theme.of(context).dividerColor),
left: BorderSide(color: Theme.of(context).dividerColor),
),
color: Theme.of(context).cardColor,
);
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: CustomStorybook(
builder: (context) => Row(
children: [
Container(
width: 200,
decoration: decoration,
child: const Contents(),
),
const Expanded(child: CurrentStory()),
Container(
width: 200,
decoration: decoration,
child: const KnobPanel(),
),
],
),
children: [
Story(
name: 'Button',
builder: (context, k) => ElevatedButton(
onPressed:
k.boolean(label: 'Enabled', initial: true) ? () {} : null,
child: Text(k.text(label: 'Text', initial: 'Push me')),
),
)
],
),
),
);
}
}
При этом вы можете использовать встроенные виджеты Contents, CurrentStory и KnobPanel (думаю, вы догадались, что они делают). Получим вот такую минималистичную картину:
Один из возможных юзкейсов для CustomStorybook – вот этот плагин, который добавляет Storybook в другую библиотеку, device_preview, с поддержкой оглавления и настроек. Получается вот так:
Что там с плагинами?Как я уже говорил, в превью версии появилась поддержка плагинов и первый 1st party плагин: DeviceFramePlugin:
Плагины позволяют как переопределить рендеринг истории, так и добавить настройки в панель управления.Про создание плагинов, если будет интересно, расскажу в другой статье.Какие платформы поддерживаются?Никакой особой магии под капотом нет, так что теоретически должно работать на всех платформах, которые поддерживаются Flutter'ом. Я проверял на Android, iOS, Web и macOS.Что дальше?Дальше в планах – устаканить API плагинов, подумать, какие плагины еще нужны из коробки (ну и написать их).Потом, скорее всего, займусь генерацией тестов, про которую я писал в начале статьи.На этом все. Буду рад замечаниям, предложениям и баг-репортам (ну и лайкам/звездочкам, конечно же, чего уж греха таить).
===========
Источник:
habr.com
===========
Похожие новости:
- [Тестирование IT-систем, Я пиарюсь, Тестирование веб-сервисов, Тестирование мобильных приложений, Тестирование игр] Лучшие сайты для практики автоматизации тестирования (перевод)
- [Я пиарюсь] BitClout. Котики осваивают новую криптовалюту и соцсеть
- [Разработка под iOS, Разработка мобильных приложений, Swift, Дизайн мобильных приложений] iOS. UI. Приëмы. Часть 1
- [Разработка мобильных приложений, Разработка под Android, Kotlin] Android и привязка к жизненному циклу компонентов
- [Dart, Flutter] Flutter: слоёный пирог с интересной начинкой. Графика
- [Разработка мобильных приложений, Машинное обучение, Искусственный интеллект, Natural Language Processing] OpenAI: более 300 сторонних приложений работают на GPT-3
- [Разработка мобильных приложений, Git, Big Data, Машинное обучение] DVC — Git для данных на примере ML-проекта
- [Разработка мобильных приложений, Разработка под Android, Kotlin] Android + Redux = <3
- [Разработка мобильных приложений, Разработка под Android, DevOps, Gradle] Советы по работе с Gradle для Android-разработчиков
- [Программирование, Разработка мобильных приложений, Dart, Flutter] Dart 2.12: Sound null safety и Dart FFI отправлены на стабильный канал (перевод)
Теги для поиска: #_ja_piarjus (Я пиарюсь), #_razrabotka_mobilnyh_prilozhenij (Разработка мобильных приложений), #_flutter, #_flutter, #_dart, #_storybook, #_ja_piarjus (
Я пиарюсь
), #_razrabotka_mobilnyh_prilozhenij (
Разработка мобильных приложений
), #_flutter
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 18:50
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Всем привет! В этой статье я буду бессовестно пиарить рассказывать о своей библиотеке для Flutter'а, которая позволяет создавать истории из изолированных виджетов и/или экранов. Что-то типа Storybook из мира React. Собственно, она так и называется: storybook_flutter.Зачем она нужна?Во-первых, быстрее делать UI. Конечно, у Flutter'а и так есть hot reload, но если виджет зарыт где-то в дебрях приложения, то до него еще надо добраться. А если этот виджет показывается только при определенных условиях, то эти условия надо воспроизвести. Кроме того, hot reload работает не во всех случаях. Поэтому удобнее изолировать виджет, вынести его в отдельную историю, и работать с этой историей. При этом вам придется задуматься над тем, как бы убрать лишние зависимости из этого виджета, так что код в итоге будет чище.Во-вторых, демонстрация виджетов/экранов. Например, мы делаем свою дизайн-библиотеку для Flutter'а, и в документацию мы бы хотели встраивать интерактивную песочницу с виджетами, тем более, что Flutter for Web уже в стабильной ветке.В-третьих, в будущем я хочу добавить (мне эту идею подсказали в issues) возможность автоматически генерировать golden tests для виджетов с разными комбинациями параметров.Может, взять что-то готовое?Наверное, можно. Но, во-первых, какого-то явного фаворита в сообществе пока нет. Во-вторых, синдром NIH никто не отменял. В-третьих, я хочу иметь возможность быстро добавлять те фичи, которые нам нужны.Как она выглядит?Как-то так: Не очень элегантно, но внешний вид пока не в приоритете. Да и дизайнер из меня – так себе. Кроме того, я пока еще экспериментирую с расположением тулбаров, кнопок и менюшек, поэтому полировать дизайн смысла нет.Что она умеет?
storybook_flutter: ^0.5.0-dev.0
import 'package:flutter/material.dart';
import 'package:storybook_flutter/storybook_flutter.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) => Storybook( children: [ Story.simple( name: 'Button', child: ElevatedButton( onPressed: () {}, child: const Text('Push me'), ), ), ], ); } Добавим несколько параметров. Для этого меняем simple конструктор на обычный, и используем builder вместо child: Story(
name: 'Button', builder: (context, k) => ElevatedButton( onPressed: k.boolean(label: 'Enabled', initial: true) ? () {} : null, child: Text(k.text(label: 'Text', initial: 'Push me')), ), ), Если надо добавить секцию, просто добавляем параметр section: Story(
name: 'Button', section: 'Buttons', builder: (context, k) => ElevatedButton( onPressed: k.boolean(label: 'Enabled', initial: true) ? () {} : null, child: Text(k.text(label: 'Text', initial: 'Push me')), ), ), Story(
name: 'Button', section: 'Buttons', padding: const EdgeInsets.all(8), background: Colors.red, builder: (context, k) => ElevatedButton( onPressed: k.boolean(label: 'Enabled', initial: true) ? () {} : null, child: Text(k.text(label: 'Text', initial: 'Push me')), ), ), Story(
name: 'Button', section: 'Buttons', wrapperBuilder: (context, story, child) => Container( decoration: BoxDecoration(border: Border.all()), margin: const EdgeInsets.all(16), child: Center(child: child), ), builder: (context, k) => ElevatedButton( onPressed: k.boolean(label: 'Enabled', initial: true) ? () {} : null, child: Text(k.text(label: 'Text', initial: 'Push me')), ), ), class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { final decoration = BoxDecoration( border: Border( right: BorderSide(color: Theme.of(context).dividerColor), left: BorderSide(color: Theme.of(context).dividerColor), ), color: Theme.of(context).cardColor, ); return MaterialApp( debugShowCheckedModeBanner: false, home: Scaffold( body: CustomStorybook( builder: (context) => Row( children: [ Container( width: 200, decoration: decoration, child: const Contents(), ), const Expanded(child: CurrentStory()), Container( width: 200, decoration: decoration, child: const KnobPanel(), ), ], ), children: [ Story( name: 'Button', builder: (context, k) => ElevatedButton( onPressed: k.boolean(label: 'Enabled', initial: true) ? () {} : null, child: Text(k.text(label: 'Text', initial: 'Push me')), ), ) ], ), ), ); } } Один из возможных юзкейсов для CustomStorybook – вот этот плагин, который добавляет Storybook в другую библиотеку, device_preview, с поддержкой оглавления и настроек. Получается вот так: Что там с плагинами?Как я уже говорил, в превью версии появилась поддержка плагинов и первый 1st party плагин: DeviceFramePlugin: Плагины позволяют как переопределить рендеринг истории, так и добавить настройки в панель управления.Про создание плагинов, если будет интересно, расскажу в другой статье.Какие платформы поддерживаются?Никакой особой магии под капотом нет, так что теоретически должно работать на всех платформах, которые поддерживаются Flutter'ом. Я проверял на Android, iOS, Web и macOS.Что дальше?Дальше в планах – устаканить API плагинов, подумать, какие плагины еще нужны из коробки (ну и написать их).Потом, скорее всего, займусь генерацией тестов, про которую я писал в начале статьи.На этом все. Буду рад замечаниям, предложениям и баг-репортам (ну и лайкам/звездочкам, конечно же, чего уж греха таить). =========== Источник: habr.com =========== Похожие новости:
Я пиарюсь ), #_razrabotka_mobilnyh_prilozhenij ( Разработка мобильных приложений ), #_flutter |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 18:50
Часовой пояс: UTC + 5