Создание крутых интерфейсов с Flow Widget

Создание крутых интерфейсов с Flow Widget

FlutterPulse

Эта статья переведена специально для канала FlutterPulse. В этом канале вы найдёте много интересных вещей, связанных с Flutter. Не забывайте подписываться! 🚀

На этом третьем этапе определяется пользовательский класс FlowWidgetDelegate, расширяющий FlowDelegate, для управления компоновкой и отображением дочерних элементов внутри виджета Flow. Делегат принимает Animation<double>, elementsSpacing, iconsSpacing и Curve в качестве параметров для управления движением, расстоянием и поведением плавности. Внутри paintChildren позиция каждого дочернего элемента рассчитывается на основе текущего значения анимации. Применяется преобразование Matrix4.translationValues для анимации смещения. Последний дочерний элемент обрабатывается отдельно, обычно оставаясь статичным, в то время как остальные позиционируются динамически с использованием значения анимации и кривой для определения их смещения. Метод shouldRepaint возвращает true, если изменились какие-либо релевантные свойства, обеспечивая правильное отображение обновлений. Этот делегат позволяет точно контролировать позиционирование дочерних элементов с анимацией внутри компоновки Flow.

class FlowWidgetDelegate extends FlowDelegate {
const FlowWidgetDelegate({
required this.animation,
required this.elementsSpacing,
required this.iconsSpacing,
required this.curve,
}) : super(repaint: animation);

final Animation<double> animation;
final double elementsSpacing;
final double iconsSpacing;
final Curve curve;

@override
void paintChildren(FlowPaintingContext context) {
final size = context.size;
final x = size.width;
final y = size.height;

for (int i = 0; i < context.childCount; i++) {
if (i == context.childCount - 1) {
context.paintChild(
i,
transform: Matrix4.translationValues(
x - 50 - elementsSpacing,
y - 50 - elementsSpacing,
0,
),
);
} else {
var offset = 0.0;
if (animation.value == 0) {
offset = 0;
} else {
offset =
(curve.transform(animation.value) * 30) +
(iconsSpacing * context.childCount);
}
context.paintChild(
i,
transform: Matrix4.translationValues(
x - 50 - elementsSpacing,
y - offset * (i + 1) - 50 - elementsSpacing,
0,
),
);
}
}
}

Наконец мы всё собираем вместе с использованием AnimatedBuilder:

Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: const Text('Flow Widget'),
),
body: AnimatedBuilder(
animation: _animation,
builder:
(context, _) => Flow(
delegate: FlowWidgetDelegate(
animation: _animation,
elementsSpacing: 35,
iconsSpacing: 10,
curve: Curves.ease,
),
children: [
FloatingButton(iconData: Icons.phone, onPressed: () {}),
FloatingButton(iconData: Icons.email, onPressed: () {}),
FloatingButton(iconData: Icons.rss_feed, onPressed: () {}),
FloatingButton(
iconData: Icons.more_horiz,
onPressed: () async {
if (_controller.isCompleted) {
await _controller.reverse();
} else {
await _controller.forward();
}
},
),
],
),
),
);

Чтобы посмотреть и запустить полный пример, ознакомьтесь с репозиторием на GitHub. Если вам это было полезно, подумайте о том, чтобы поставить ему звезду — это небольшой жест, который очень помогает в поддержке будущего контента.

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

Спасибо за чтение, и счастливого кодинга!

Report Page