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

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

Позволяет ли Flutter внедрить эффект параллакса?

Да, Flutter — один из таких языков программирования, с которым можно легко реализовать эффект параллакса. Эта структура разработки веб-сайтов в основном используется для определения компонентов и элементов пользовательского интерфейса. Поскольку он поставляется с несколькими многоразовыми виджетами, вам не нужно писать код для эффекта параллакса с нуля.

Как добавить эффект параллакса в пользовательский интерфейс с помощью Flutter?

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

Создание списка для хранения всех элементов параллакса

Сначала вам нужно создать список для хранения элементов параллакса в одном месте. Это могут быть изображения, текстовые поля, видео и так далее. Во-первых, вам нужно создать виджет без сохранения состояния под названием ParallaxRecipe, в котором вам нужно разработать дерево виджетов.

Поскольку все элементы будут просматриваться на одной странице, вам нужно использовать виджет SingleChildScrollView, а для определения столбцов вам нужен виджет с именем Column.

класс ParallaxRecipe расширяет StatelessWidget {

const ParallaxRecipe({super.key});

@переопределить

Сборка виджета (контекст BuildContext) {

возврат SingleChildScrollView(

ребенок: столбец (

дети: константа [],

),

);

}

}

Отображение элементов параллакса с текстом и изображением

В созданном вами списке есть дерево виджетов, содержащее все элементы, которые должны отображаться в параллаксе. Теперь первый элемент списка — это фоновое изображение. Для каждого списка должно быть несколько изображений. Вы можете определить форму, в которой будет отображаться фоновое изображение. Вы также можете определить соотношение сторон выбранной вами формы, при условии, что вы выбрали прямоугольник или квадрат.

Если вы хотите, чтобы какой-либо текст отображался на экране, добавьте текст в базу кода и определите его положение. Вы можете указать позицию с помощью ключевых слов left и right и присвоить каждому целочисленное значение. Здесь вам нужно определить дочерний виджет с именем Column, который будет содержать следующие атрибуты:

а. Цвет текста

б. Размер шрифта, который вы хотите отобразить

в. Плотность шрифта, например полужирный, полужирный, обычный, светлый, очень светлый и т. д.

Для добавления нескольких текстов в разные строки вы можете определить дочерний массив, и каждый блок текста будет определять текстовую строку, отображаемую на фоновых изображениях. Если вы не определите какую-либо границу, пользователям будет трудно идентифицировать изображения, особенно если каждое изображение представляет собой что-то уникальное. Эта граница будет присутствовать между текстом и изображением.

После определения макета и структуры параллакса вам необходимо добавить элементы в список параллакса, хранящийся в виджете ParallaxRecipe. Это расширит StatelessWidget. Если значения повторяются, вам необходимо реализовать цикл и сохранить атрибуты, которые будут хранить текстовые данные в этом цикле.

импортировать ‘package:flutter/material.dart’;

импортировать «пакет: флаттер/rendering.dart»;

const Color darkBlue = Color.fromARGB(255, 18, 32, 47);

void main() {

runApp(const MyApp());

}

класс MyApp расширяет StatelessWidget {

константа MyApp({супер.ключ});

@переопределить

Сборка виджета (контекст BuildContext) {

возврат MaterialApp(

тема: ThemeData.dark().copyWith(scaffoldBackgroundColor: темно-синий),

debugShowCheckedModeBanner: false,

дом: конст эшафот(

тело: Центр(

дочерний элемент: ПримерПараллакс(),

),

),

);

}

}

класс ExampleParallax extends StatelessWidget {

const ПримерПараллакс({

супер.ключ,

});

@переопределить

Сборка виджета (контекст BuildContext) {

возврат SingleChildScrollView(

ребенок: столбец (

дети: [

для (конечное местоположение в местоположениях)

ЭлементСпискаРасположений(

URL-адрес изображения: location.url-изображения,

имя: местоположение.имя,

страна: location.place,

),

],

),

);

}

}

