Как создать эффект отрицательного поля во Flutter

Как создать эффект отрицательного поля во Flutter

5 мая 2023 г.

Около 2 лет назад я создал образец виджета карты для веб-панели с помощью Реагируйте JS. Меня вдохновил исходный код на Codepen. Теперь я хочу воссоздать его с помощью кода Flutter. Поскольку он создан для веб-интерфейса, стиль использует код CSS. В исходном коде создатель использует отрицательное поле для поля значка.

original design

 .card
    margin: 0 -8px 32px -8px
    color: rgba(0,0,0,.87)
    box-shadow: 2px 2px 8px rgba(0,0,0,.05)

Я воссоздал аналогичную карту в соответствии с потребностями моей панели инструментов с помощью React JS. Я использую абсолютную позицию и отрицательное значение в свойстве top.

Посмотрите на значки, расположенные поверх карточек.

recreated design with ReactJS

boxicon: {
    position: "absolute",
    zIndex: 1,
    top: -20,
    left: 12,
}

Как насчет Flutter?

В Flutter мы можем использовать margin для некоторых виджетов. Например, Container, Card и т. д. А свойство margin реализует EdgeInsetsGeometry класс. Этот класс также используется для установки отступов во Flutter.

Как мы используем padding и margin во Flutter:

Container(
   padding: EdgeInsets.all(8),
   margin: EdgeInsets.fromLRTB(4,8,4,2)
)

EdgeInsetsGeometry в Flutter имеет метод isNonNegative. Итак….

<цитата>

Значения поля должны быть положительными, мы не можем назначать отрицательные значения для EdgeInsetsGeometry.

Мы получим неудачное утверждение, если укажем отрицательные значения свойств margins или padding.

════════ Exception caught by widgets library ════════
The following assertion was thrown building Card(dirty, dependencies: [_InheritedTheme, _LocalizationsScope-[GlobalKey#95d0d]]):
'package:flutter/src/widgets/container.dart': Failed assertion: line 267 pos 15: 'margin == null || margin.isNonNegative': is not true.


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

Для этого есть несколько способов:

  • Позиционированный виджет | В CSS, если вы знаете о position: absolute. Во Flutter мы можем добиться аналогичного поведения с помощью виджета Positioned.

* Виджет преобразования | Это похоже на свойство преобразования в CSS. Он применяет преобразование перед визуализацией виджета.

* CustomPainter | Я не пробовал, но думаю, что с помощью класса CustomPainter можно создать пользовательскую фигуру, подобную карточке выше.

В этой статье я буду использовать класс Transform для создания карточных виджетов, как на изображении выше. Поскольку отрицательное поле применить нельзя, мы переместим виджет значка с преобразованием матрицы из класса Transform.

Преобразование матрицы: тип преобразования, которое происходит, когда фигура перемещается из одного места в другое на координатной плоскости без изменения ее размера, формы или ориентации… [ref]

С матричным преобразованием мы можем перемещать виджеты, не меняя ничего, кроме их положения. Мы можем доказать это, сравнив положение координат виджета. Если вам интересно, как получить координаты виджета, вы можете попробовать метод расширения globalPaintBound.

Прочитайте мою статью об этом здесь:

https:/ /medium.easyread.co/how-to-get-widget-coordinates-in-flutter-ui-dart-extension-4-d59dc15a9e3f?embedable=true

Создание карточек

Прежде чем применить виджет преобразования, давайте создадим начальную карточку. (Смотрите картинку перед переводом).

before translation

after translation

Теперь мы хотим разместить иконку над картой. Мы будем использовать матричный перевод. Чтобы добавить перевод, есть 2 варианта.

* Если родитель виджета не является виджетом-контейнером, вы можете обернуть его с помощью Transfrom виджета. Например:

javascript Преобразовать( преобразование: Matrix4.translationValues(x, y, z), дочерний элемент: const SomeWidget(), )

* Если это Контейнер, то мы можем присвоить его непосредственно свойству преобразования:

javascript Контейнер( преобразование: Matrix4.translationValues(x, y, z), .....// прочий реквизит )

После добавления значения перевода в виджет значка теперь у нас есть сложенный значок на виджете карточки (Посмотрите на изображение после перевода).

Дополнительно: виджет неоморфизма

Мы закончили с формой виджета карточки. Но если сравнить текущий результат, мы пропустили тень. Чтобы добавить тень эффекта, мы можем добавить ее вручную к свойству BoxDecoration из виджета Container.

Мы также можем использовать метод расширения с именем addNeumorphism.

* Ручная тень для окна значка

javascript Контейнер( украшение: BoxDecoration( borderRadius: BorderRadius.circular(20), boxShadow: константа [ КоробкаТень( смещение: смещение (3, 3), размытиеРадиус: 8, цвет: Цвет (0xFFffa726), ), КоробкаТень( смещение: смещение (-1, -1), размытиеРадиус: 10, цвет: Цвета.белый, ), ....

* Используйте неоморфизм метода расширения

javascript @переопределить Сборка виджета (контекст BuildContext) { возвратный контейнер( ..../// остальная часть кода ).добавитьНевморфизм( bottomShadowColor: Colors.black26, );

И теперь у нас есть улучшенная карта с реализованным эффектом тени:

shadow effect

Завершение

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

https://hackernoon.com/creating-responsive -flutter-app-layouts-for-all-screen-sizes?embedable=true

Карточки будут отображаться с виджетом GridView.count(). Затем мы применяем адаптивный метод для определения crossAxisCount и значения childAspectRatio.

...
body: Padding(
  padding: const EdgeInsets.symmetric(horizontal: 18.0),
  child: GridView.count(
    crossAxisSpacing: 20,
    // mainAxisSpacing: 20,
    childAspectRatio: size.width /
        size.height /
        context.responsive(0.3,
            md: 0.6,
            lg: 0.59,
            xl: 1.2), // this ratio is hard code, you may need to change it base on your need
    crossAxisCount: context.responsive(1, md: 2, xl: 4),
    children: widge,
  ),
),
...

И, наконец, у нас есть виджет карты со сложенными значками, написанный в коде Flutter.

final result

Полный код и демонстрацию можно найти на Dartpad: https://dartpad.dev/?id=be8f84a08f9e2347f20be108ac030484

Спасибо, что прочитали!


:::информация Также опубликовано здесь

:::


Оригинал