Flutter Desktop, Mobile, Web и Embedded — адаптивные интерфейсы для разных платформ.

Официальная документация Flutter, доступная здесь, гласит следующее: Адаптивный и Отзывчивыйможно рассматривать как отдельные аспекты приложения: вы может иметь адаптивное приложение, которое не отвечает или наоборот. И, конечно же, приложение может быть и тем, и другим.

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

2. Адаптивный
Адаптация приложения для работы на различных типах устройств, таких как мобильные и настольные, требует работы с мышью и клавиатурой, а также с сенсорным вводом. Это также означает, что существуют разные ожидания относительно визуальной плотности приложения, того, как работает выбор компонентов (например, каскадные меню или нижние листы), использования функций, специфичных для платформы (таких как окна верхнего уровня), и многого другого.

Разобравшись с этим, давайте перейдем к моему делу.

Описание моего дела:

Как только была выпущена первая более стабильная версия Flutter Desktop, я получил задание разработать многоплатформенное приложение с «унифицированной базой кода» для настольных компьютеров и мобильных устройств.

В начале моей первой идеей было создать виджет с условной структурой для отображения дерева виджетов для каждой платформы. Что-то вроде этого:

import 'package:flutter/material.dart';
import 'breakpoints.dart';

class Responsive extends StatefulWidget {
  final Widget mobile;
  final Widget? desktop;
  final Widget? tablet;

  const Responsive({
    Key? key,
    required this.mobile,
    this.tablet,
    this.desktop,
  }) : super(key: key);

  static bool isMobile(BuildContext _) =>
      MediaQuery.of(_).size.width < kTabletBreakpoint;

  static bool isTablet(BuildContext _) =>
      MediaQuery.of(_).size.width < kDesktopBreakpoint &&
      MediaQuery.of(_).size.width >= kTabletBreakpoint;

  static bool isDesktop(BuildContext _) =>
      MediaQuery.of(_).size.width >= kDesktopBreakpoint;

  @override
  State<Responsive> createState() => _ResponsiveState();
}

class _ResponsiveState extends State<Responsive> {
  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (context, dimension) {
        if (dimension.maxWidth < kTabletBreakpoint) {
          return widget.mobile;
        } else if (dimension.maxWidth >= kTabletBreakpoint &&
            dimension.maxWidth < kDesktopBreakpoint) {
          return widget.tablet ?? widget.mobile;
        } else {
          return widget.desktop ?? widget.mobile;
        }
      },
    );
  }
}

И используйте это следующим образом:

class MyWidget extends StatelessWidget {
  const MyWidget({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Responsive(
      mobile: MobileWidget(),
      desktop: DesktopWidget(),
    );
  }
}

Примечание: если вам нужно создать экран и изменить размер адаптивного макета, этот виджет для вас! Но если вы ищете приложение с адаптированным интерфейсом, оставайтесь здесь…

Во время разработки я понял, что с этой архитектурой у меня будет много условных структур для обработки деталей каждой платформы. Виджеты становились больше и сложнее, а иногда виджеты были настолько сложными, что лучше всего было создать отдельный виджет для каждой платформы (например, list_items_mobile.dart и list_items_desktop.dart).

Идея создать приложение с единой кодовой базой была потеряна.

Возможное решение:

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

Итак, у нас будет следующая организация:

  • услуги: содержит все, что не связано с визуальным интерфейсом.
  • проект платформы x: содержит все визуальные элементы (UI) для платформы x.
  • проект платформы y: содержит все визуальные элементы (UI) для платформы y.

С помощью Flutter сегодня можно разрабатывать приложения для настольных компьютеров Windows, Mac и Linux, мобильных устройств для Android и IOS, веб-приложений и встроенных приложений.
https://flutter.dev/

Как сделать:

Начнем с создания слоя сервисов с помощью template package, например:

flutter create --template=package services

Теперь давайте создадим два других слоя пользовательского интерфейса: один для мобильных и один для веб-сайтов. При необходимости создайте дополнительные слои для необходимых платформ.

Бегать:

flutter create --platforms=android,ios project_mobile

и после:

flutter create --platforms=web project_web

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

Измените проекты пользовательского интерфейса pubspec.yaml следующим образом:

dependencies:
  flutter:
    sdk: flutter
  services:
    path: ../services

Для организации все сервисы, контроллеры, адаптеры, модели, utils, константы должны быть создан в папке lib/src следующим образом:

Чтобы разрешить проектам доступ к документам, которые находятся на уровне services, их необходимо экспортировать. Создайте файл для каждой доступной службы (пример: utils_library.dart).

Этот файл должен выглядеть примерно так:

library utils;

export './src/services/utils.dart';
export './src/services/secure_storage.dart';

И, наконец, чтобы получить доступ к сервису, доступному в проектах каждой платформы, просто импортируйте его:

import 'package:services/utils_library.dart' as utils;

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

Если у вас есть какие-либо вопросы, отзывы или предложения, не стесняйтесь, оставьте комментарий, и мы будем искать! :-)

Следите за нашим блогом на Medium и будьте в курсе всего, что происходит в Ateliê.

Передай нам привет! И присоединяйтесь к нам в социальных сетях:
Электронная почта: [email protected]
Сайт
Facebook
Instagram
LinkedIn