класс LocationListItem расширяет StatelessWidget {

LocationListItem({

супер.ключ,

требуется этот.imageUrl,

требуется это.имя,

требуется эта.страна,

});

окончательная строка imageUrl;

конечное имя строки;

конечная страна строки;

final GlobalKey _backgroundImageKey = GlobalKey();

@переопределить

Сборка виджета (контекст BuildContext) {

возврат Заполнение(

отступы: const EdgeInsets.symbol (по горизонтали: 24, по вертикали: 16),

ребенок: Соотношение сторон(

соотношение сторон: 16/9,

ребенок: ClipRRect(

borderRadius: BorderRadius.circular(16),

ребенок: Стек(

дети: [

_buildParallaxBackground(контекст),

_buildGradient(),

_buildTitleAndSubtitle(),

],

),

),

),

);

}

Виджет _buildParallaxBackground (контекст BuildContext) {

возврат поток(

делегат: ParallaxFlowDelegate(

прокручиваемый: Scrollable.of(контекст)!,

listItemContext: контекст,

backgroundImageKey: _backgroundImageKey,

),

дети: [

Изображение.сеть(

URL изображения,

ключ: _backgroundImageKey,

подходят: BoxFit.крышка,

),

],

);

}

Виджет _buildGradient() {

возврат Positioned.fill(

дочерний элемент: Украшенная коробка (

украшение: BoxDecoration(

градиент: LinearGradient(

цвета: [Colors.transparent, Colors.black.withOpacity(0.7)],

начало: Alignment.topCenter,

конец: Alignment.bottomCenter,

остановки: const [0,6, 0,95],

),

),

),

);

}

Виджет _buildTitleAndSubtitle() {

возврат Позиционировано(

слева: 20,

внизу: 20,

ребенок: столбец (

mainAxisSize: MainAxisSize.min,

crossAxisAlignment: CrossAxisAlignment.start,

дети: [

Текст(

имя,

стиль: const TextStyle(

цвет: Цвета.белый,

размер шрифта: 20,

fontWeight: FontWeight.bold,

),

),

Текст(

страна,

стиль: const TextStyle(

цвет: Цвета.белый,

размер шрифта: 14,

),

),

],

),

);

}

}

класс ParallaxFlowDelegate расширяет FlowDelegate {

ParallaxFlowDelegate({

требуется это.scrollable,

требуется этот.listItemContext,

требуется этот.backgroundImageKey,

}) : super(перерисовать: scrollable.position);

окончательный ScrollableState прокручиваемый;

окончательный BuildContext listItemContext;

окончательный GlobalKey backgroundImageKey;

@переопределить

BoxConstraints getConstraintsForChild (int i, ограничения BoxConstraints) {

возврат BoxConstraints.tightFor(

ширина: ограничения.maxWidth,

);

}

@переопределить

void paintChildren (контекст FlowPaintingContext) {

// Вычислить положение этого элемента списка в окне просмотра.

окончательный scrollableBox = scrollable.context.findRenderObject() as RenderBox;

окончательный listItemBox = listItemContext.findRenderObject() as RenderBox;

окончательный listItemOffset = listItemBox.localToGlobal(

listItemBox.size.centerLeft(Offset.zero),

предок: scrollableBox);

// Определяем процентное положение этого элемента списка в пределах

// прокручиваемая область.

final viewportDimension = scrollable.position.viewportDimension;

конечная дробь прокрутки =

(listItemOffset.dy/viewportDimension).clamp(0.0, 1.0);

// Рассчитываем вертикальное выравнивание фона

// на основе процента прокрутки.

окончательное вертикальное выравнивание = выравнивание (0,0, scrollFraction * 2–1);

// Преобразование выравнивания фона в смещение пикселей для

// цели рисования.

окончательный размер фона =

(backgroundImageKey.currentContext!.findRenderObject() как RenderBox)

.размер;

окончательный размер элемента списка = context.size;

окончательный дочерний прямоугольник =

verticalAlignment.inscribe(backgroundSize, Offset.zero и listItemSize);

// Красим фон.

контекст.paintChild(

0,

трансформировать:

Transform.translate(смещение: Offset(0.0, childRect.top)).transform,

);

}

@переопределить

bool shouldRepaint (ParallaxFlowDelegate oldDelegate) {

return прокручиваемый != oldDelegate.scrollable ||

listItemContext != oldDelegate.listItemContext ||

backgroundImageKey != oldDelegate.backgroundImageKey;

}

}

