Можно ли использовать Material-виджеты в iOS-приложении на Flutter?

Ответ

Да, Material-виджеты работают на iOS, но это нарушает Apple Human Interface Guidelines (HIG) и создает неестественный пользовательский опыт для iOS-пользователей.

Пример Material-виджетов на iOS:

import 'package:flutter/material.dart';

MaterialApp(
  theme: ThemeData.light(),
  home: Scaffold(
    appBar: AppBar(
      title: Text('Material Design on iOS'),
      actions: [
        IconButton(
          icon: Icon(Icons.more_vert),
          onPressed: () {},
        ),
      ],
    ),
    body: Center(
      child: Column(
        children: [
          ElevatedButton(
            onPressed: () {},
            child: Text('Material Button'),
          ),
          Switch(
            value: true,
            onChanged: (bool value) {},
          ),
          CircularProgressIndicator(),
        ],
      ),
    ),
    floatingActionButton: FloatingActionButton(
      onPressed: () {},
      child: Icon(Icons.add),
    ),
  ),
);

Проблемы Material Design на iOS:

  1. Визуальные различия:

    • Material использует shadows и elevation, iOS — flat design с blurs
    • Разные типографика и spacing
    • Material buttons имеют ripple effect, iOS — highlight
  2. Навигационные паттерны:

    • Material: hamburger menu, tabs сверху
    • iOS: tab bar снизу, navigation bar сверху
    • Разные жесты для возврата
  3. Компоненты:

    • Material dialogs vs. iOS alerts
    • Material snackbars vs. iOS toasts
    • Разные pickers и date selectors

Когда Material допустим на iOS:

// 1. Корпоративные/инструментальные приложения
Material(
  elevation: 4,
  borderRadius: BorderRadius.circular(8),
  child: Container(
    padding: EdgeInsets.all(16),
    child: Text('Инструментальный интерфейс'),
  ),
);

// 2. Приложения с сильным брендингом
Theme(
  data: ThemeData(
    primaryColor: BrandColors.primary,
    buttonTheme: ButtonThemeData(/* кастомный стиль */),
  ),
  child: MaterialWidget(),
);

// 3. Прототипы и MVP

Лучшие практики для iOS-приложений:

// 1. Использование Cupertino-виджетов
CupertinoApp(
  theme: CupertinoThemeData(
    primaryColor: CupertinoColors.systemBlue,
  ),
  home: CupertinoPageScaffold(
    navigationBar: CupertinoNavigationBar(
      middle: Text('Нативный iOS'),
    ),
    child: SafeArea(
      child: ListView.builder(
        itemBuilder: (context, index) => CupertinoListTile(
          title: Text('Item $index'),
          onTap: () {},
        ),
      ),
    ),
  ),
);

// 2. Адаптивные компоненты
Widget buildPlatformButton() {
  if (Theme.of(context).platform == TargetPlatform.iOS) {
    return CupertinoButton.filled(
      onPressed: () {},
      child: Text('iOS Button'),
    );
  } else {
    return ElevatedButton(
      onPressed: () {},
      child: Text('Android Button'),
    );
  }
}

// 3. Пакет platform_widgets для упрощения
PlatformWidget(
  android: (context) => MaterialWidget(),
  ios: (context) => CupertinoWidget(),
);

Для production iOS-приложений рекомендуется использовать Cupertino-виджеты или реализовывать адаптивный UI, который соответствует ожиданиям пользователей каждой платформы.

Ответ 18+ 🔞

А, слушай, вот тебе история про Flutter и iOS, просто пиздец. Представь: ты делаешь приложение, всё красиво, Material Design, тени, кнопки с этими риппл-эффектами — красота, ёпта! А потом запускаешь на айфоне, и тут такое чувство, будто ты в Москву приехал в шортах и гавайской рубахе, когда на улице минус двадцать. Вроде живёшь, но все на тебя смотрят как на долбоёба.

Вот смотри, как это выглядит в коде:

import 'package:flutter/material.dart';

