← Назад к вопросам

Можно ли отказаться от material?

1.2 Junior🔥 101 комментариев
#Flutter виджеты#Архитектура Flutter

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Можно ли отказаться от Material Design

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

Что такое Material Design в Flutter

Material Design — это не обязательная библиотека, а просто набор готовых компонентов и стилей. Flutter дает вам полную свободу в выборе дизайн-системы.

// Приложение работает БЕЗ Material
import 'package:flutter/widgets.dart'; // Нет Material!

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp();

  @override
  Widget build(BuildContext context) {
    return Scaffold( // ОШИБКА: Scaffold требует MaterialApp!
      body: Center(
        child: Text('Hello'),
      ),
    );
  }
}

Случай 1: Минимальное приложение без Material

Если вы используете только базовые виджеты:

import 'package:flutter/widgets.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp();

  @override
  Widget build(BuildContext context) {
    return WidgetsApp(
      title: 'My App',
      home: const HomeScreen(),
    );
  }
}

class HomeScreen extends StatelessWidget {
  const HomeScreen();

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Color(0xFFFFFFFF),
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Text(
            'Hello World',
            style: TextStyle(
              fontSize: 24,
              fontWeight: FontWeight.bold,
            ),
          ),
          GestureDetector(
            onTap: () => print('Tapped!'),
            child: Container(
              padding: EdgeInsets.all(16),
              decoration: BoxDecoration(
                color: Color(0xFF2196F3),
                borderRadius: BorderRadius.circular(8),
              ),
              child: Text(
                'Click me',
                style: TextStyle(color: Color(0xFFFFFFFF)),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

Преимущества:

  • Минимальный размер приложения
  • Полный контроль над UI
  • Нет зависимостей от Material

Недостатки:

  • Нужно реализовать много базового функционала
  • Нет Material компонентов (AppBar, FloatingActionButton и т.д.)
  • Требует больше кода для простых вещей

Случай 2: Cupertino Design (iOS style)

Если ваше приложение только для iOS или нужен iOS дизайн:

import 'package:flutter/cupertino.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp();

  @override
  Widget build(BuildContext context) {
    return CupertinoApp(
      title: 'iOS App',
      theme: CupertinoThemeData(
        brightness: Brightness.light,
      ),
      home: const HomeScreen(),
    );
  }
}

class HomeScreen extends StatelessWidget {
  const HomeScreen();

  @override
  Widget build(BuildContext context) {
    return CupertinoPageScaffold(
      navigationBar: CupertinoNavigationBar(
        middle: const Text('Home'),
      ),
      child: Center(
        child: CupertinoButton(
          onPressed: () => print('Tapped!'),
          child: const Text('Click me'),
        ),
      ),
    );
  }
}

Когда использовать:

  • iOS-only приложение
  • Нужен нативный iOS look
  • Работаете с iOS инженерами

Случай 3: Кастомная дизайн-система

Много современных приложений используют свои компоненты:

import 'package:flutter/material.dart'; // Можно использовать базовое

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp();

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Custom Design',
      home: const HomeScreen(),
    );
  }
}

// Кастомный компонент вместо Material Button
class CustomButton extends StatelessWidget {
  final String label;
  final VoidCallback onPressed;
  final Color backgroundColor;
  final Color textColor;

  const CustomButton({
    required this.label,
    required this.onPressed,
    this.backgroundColor = const Color(0xFF2196F3),
    this.textColor = const Color(0xFFFFFFFF),
  });

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: onPressed,
      child: Container(
        padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
        decoration: BoxDecoration(
          color: backgroundColor,
          borderRadius: BorderRadius.circular(16),
          boxShadow: [
            BoxShadow(
              color: backgroundColor.withOpacity(0.3),
              blurRadius: 8,
              offset: const Offset(0, 4),
            ),
          ],
        ),
        child: Text(
          label,
          style: TextStyle(
            color: textColor,
            fontSize: 16,
            fontWeight: FontWeight.w600,
          ),
        ),
      ),
    );
  }
}

class HomeScreen extends StatelessWidget {
  const HomeScreen();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Custom Design')),
      body: Center(
        child: CustomButton(
          label: 'My Custom Button',
          onPressed: () => print('Pressed!'),
          backgroundColor: const Color(0xFFFF6B6B),
        ),
      ),
    );
  }
}

Полностью кастомное приложение с WidgetsApp

Если вы ДЕЙСТВИТЕЛЬНО хотите отказаться от Material полностью:

import 'package:flutter/widgets.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp();

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  int _currentIndex = 0;

  @override
  Widget build(BuildContext context) {
    return WidgetsApp(
      debugShowCheckedModeBanner: false,
      title: 'Widgets Only',
      onGenerateRoute: (settings) {
        return PageRouteBuilder(
          pageBuilder: (context, animation, secondaryAnimation) {
            return AnimatedBuilder(
              animation: animation,
              builder: (context, child) {
                return Opacity(
                  opacity: animation.value,
                  child: HomeScreen(),
                );
              },
            );
          },
        );
      },
    );
  }
}

class HomeScreen extends StatefulWidget {
  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  @override
  Widget build(BuildContext context) {
    return Container(
      color: const Color(0xFFFFFFFF),
      child: SafeArea(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Text(
              'Pure Widgets App',
              style: TextStyle(
                fontSize: 32,
                fontWeight: FontWeight.bold,
              ),
            ),
            const SizedBox(height: 40),
            GestureDetector(
              onTap: () => print('Tapped!'),
              child: MouseRegion(
                cursor: SystemMouseCursors.click,
                child: Container(
                  padding: const EdgeInsets.all(20),
                  decoration: BoxDecoration(
                    color: const Color(0xFF2196F3),
                    borderRadius: BorderRadius.circular(12),
                  ),
                  child: const Text(
                    'Custom Button',
                    style: TextStyle(
                      color: Color(0xFFFFFFFF),
                      fontSize: 18,
                    ),
                  ),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

Сравнение подходов

ПодходРазмерСложностьРекомендуется для
MaterialApp+2 MBНизкаяБольшинство приложений
CupertinoApp+1.5 MBНизкаяiOS приложения
WidgetsApp+0.5 MBВысокаяМинималистичные приложения
Кастомная системаЗависитОчень высокаяУникальный дизайн

Практические сценарии

Используйте Material когда:

  • Нужно быстро создать приложение
  • Нужны стандартные компоненты
  • Работаете в команде (стандарты)
  • Нужна постоянная поддержка компонентов

Отказывайтесь от Material когда:

  • Уникальный кастомный дизайн
  • Очень строгие требования по размеру APK
  • Нужен полный контроль над UI
  • Работаете только с iOS (используйте Cupertino)

Real-world альтернативы Material

// flutter_custom_paint: рисуем сами
// skia: низкоуровневая графика
// flame: для игр
// get_ui: кастомная дизайн-система
// riverpod + widgets: для состояния

My Recommendation

Для 95% приложений оставайтесь с Material. Это:

  • Уже оптимизировано
  • Постоянно обновляется
  • Имеет огромное сообщество
  • Стандарт индустрии

Отказывайтесь от Material только если у вас есть ОЧЕНЬ веские причины. Время, потраченное на создание кастомных компонентов, обычно не окупается экономией размера приложения.

Можно ли отказаться от material? | PrepBro