класс Parallax расширяет SingleChildRenderObjectWidget {

постоянный параллакс ({

супер.ключ,

обязательный фон виджета,

}) : супер(ребенок: фон);

@переопределить

RenderObject createRenderObject (контекст BuildContext) {

возврат RenderParallax(scrollable: Scrollable.of(context)!);

}

@переопределить

void updateRenderObject(

Контекст BuildContext, ковариантный RenderParallax renderObject) {

renderObject.scrollable = Scrollable.of(context)!;

}

}

класс ParallaxParentData расширяет ContainerBoxParentData‹RenderBox› {}

класс RenderParallax расширяет RenderBox

с RenderObjectWithChildMixin‹RenderBox›, RenderProxyBoxMixin {

РендерПараллакс({

требуется прокручиваемый ScrollableState,

}) : _scrollable = прокручиваемый;

ScrollableState _scrollable;

ScrollableState получить прокручиваемый => _scrollable;

установить прокручиваемый (значение ScrollableState) {

если (значение != _scrollable) {

if (прикреплен) {

_scrollable.position.removeListener (markNeedsLayout);

}

_scrollable = значение;

if (прикреплен) {

_scrollable.position.addListener (markNeedsLayout);

}

}

}

@переопределить

void attach(ковариантный владелец PipelineOwner) {

super.attach(владелец);

_scrollable.position.addListener (markNeedsLayout);

}

@переопределить

void отсоединить() {

_scrollable.position.removeListener (markNeedsLayout);

супер.отсоединить();

}

@переопределить

void setupParentData (ковариантный дочерний объект RenderObject) {

if (child.parentData is! ParallaxParentData) {

child.parentData = ParallaxParentData();

}

}

@переопределить

void PerformLayout() {

размер = ограничения.большой;

// Заставляем фон занимать всю доступную ширину

// а затем масштабируем его высоту в зависимости от соотношения сторон изображения.

окончательный фон = ребенок!;

окончательный backgroundImageConstraints =

BoxConstraints.tightFor(ширина: размер.ширина);

background.layout(backgroundImageConstraints, parentUsesSize: true);

// Устанавливаем локальное смещение фона, равное нулю.

(background.parentData как ParallaxParentData).offset = Offset.zero;

}

@переопределить

void paint (контекст PaintingContext, смещение смещения) {

// Получаем размер прокручиваемой области.

final viewportDimension = scrollable.position.viewportDimension;

// Вычислить глобальную позицию этого элемента списка.

окончательный scrollableBox = scrollable.context.findRenderObject() as RenderBox;

окончательное смещение фона =

localToGlobal (size.centerLeft (Offset.zero), предок: scrollableBox);

// Определяем процентное положение этого элемента списка в пределах

// прокручиваемая область.

конечная дробь прокрутки =

(backgroundOffset.dy/viewportDimension).clamp(0.0, 1.0);

// Рассчитываем вертикальное выравнивание фона

// на основе процента прокрутки.

окончательное вертикальное выравнивание = выравнивание (0,0, scrollFraction * 2–1);

// Преобразование выравнивания фона в смещение пикселей для

// цели рисования.

окончательный фон = ребенок!;

окончательный backgroundSize = background.size;

окончательный размер элемента списка = размер;

окончательный дочерний прямоугольник =

verticalAlignment.inscribe(backgroundSize, Offset.zero и listItemSize);

// Красим фон.

контекст.paintChild(

фон,

(background.parentData как ParallaxParentData).смещение +

смещение +

Смещение (0.0, childRect.top));

}

}

