Какой Sliver позволяет вставить обычный виджет в CustomScrollView?
Anonymous Quiz
15%
SliverList
76%
SliverToBoxAdapter
4%
SliverAppBar
5%
SliverGrid
За этот год во @flutterfriendly вышло 222 публикации, а вы поставили более 3800 реакций. Решили вспомнить посты, которые вы больше всего читали и которыми активно делились за 2025 год:
Аудит безопасности мобильных приложений: виды и этапы
Использование ARB-формата
Обновление Android Studio без ошибок
Как пользоваться режимом выбора виджетов
Пакет meta
Оптимизация списков: как сделать скролл плавным и эффективным
Виджеты для управления размерами
Работа с иконками
Библиотека dartx
FutureOr в Dart
gRPC во Flutter: эффективная коммуникация между клиентом и сервером
Модификаторы классов в Dart
Тестирование кода: виды и для чего это нужно
Режимы сборки: debug, profile и release
Friflex Flutter Starter
Паттерн Strategy
Запись митапа: способы темизации и кастомизации мобильных приложений
Создание виджетов поверх существующего интерфейса
Определение местоположение пользователя: интеграция в приложение
Как быстро развернуть сайт документации с помощью Docusaurus
Адаптивная верстка: что это такое и как реализовать
Утечки памяти во Flutter-приложениях
Техническое собеседование: как подготовиться начинающим разработчикам
Hot Restart и Hot Reload: в чем отличия и как работают
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥9❤4
Какой принцип SOLID нарушен, если класс UserManager одновременно валидирует данные, сохраняет в БД и отправляет email?
Anonymous Quiz
2%
Принцип открытости/закрытости (O)
96%
Принцип единственной ответственности (S)
2%
Принцип инверсии зависимостей (D)
1%
Принцип подстановки Лисков (L)
Что из этого НЕ является Ephemeral state?
Anonymous Quiz
4%
Состояние текущей вкладки в TabBar
11%
Позиция скролла в ListView
71%
Данные пользователя из API
14%
Состояние анимации
Библиотека Equatable помогает:
Anonymous Quiz
5%
Упростить работу с State Management
85%
Упростить сравнение объектов по значению
8%
Создавать immutable объекты
2%
Генерировать тесты автоматически
Что означает TDD?
Anonymous Quiz
8%
Type-Driven Development
5%
Time-Delayed Deployment
1%
Top-Down Design
85%
Test-Driven Development
Dart FFI позволяет:
Anonymous Quiz
95%
Вызывать нативный C/C++ код из Dart
0%
Создавать красивые интерфейсы
3%
Работать с Firebase
2%
Ускорять компиляцию
Какой виджет лучше всего подходит для длинных списков с большим количеством простых элементов?
Anonymous Quiz
14%
SingleChildScrollView
13%
CustomScrollView
4%
Column
69%
ListView
Когда объект может быть удалён Garbage Collector’ом?
Anonymous Quiz
1%
Сразу после создания
5%
При переходе на новый экран
92%
Когда на объект больше нет ссылок
1%
Только после ручного вызова GC
Какой ключ лучше использовать для элементов списка с уникальным id из объекта item?
Anonymous Quiz
19%
UniqueKey
72%
ValueKey(item.id)
4%
GlobalKey
5%
ObjectKey(item)
Что произойдет, если вы измените метод initState() в StatefulWidget и примените Hot Reload?
Anonymous Quiz
8%
Новый код initState() будет выполнен сразу
22%
Виджет будет полностью пересоздан, initState() вызовется
67%
initState() не вызовется, старое состояние сохранится
4%
Приложение полностью перезапустится
❤2
Сегодня поговорим про push‑уведомления в реальном проекте: как работать с FCM, показывать локальные уведомления в foreground, обрабатывать background‑события, реализовать deep links по клику и корректно запрашивать разрешения.
Так как это первая статья в новом году, поздравляю всех с праздниками! Желаю вам продуктивного и приятного 2026‑го: чтобы баги фиксились легко, а фичи шли в прод. Уже все вернулись к работе или кто‑то все еще лежит на диване?
Что и зачем:
◾️FCM (Firebase Cloud Messaging) — транспорт: доставляет уведомления/дату на устройство. Поддерживает notification (авто‑показ) и data‑messages (передача произвольных данных)
◾️flutter_local_notifications — показывает локальное нотификационное состояние, полезно, когда приложение на foreground (FCM обычно не показывает системное уведомление, если приложение активно)
◾️Deep links — позволяют при клике на уведомление перейти в конкретный экран приложения (через data payload или динамические ссылки)
Код: инициализация и обработка
Пакеты: firebase_core, firebase_messaging, flutter_local_notifications, (go_router / navigatorKey для навигации).
Простой пример:
// main.dart (сокращённо)
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
final FlutterLocalNotificationsPlugin localNotif = FlutterLocalNotificationsPlugin();
Future<void> _bgHandler(RemoteMessage m) async {
await Firebase.initializeApp();
// Лёгкая логика: запись в БД или планирование локальной нотификации
print('BG message ${m.messageId}');
}
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
FirebaseMessaging.onBackgroundMessage(_bgHandler);
await localNotif.initialize(
const InitializationSettings(
android: AndroidInitializationSettings('@mipmap/ic_launcher'),
iOS: DarwinInitializationSettings(),
),
onDidReceiveNotificationResponse: (resp) {
final p = resp.payload;
if (p != null) navigatorKey.currentState?.pushNamed(p);
},
);
runApp(MyApp());
}
final GlobalKey<NavigatorState> navigatorKey = GlobalKey();
class MyApp extends StatefulWidget { @override State createState() => _MyAppState(); }
class _MyAppState extends State<MyApp> {
final FirebaseMessaging fm = FirebaseMessaging.instance;
@override
void initState() {
super.initState();
_requestPermissions();
FirebaseMessaging.onMessage.listen(_onMessage);
FirebaseMessaging.onMessageOpenedApp.listen((m) => _handleData(m.data));
_checkInitialMessage();
}
Future<void> _requestPermissions() async {
if (Platform.isIOS) {
await fm.requestPermission(alert: true, badge: true, sound: true);
} else {
// Android 13+: POST_NOTIFICATIONS нужно в Manifest + runtime request (permission_handler)
await fm.requestPermission();
}
}
void _onMessage(RemoteMessage m) {
// в foreground показываем локальную нотификацию
final t = m.notification?.title ?? m.data['title'];
final b = m.notification?.body ?? m.data['body'];
localNotif.show(m.hashCode, t, b, const NotificationDetails(
android: AndroidNotificationDetails('ch', 'Channel', importance: Importance.max),
), payload: m.data['deeplink']);
}
Future<void> _checkInitialMessage() async {
final m = await fm.getInitialMessage();
if (m != null) _handleData(m.data);
}
void _handleData(Map<String, dynamic> d) {
final deeplink = d['deeplink'] ?? d['url'] ?? d['screen'];
if (deeplink != null) navigatorKey.currentState?.pushNamed(deeplink);
}
@override
Widget build(BuildContext c) => MaterialApp(navigatorKey: navigatorKey, home: Scaffold(body: Center(child: Text('Ready'))));
}
Продолжение — в комментариях 👇
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5⚡3👍1🔥1
This media is not supported in your browser
VIEW IN TELEGRAM
Ну-ка признавайтесь, кто всю неделю прокрастинировал вместо работы? А кто виноват? Конечно, новогодние праздники! Сегодня поговорим о том, как же максимально мягко войти в этот привычный, но давно забытый рабочий режим.
1 шаг. Пообщаться с коллегами
Всем нам непросто возвращаться к работе. Поговорите об этом! Немного юмора и обсуждений самых приятных воспоминаний с каникул легко поднимут настроение и настроют на позитивную волну.
2 шаг. Восстановить память
Наверняка, почти никто из вашей команды полноценно не помнит, какие проблемы и вопросы остались с прошлого года. Поэтому перед тем, как приступить к работе, синхронизируйтесь с коллегами.
Посмотрите доску задач, вспомните, какие незакрытые моменты были отложены на новый год. В идеале — провести планирование с командой, сформировать список задач, расставить приоритеты. Как только вы четко увидите список задач, вам будет проще настроиться на работу.
3 шаг. Начните с простого
Если у вас есть возможность самостоятельно определять порядок выполняемых задач, воспользуйтесь ею. Возьмите в первую очередь самые простые и короткие задачи. Сначала закроете одну, потом вторую, а дальше двигаться по инерции будет проще.
4 шаг. Чаще делайте перерывы
Конечно, звучит не очень продуктивно. Но после долгого отдыха мозгу тяжело долго держать фокус. Давайте ему возможность разгрузиться — короткие перерывы по 5-10 минут помогут в этом. Но не слишком злоупотребляйте, есть риск снова уйти в прокрастинацию.
5 шаг. Восстановите привычный режим жизни.
Чаще всего после длительного перерыва страдает не только работа, но и другие сферы жизни. Верните в жизнь свои старые привычки, приостановленные на праздники. Ходили в спортзал? Вернитесь к тренировкам. Занимались английским? Возобновите занятия. Ложились спать в 22:00? Самое время наладить режим.
Делитесь в комментариях своими советами!
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5🔥3👍2😍1
This media is not supported in your browser
VIEW IN TELEGRAM
Понимать код, а не копировать
Привет, это Катя, Flutter Dev Friflex. Сегодня — короткая и практичная заметка о том, почему важно понимать, что делает каждое поле и компонент в проекте, регулярно «проваливаться» в пакеты и отслеживать версии, чтобы избежать сюрпризов в проде.
Почему это критично?
▪️Непонимание контракта поля/метода = баги, неожиданные побочные эффекты, уязвимости
▪️Непроверенные апдейты зависимости = сломанные сборки и runtime‑ошибки
▪️Понимание реализации помогает правильно тестировать, оптимизировать и писать корректную миграцию при изменениях
Куда смотреть?
▫️pub.dev: дата релиза, репозиторий, example, issue tracker
▫️GitHub: README, CHANGELOG.md, Releases/Tags, open/closed issues и PR
▫️Исходники: «Go to definition» в IDE, искать @deprecated, читать реализацию конструктора/методов
▫️Тесты и пример в пакете — часто показывают ожидаемое поведение
На что обращать внимание в поле/компоненте?
▪️Контракт: допустимые входы/выходы, nullable/required, default‑значения
▪️Эффекты: I/O, глобальное состояние, запуск таймеров, необходимость dispose()
▪️Производительность: rebuild/rerender cost, аллокации, потокобезопасность
▪️Депрексации и migration notes: @deprecated и changelog
Практики по версиям и апдейтам
▫️Понимай major = breaking changes. Читай CHANGELOG перед апдейтом
▫️Используй pubspec.lock для воспроизводимости билдов.
Команды: flutter pub outdated; flutter pub deps --style=compact
▫️CI: автоматические тесты после обновления зависимостей
Краткий процесс обновления зависимости
▪️Исследовать пакет (README, changelog, issues, example)
▪️В feature‑ветке обновить зависимость и запустить flutter pub get
▪️Прогнать unit & integration тесты локально и в CI
▪️Развернуть на стейдже
▪️Мониторинг (Crashlytics/Sentry)
▪️Быстрый откат при регрессии
Культура в команде
▫️Составить шаблон PR
▫️Назначать владельца критичных библиотек
▫️Регулярный dependency health check (реально желательно делать)
▫️Обучать команду читать исходники и миграционные заметки
Какие еще практики и инструменты вы используете, чтобы безопасно работать со сторонними зависимостями и глубоко понимать чужой код?
Привет, это Катя, Flutter Dev Friflex. Сегодня — короткая и практичная заметка о том, почему важно понимать, что делает каждое поле и компонент в проекте, регулярно «проваливаться» в пакеты и отслеживать версии, чтобы избежать сюрпризов в проде.
Почему это критично?
▪️Непонимание контракта поля/метода = баги, неожиданные побочные эффекты, уязвимости
▪️Непроверенные апдейты зависимости = сломанные сборки и runtime‑ошибки
▪️Понимание реализации помогает правильно тестировать, оптимизировать и писать корректную миграцию при изменениях
Куда смотреть?
▫️pub.dev: дата релиза, репозиторий, example, issue tracker
▫️GitHub: README, CHANGELOG.md, Releases/Tags, open/closed issues и PR
▫️Исходники: «Go to definition» в IDE, искать @deprecated, читать реализацию конструктора/методов
▫️Тесты и пример в пакете — часто показывают ожидаемое поведение
На что обращать внимание в поле/компоненте?
▪️Контракт: допустимые входы/выходы, nullable/required, default‑значения
▪️Эффекты: I/O, глобальное состояние, запуск таймеров, необходимость dispose()
▪️Производительность: rebuild/rerender cost, аллокации, потокобезопасность
▪️Депрексации и migration notes: @deprecated и changelog
Практики по версиям и апдейтам
▫️Понимай major = breaking changes. Читай CHANGELOG перед апдейтом
▫️Используй pubspec.lock для воспроизводимости билдов.
Команды: flutter pub outdated; flutter pub deps --style=compact
▫️CI: автоматические тесты после обновления зависимостей
Краткий процесс обновления зависимости
▪️Исследовать пакет (README, changelog, issues, example)
▪️В feature‑ветке обновить зависимость и запустить flutter pub get
▪️Прогнать unit & integration тесты локально и в CI
▪️Развернуть на стейдже
▪️Мониторинг (Crashlytics/Sentry)
▪️Быстрый откат при регрессии
Культура в команде
▫️Составить шаблон PR
▫️Назначать владельца критичных библиотек
▫️Регулярный dependency health check (реально желательно делать)
▫️Обучать команду читать исходники и миграционные заметки
Какие еще практики и инструменты вы используете, чтобы безопасно работать со сторонними зависимостями и глубоко понимать чужой код?
❤4🔥3🎉1
Один из самых частых запросов бизнеса — отобразить важные документы внутри приложения. Это может быть все, что угодно: от политики конфиденциальности и правил сервиса до персональных документов пользователей. И как показывает практика, чаще всего такие документы приходят в формате pdf.
Сегодня поговорим о том, как удобно отображать pdf-файлы во Flutter-приложении.
На pub.dev можно найти несколько похожих плагинов для показа pdf-файлов в приложении. Но сегодня рассмотрим один из самых популярных и мною любимых плагинов — syncfusion_flutter_pdfviewer.
Первое, что привлекает в этой библиотеке — возможность открыть файл из разных источников, не только из внутреннего хранилища. Рассмотрим разные варианты.
1️⃣
SfPdfViewer.networkЭтот метод позволяет загрузить файл по ссылке, достаточно передать соответствующий url. И что самое удобное — вы легко можете открыть даже защищенный паролем файл, так как метод дает возможность передать
passwordreturn Scaffold(
body: SfPdfViewer.network(
'https://cdn.syncfusion.com/content/PDFViewer/encrypted.pdf',
password: 'syncfusion',
),
);
2️⃣
SfPdfViewer.asset
Здесь можно открыть любой файл, вложенный в assets проектаreturn Scaffold(body: SfPdfViewer.asset('assets/files/test_file.pdf'))
3️⃣
SfPdfViewer.fileЭтот виджет дает возможность отобразить файл из локального хранилища устройства по пути
return Scaffold(
body: SfPdfViewer.file(
File('path_to_your_local_file'),
),
);
4️⃣
SfPdfViewer.memoryА этот позволяет отобразить файл, представленный в байтах
return Scaffold(
body: FutureBuilder(
future: _loadFromAsset('assets/files/test_file.pdf'),
builder: (context, snapshot) {
if (snapshot.hasData) {
return SfPdfViewer.memory(snapshot.data!);
} else {
return const CircularProgressIndicator();
}
},
),
);
...
Future<Uint8List> _loadFromAsset(String path) async {
final data = await rootBundle.load(path);
return data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
}
Еще одна причина попробовать этот плагин — вид файла можно легко настраивать с помощью дополнительных параметров. Например, можно задать начальные значения страницы и зума —
initialPageNumber и initialZoomLevel. А также цвет выделенного текста при поиске — otherSearchTextHighlightColor и currentSearchTextHighlightColorSfPdfViewer.network(
'https://cdn.syncfusion.com/content/PDFViewer/encrypted.pdf',
password: 'syncfusion',
initialPageNumber: 1,
initialZoomLevel: 1.0,
otherSearchTextHighlightColor: Colors.green.withValues(alpha: 0.5),
currentSearchTextHighlightColor: Colors.blue.withValues(alpha: 0.5),
),
Продолжение — в комментариях 👇
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥11❤4💯2❤🔥1🆒1
Привет, это Анна, Flutter Team Lead Friflex. В этой статье разобрала, как во Flutter реализовать поддержку deeplink-ов и универсальных ссылок и как управлять ими на уровне платформы.
Please open Telegram to view this post
VIEW IN TELEGRAM
Хабр
Deeplink-и во Flutter: динамические ссылки и app_links
Привет! Меня зовут Анна Ахлестова, я Flutter Team Lead в компании Friflex . Мобильные приложения, в том числе на Flutter, позволяют настраивать обработку различных ссылок. В этой статье я разберу, как...
🔥7❤4💯2
Сегодня хочу поговорить о довольно интересной задачей, с которой я столкнулась в разработке — как сделать так, чтобы на экране одновременно отображалось несколько модальных окон и при этом они не блокировали друг друга.
Суть проблемы
Стандартное поведение модальных окон во Flutter построено так, что каждое новое окно блокирует предыдущее. Когда вы вызываете showDialog или showModalBottomSheet, появляется затемненный фон (barrier). И даже если его сделать прозрачным, то все равно блокировка, которая не дает взаимодействовать с контентом под фоном, остается. Это классическое поведение модальных окон, но что если нужно открыть несколько окон одновременно и работать с каждым из них?
Первый подход: Stack с позиционированием
Самый очевидный и гибкий способ — отказаться от стандартных диалогов и построить свою собственную систему управления окнами. Основная идея заключается в использовании виджета Stack, в котором мы будем размещать наши модальные окна с помощью Positioned.
Можно создать специальный менеджер, который будет оборачивать все приложение или отдельный экран. Этот менеджер хранит список всех открытых окон и отрисовывает их поверх основного контента. Каждое окно — это отдельный виджет с собственными координатами и размером.
Второй подход: Overlay API
Flutter предоставляет более низкоуровневый инструмент для работы со слоями — Overlay. Это та самая система, которую Flutter использует для отображения диалогов, снекбаров и прочих всплывающих элементов.
Идея в том, чтобы создавать OverlayEntry для каждого нового окна и вставлять его в оверлей. Преимущество этого подхода в том, что окна не ограничены размерами родительского виджета — они существуют на уровне всего приложения.
Для реализации нужно получить доступ к Overlay через контекст, создать OverlayEntry с описанием виджета окна и вставить его. При закрытии окна не забываем удалить entry из оверлея и очистить ссылки.
Я сейчас выбираю между этими вариантами. Суть в том, что:
◾️Stack-подход проще в реализации и отладке, вся логика находится в одном месте, легко управлять состоянием через обычный StatefulWidget
◾️Overlay-подход более мощный и гибкий, но требует большего внимания к управлению жизненным циклом
А вы сталкивались с необходимостью показывать несколько модальных окон одновременно? Какой вариант использовали — Stack, Overlay или, может быть, какое-то готовое решение?
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5❤2🔥2