MaterialApp(
  theme: ThemeData.light(),
  home: Scaffold(
    appBar: AppBar(
      title: Text('Material Design on iOS'),
      actions: [
        IconButton(
          icon: Icon(Icons.more_vert),
          onPressed: () {},
        ),
      ],
    ),
    body: Center(
      child: Column(
        children: [
          ElevatedButton(
            onPressed: () {},
            child: Text('Material Button'),
          ),
          Switch(
            value: true,
            onChanged: (bool value) {},
          ),
          CircularProgressIndicator(),
        ],
      ),
    ),
    floatingActionButton: FloatingActionButton(
      onPressed: () {},
      child: Icon(Icons.add),
    ),
  ),
);

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

А теперь, почему это — пизда рулю на iOS:

  1. Визуал — полный пиздец. У Material — тени, объём, эта материя. У iOS — всё плоское, с лёгкими размытиями, элегантное такое. Твои Material-кнопки на айфоне выглядят как жирные пончики на фоне хрустальных бокалов. Типографика другая, отступы другие. У Material кнопка при нажатии волнами расходится, а на iOS она просто подсвечивается. Пользователь айфона ткнет в твою кнопку и подумает: «Чё за хуйня, она что, сломалась?».

  2. Навигация — ёперный театр. В Material-приложении меню часто слева, выдвижное, гамбургер. На iOS табы ВСЕГДА внизу, а навигационная панель — сверху. Жесты назад разные! На андроиде часто кнопка, на iOS — свайп с края. Твой пользователь будет пытаться свайпнуть, а него нихуя не получится, и он просто выбросит телефон в окно от бессилия. Доверия ебать ноль после такого.

  3. Компоненты — вообще манда с ушами. Диалоговые окна, алерты, пикеры выбора даты — всё абсолютно другое. Material snackbar всплывает снизу, а iOS тост — обычно по центру. Поставишь не тот — и человек просто не поймёт, что ему приложение только что сообщило.

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

// 1. Приложения-инструменты, корпоративные штуки.
// Ну там, складской учёт или графики для начальства. Там всем похуй на дизайн, лишь бы работало.
Material(
  elevation: 4,
  borderRadius: BorderRadius.circular(8),
  child: Container(
    padding: EdgeInsets.all(16),
    child: Text('Инструментальный интерфейс'),
  ),
);

// 2. Сильный бренд. Если у тебя, например, весь фирменный стиль — это жёлтые треугольные кнопки.
// Тогда да, хуй с горы, делай как по бренд-буку, пусть даже на iOS.
// 3. Прототип или MVP, который надо вчера. Тут да, **да похуй**, лишь бы показать функционал.

Но если ты делаешь нормальное, продакшен-приложение для iOS, то делай так, чтобы не было стыдно:

// 1. Используй родные Cupertino-виджеты. Это как надеть костюм.
CupertinoApp(
  theme: CupertinoThemeData(
    primaryColor: CupertinoColors.systemBlue,
  ),
  home: CupertinoPageScaffold(
    navigationBar: CupertinoNavigationBar(
      middle: Text('Нативный iOS'),
    ),
    child: SafeArea(
      child: ListView.builder(
        itemBuilder: (context, index) => CupertinoListTile(
          title: Text('Item $index'),
          onTap: () {},
        ),
      ),
    ),
  ),
);

// 2. Делай адаптивные штуки. Если на айфоне — показывай одну кнопку, если на андроиде — другую.
Widget buildPlatformButton() {
  if (Theme.of(context).platform == TargetPlatform.iOS) {
    return CupertinoButton.filled(
      onPressed: () {},
      child: Text('iOS Button'),
    );
  } else {
    return ElevatedButton(
      onPressed: () {},
      child: Text('Android Button'),
    );
  }
}

// 3. Есть куча пакетов, которые упрощают эту жизнь. Не изобретай велосипед.
PlatformWidget(
  android: (context) => MaterialWidget(),
  ios: (context) => CupertinoWidget(),
);

Короче, суть в чём. Можно, конечно, запихнуть Material на iOS — технически-то всё запустится. Но это будет выглядеть как пидарас шерстяной на фоне остальных приложений. Пользователь откроет и сразу почувствует подозрение ебать, что что-то не так. А если он чувствует, что что-то не так, он удаляет приложение. Всё просто, ёпта. Хочешь, чтобы на iOS было хорошо — делай по-ихнему. Или хотя бы умно адаптируй. Иначе получится хитрая жопа, которая никому не нравится.