класс Местоположение {

константное местоположение({

требуется это.имя,

требуется это.место,

требуется этот.imageUrl,

});

конечное имя строки;

итоговое струнное место;

окончательная строка imageUrl;

}

постоянный urlPrefix =

«https://docs.flutter.dev/cookbook/img-files/effects/parallax»;

постоянные местоположения = [

Расположение(

название: «Гора Рашмор»,

место: «США»,

imageUrl: ‘$urlPrefix/01-mount-rushmore.jpg’,

),

Расположение(

название: «Сады у залива»,

место: «Сингапур»,

imageUrl: ‘$urlPrefix/02-singapore.jpg’,

),

Расположение(

название: «Мачу-Пикчу»,

место: «Перу»,

URL-адрес изображения: ‘$urlPrefix/03-machu-picchu.jpg’,

),

Расположение(

название: «Вицнау»,

место: «Швейцария»,

imageUrl: ‘$urlPrefix/04-vitznau.jpg’,

),

Расположение(

название: «Бали»,

место: «Индонезия»,

imageUrl: ‘$urlPrefix/05-bali.jpg’,

),

Расположение(

название: «Мехико»,

место: «Мексика»,

imageUrl: ‘$urlPrefix/06-мехико-сити.jpg’,

),

Расположение(

название: «Каир»,

место: «Египет»,

imageUrl: ‘$urlPrefix/07-cairo.jpg’,

),

];

Выход

Реализация эффекта параллакса в кодовой базе

Основная логика реализации эффекта параллакса состоит в том, чтобы ввести небольшое противоречие в направлении потока изображений (элементов списка) и экрана. Например, если экран прокручивается вниз, изображения будут двигаться вверх, и наоборот. Текущая позиция списка определяется в Прокручиваемом классе. Однако он не будет изменен до тех пор, пока не будет завершена вся фаза макета веб-страницы.

Разработчики Flutter смогут менять положение фоновых изображений только на этапе рисования. Поэтому вам нужен виджет Flow, чтобы установить больший контроль над изменением элементов списка и фоновых изображений на ходу. Если дочерний элемент Flow имеет более одного дочернего элемента, вам необходимо использовать виджет FlowDelegate для выбора времени и положения каждого дочернего блока.

Чтобы определить положение фоновых изображений, вы должны учесть три наиболее важных фактора. Это:

а. Размер изображения после уменьшения в соответствии с соотношением сторон списка

б. Границы скроллера

в. Привязка отдельного элемента, хранящегося в списке

Заключение

В этой статье мы поделились краткой информацией о добавлении эффекта параллакса в приложение Flutter самым простым способом. Поскольку StatelessWidget, ParallaxRecipe уже доступен в SDK Flutter, все, что вам нужно сделать, это определить различные параметры для списка элементов, хранящихся внутри дерева виджетов. Внедрить Parallax с этим фреймворком намного проще, чем с другими.

Если вы хотите разработать приложение Flutter для своего бизнеса, вы можете связаться с компанией по разработке приложений Flutter, такой как Flutter Agency, которая может оказать помощь в вашем проекте, а также позаботится о том, чтобы приложение идеально подходило. в ваш бюджет.

Часто задаваемые вопросы (FAQ)

1. Что такое класс полосы прокрутки во Flutter?

Объект класса Scrollbar используется для включения горизонтальной и вертикальной полос прокрутки. Именно компоненты GUI позволяют нам просматривать невидимое количество столбцов и строк. Он может добавить контейнер верхнего уровня, например фрейм, или компонент, например панель. Он расширяет класс компонентов.

2. Укажите виджет делегата потока в приложении Flutter.

Flow относится к библиотеке виджетов, которая размерами и позиционирует своих дочерних элементов, как это указано в описании FlowDelegate. Это полезно, когда дети должны переместить использованные измененные матрицы.

3. Определите виджет без сохранения состояния

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