Flutter Pulse
613 subscribers
379 photos
831 links
На канале будут новости про flutter с сайтов, информация об обновлении пакетов, а также авторский контент.
Download Telegram
Ждём... или используем скелетную анимацию?

При загрузке контента важно сделать ожидание для пользователя максимально комфортным. Есть два основных способа сделать это: использовать стандартный индикатор загрузки или скелетную анимацию.

Индикатор загрузки - простой и понятный способ показать, что контент загружается. Flutter предоставляет встроенный виджет CircularProgressIndicator.adaptive(), который адаптируется под разные платформы.

// Создает индикатор, который является 
// [CupertinoActivityIndicator] на iOS
// [CircularProgressIndicator] на других платформах
CircularProgressIndicator.adaptive();


Для более широких возможностей можно использовать пакеты, такие как:
- sleek_circular_slider
- flutter_spinkit

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

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

Для реализации скелетной анимации можно использовать пакет better_skeleton.

Оцените новую рубрику и напишите своё мнение в комментарии! 🤔💬

Все подобные новости можно найти по хэштегу #FlutterPulseTips

#flutter #dart #flutterpulse #FlutterPulseTips #MobileDevelopment #UIUX #LoadingAnimation #AppDevelopment #FlutterTips
👍1
Форматирование JSON с помощью Dart

Привет, разработчики! 👋 Сегодня мы рассмотрим полезный совет по работе с JSON в Dart. Вы узнаете, как красиво напечатать JSON-строку, сделав её более читаемой и удобной для отладки 🛠️

Проблема: JSON-данные часто приходят в компактном, неформатированном виде, что затрудняет их чтение и анализ.

Решение: Используйте класс JsonEncoder из пакета dart:convert для форматирования JSON.


import 'dart:convert';

// Создаём кодировщик с отступами для форматирования
var encoder = const JsonEncoder.withIndent(' ');
// Преобразуем данные в красиво отформатированную строку
String prettyprint = encoder.convert(data);


Этот простой код позволяет превратить нечитаемую JSON-строку в структурированный и понятный формат с отступами 🌟

Оцените эту рубрику и напишите в комментариях, какие темы вам было бы интересно разобрать в следующих выпусках! 💬

Все подобные новости вы можете найти по хэштегу #FlutterPulseTips

#flutter #dart #flutterpulse #FlutterPulseTips #JSON #DartTips #FlutterTips #CodingTips #AppDevelopment #MobileDevelopment
👍31
Изучаем OverflowBar: Легкое управление адаптивными строками и столбцами

Привет, разработчики Flutter! 👋 Вы когда-нибудь сталкивались с проблемой, когда содержимое строки или столбца выходит за пределы экрана? 🤔 Сегодня мы рассмотрим OverflowBar - удобный виджет, который помогает легко решить эту проблему! 💡

Что такое OverflowBar?
OverflowBar - это виджет, который располагает своих потомков в строке, если хватает места, или в столбце, если места недостаточно. 📐 Это особенно полезно для создания адаптивных интерфейсов, которые корректно отображаются на разных устройствах и в различных ориентациях экрана.

Пример использования:



OverflowBar(
children: [
Image.asset('asset/image.jpg'), // Загружаем изображение из assets
const Card(
child: Text('My Title'), // Отображаем текст внутри карточки
),
],
);



Как видно из примера, OverflowBar автоматически определяет доступное пространство и перераспределяет элементы при необходимости. 🔄

Ключевые особенности:
- Автоматическое обнаружение переполнения и перераспределение элементов 🔍
- Возможность использования вместе с виджетом Wrap 🌟
- Гибкость в управлении выравниванием переполненных элементов ⚖️

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

👉 Оцените новую рубрику #FlutterPulseTips и оставьте свои отзывы! 💬

Все подобные новости вы можете найти по хэштегу #FlutterPulseTips.

#flutter #dart #flutterpulse #FlutterPulseTips #MobileDevelopment #UIUX #AppDevelopment #CodingTips
OverflowBar или Wrap?
В чем основные различия между этими двумя виджетами Flutter? 🤔

При создании адаптивных интерфейсов в Flutter часто возникает вопрос о том, какой виджет использовать для размещения дочерних элементов: OverflowBar или Wrap? Давайте разберемся в их основных различиях. 🔍



_buildTestA(BuildContext context) => OverflowBar(
children: [
Container(width: 300, height: 100, color: Colors.blue),
const Card(
margin: EdgeInsets.all(32),
child: Text('My Title lorem lorem lorem'),
),
Expanded(child: Container(height: 100, color: Colors.red)),
],
);

_buildTestB(BuildContext context) => Wrap(
children: [
Container(width: 300, height: 100, color: Colors.blue),
const Card(
margin: EdgeInsets.all(32),
child: Text('My Title lorem lorem lorem'),
),
Expanded(child: Container(height: 100, color: Colors.red)),
],
);



OverflowBar и Wrap имеют разные подходы к размещению дочерних элементов. OverflowBar предназначен для размещения элементов в одной строке и не переносит их на новую строку, если они не помещаются. Wrap, наоборот, переносит элементы на новую строку, если они не помещаются в доступное пространство. 🌟

Оцените новую рубрику и напишите в комментариях, насколько она вам полезна! 👍💬

Все подобные новости можно найти по хэштегу #FlutterPulseTips. 🔍

#flutter #dart #flutterpulse #FlutterPulseTips #mobiledevelopment #appdevelopment #uiux #programmingtips
👍2🔥2
Центрирование формы без скрытия полей при открытом клавиатуре

Привет, подписчики! 👋 Сегодня мы рассмотрим полезный совет по Flutter, который поможет вам улучшить пользовательский опыт в ваших приложениях. 📱💡

Проблема: Когда клавиатура открывается, поля формы могут быть скрыты, что затрудняет ввод данных пользователем. 😕

Решение: Использовать Scaffold с параметром resizeToAvoidBottomInset: true и обернуть форму в SingleChildScrollView. 📝



Scaffold(
resizeToAvoidBottomInset: true, // Изменяет размер при открытии клавиатуры
body: Form(
key: _formKey,
child: SingleChildScrollView( // Позволяет прокручивать содержимое
child: SizedBox(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center, // Центрирует содержимое
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Spacer(flex: 1), // Гибкое пространство сверху
TextFormField(...), // Поля формы
TextFormField(...),
const Spacer(flex: 1), // Гибкое пространство снизу
],
),
),
),
),
)



Как это работает:
- resizeToAvoidBottomInset: true заставляет Scaffold изменять размер при открытии клавиатуры. 🔄
- SingleChildScrollView позволяет прокручивать содержимое формы, если оно не помещается на экране. 🔄
- Spacer с гибким размером (flex: 1) обеспечивает равномерное распределение пространства сверху и снизу формы. ⚖️

👍 Оцените новую рубрику и напишите в комментариях, какие темы вам интересны! 💬

Все подобные новости можно найти по хэштегу #FlutterPulseTips. 🔍

#flutter #dart #flutterpulse #FlutterPulseTips #MobileDev #UIUX #AppDevelopment #CodingTips
👍41🔥1🤯1
Круглый аватар с границей
Круглый аватар не имеет границы, но есть быстрый способ добавить её!

Если вы не хотите переписывать виджет CircleAvatar...
Просто оберните его ещё в один или используйте Container с градиентом.



CircleAvatar(
radius: radius + 2, // Увеличиваем радиус для границы
backgroundColor: borderColor, // Цвет границы
child: CircleAvatar(
radius: radius, // Радиус внутреннего аватара
backgroundImage: NetworkImage(url), // Изображение из сети
),
);



Оцените новую рубрику лайком 👍 и подпишитесь, чтобы не пропустить новые советы! 😉
Все подобные новости можно найти по хэштегу #FlutterPulseTips
#flutter #dart #flutterpulse #FlutterPulseTips #mobiledev #appdevelopment #uiux #codingtips
👍3
Создаем собственный экран ошибок

Вам надоело видеть красный или серый экран при возникновении ошибки? 🤔

Это поведение Flutter-приложения по умолчанию. 📱

Примечание: Если вы хотите, чтобы Flutter перестал показывать красный экран в режиме отладки или серый в production-режиме, просто удалите функцию presentError. 💡

Вы можете переопределить виджет ошибки по умолчанию или вообще не показывать ничего... 🤷‍♂️

Хорошим решением может быть перенаправление пользователя и отображение ошибки в виде всплывающего сообщения. 📢



void main() {
FlutterError.onError = (FlutterErrorDetails details) {
FlutterError.presentError(details); // Показываем ошибку
};
runApp(const MyApp());
}

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

@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
routes: routes,
initialRoute: 'route1',
builder: (context, widget) {
ErrorWidget.builder = (FlutterErrorDetails errorDetails) {
Widget error = Text('...rendering error... : ${errorDetails.summary}');
if (widget is Scaffold || widget is Navigator) {
error = Scaffold(body: Center(child: error));
}
return error;
};
return widget;
},
);
}
}



Оцените нашу новую рубрику! 👍💬 Оставляйте ваши отзывы в комментариях! 💬👇

Все подобные новости можно найти по хэштегу #FlutterPulseTips

#flutter #dart #flutterpulse #FlutterPulseTips #MobileDevelopment #AppDevelopment #ErrorHandling #CustomErrorScreen #FlutterTips
👍2
Создаём круглый индикатор прогресса
Привет, подписчики! 👋 Сегодня мы рассмотрим интересный Flutter-трюк, который поможет вам создать круглый индикатор прогресса с помощью ClipRRect 🌟

Вы можете использовать виджет ClipRRect, чтобы создать круглый индикатор прогресса. Для этого нужно обернуть LinearProgressIndicator в ClipRRect и задать ему радиус границы 🌈



ClipRRect(
borderRadius: const BorderRadius.all(Radius.circular(10)),
child: LinearProgressIndicator(
minHeight: 14,
value: progress, // текущий прогресс
color: Colors.red, // цвет прогресса
backgroundColor: Colors.white, // фон индикатора
),
),



В этом примере мы используем LinearProgressIndicator с minHeight равным 14 и оборачиваем его в ClipRRect с радиусом 10, чтобы получить круглый индикатор прогресса 🔴⚪️

Оцените новую рубрику и напишите в комментариях, какие темы вам интересны 🔥

Все подобные новости можно найти по хэштегу #FlutterPulseTips 🤓
#flutter #dart #flutterpulse #FlutterPulseTips #MobileDevelopment #UIUX #ProgressIndicator #FlutterTips #CodingTricks #AppDevelopment
👍2
Скачивание файла из Firebase и отслеживание прогресса

Привет, разработчики Flutter! 👋 Сегодня мы рассмотрим полезный совет по загрузке файлов из Firebase Storage и отслеживанию прогресса загрузки. 📈

Код для скачивания файла:


Stream<TaskSnapshot> downloadFile(String path) async* {
if (await Permission.storage.request().isDenied) {
throw "Вы должны принять разрешение на запись";
}
var fileRef = storage.ref().child(path);
var fileName = fileRef.name;
Directory directory;
if (Platform.isAndroid) {
directory = Directory("/storage/emulated/0/Download");
} else {
directory = (await getExternalStorageDirectory())!;
}
final File destinationFile = File('${directory.path}/$fileName');
if (destinationFile.existsSync()) {
destinationFile.deleteSync();
}
destinationFile.createSync();
var task = fileRef.writeToFile(destinationFile);
yield* task.asStream();
}



Ключевые моменты:
- Проверка разрешений: Используем permission_handler для проверки разрешения на доступ к хранилищу.
- Сохранение в папку загрузок: Файл сохраняется в папку "Download" на Android.
- Замена существующего файла: Если файл уже существует, он будет удален и заменен новым.
- Отслеживание прогресса: Используем yield* для передачи событий из задачи в наш поток, что позволяет отображать прогресс загрузки в приложении.

Чтобы получить текущий прогресс, можно использовать:


var progress = task.bytesTransferred / task.totalBytes * 100;



Оцените нашу новую рубрику советов по Flutter! 👍 Ваши отзывы помогут нам сделать ее еще лучше. 💬

Все подобные советы вы можете найти по хэштегу #FlutterPulseTips.

#flutter #dart #flutterpulse #FlutterPulseTips #Firebase #MobileDevelopment #FlutterTips #AppDevelopment #CodingTips
👍1
Firestore: конфигурация из нативных приложений

Вы, возможно, пропустили это... Плагин Firebase может использовать конфигурацию напрямую на стороне Dart!

Шаги по настройке:

1. Создайте несколько окружений Firebase для разработки/стадии/продакшена, используя только Dart.
Создайте 3 файла в папке runners. Один для каждой среды.

2. Создайте несколько файлов конфигурации Flavors.
Также сгенерируйте все файлы FirebaseOptions, используя flutterFire cli.

3. Удалите запуск из вашего main.dart и добавьте это:


Future<void> runWrapperApp(FlavorConfig config) async {
// Инициализируйте конфигурацию приложения здесь
// Например, установите уровень журнала на основе среды
final firebaseApp = await Firebase.initializeApp(
options: config.firebaseConfig,
);
runApp(MyApp());
}



4. Запустите приложение:


flutter run -t lib/runners/main_dev.dart



Важно:
- FlutterFire cli добавляет нативную зависимость на iOS/Android.
- Удалите конфигурацию Firebase из папок android и iOS.
- На Android удалите службы Google из build.gradle.

Оцените новую рубрику! 👍 Оставляйте ваши отзывы в комментариях! 💬

Все подобные новости можно найти по хэштегу #FlutterPulseTips
#flutter #dart #flutterpulse #FlutterPulseTips #Firestore #Firebase #FlutterTips #MobileDevelopment #AppDevelopment
👍1
Как создать список чекбоксов с помощью CheckboxListTile

Привет, подписчики! 👋 Сегодня мы рассмотрим, как легко создать список чекбоксов в вашем Flutter-приложении, используя виджет CheckboxListTile. 📝

Преимущества CheckboxListTile:
- Упрощает создание списков с чекбоксами
- Позволяет легко управлять состоянием выбранных элементов
- Поддерживает стандартный стиль Material Design

Пример кода:


class SkillsFilterList extends StatelessWidget {
final SkillsFilter skillsFilter;
final Function() onChanged;

const SkillsFilterList({
Key? key,
required this.skillsFilter,
required this.onChanged,
}) : super(key: key);

@override
Widget build(BuildContext context) {
return ListView.separated(
shrinkWrap: true,
physics: const BouncingScrollPhysics(),
itemCount: skillsFilter.value.length,
separatorBuilder: (context, index) => const SizedBox.shrink(),
itemBuilder: (context, index) {
final skill = this.skillsFilter.value[index];
return ListTileTheme(
contentPadding: EdgeInsets.all(0),
child: CheckboxListTile(
dense: true,
title: Text(skill.scopeName),
value: skill.chosed,
onChanged: (skill) {
skillsFilter.select(skill);
onChanged();
},
),
);
},
);
}
}



Ключевые моменты:
ListView.separated используется для создания списка с разделителями
CheckboxListTile упрощает создание элемента списка с чекбоксом и текстом
✦ Свойство onChanged обрабатывает изменения состояния чекбокса

Оцените эту рубрику и напишите в комментариях, какие темы вы хотели бы видеть в будущих выпусках! 💬

Все подобные новости можно найти по хэштегу #FlutterPulseTips

#flutter #dart #flutterpulse #FlutterPulseTips #MobileDev #UIUX #FlutterTips #AppDevelopment #CodingTips
👍41
Эффективная передача стиля текста виджетам

Привет, разработчики Flutter! 👋 Сегодня мы поделимся с вами полезным советом о том, как эффективно передавать стиль текста вашим виджетам. 📝

Вы когда-нибудь сталкивались с ситуацией, когда приходилось копировать стиль текста для дочерних элементов? 🤔 Теперь вы можете этого избежать! 😉

Использование DefaultTextStyle.merge


class MyWidget extends StatelessWidget {
final Widget title;

const TheBestCustomWidget({
super.key,
required this.title,
});

@override
Widget build(BuildContext context) {
return WidgetContainer(
children: [
DefaultTextStyle.merge(
style: Theme.of(context).textTheme.headlineMedium,
child: title,
),
],
);
}
}



MyWidget(
title: Text(
'Signup now',
style: Theme.of(context).textTheme.headlineLarge.copyWith(
color: Theme.of(context).colorScheme.onBackground,
),
),
)



MyWidget(
title: Text(
'Signup now',
style: TextStyle(
color: Theme.of(context).colorScheme.onBackground,
),
),
)


Преимущества использования DefaultTextStyle.merge:

• Позволяет задать только те свойства текста, которые вы хотите переопределить при использовании вашего виджета.
• Упрощает код и делает его более читаемым.

👍 Оцените новую рубрику FlutterPulseTips и поделитесь своими мыслями! 🤔

Все подобные новости можно найти по хэштегу #FlutterPulseTips

#flutter #dart #flutterpulse #FlutterPulseTips #MobileDevelopment #UIUX #CodingTips #AppDevelopment
👍1
Создай расширение темы
Упростите доступ к свойствам темы вашего приложения 💻

Расширение темы позволяет упростить доступ к свойствам темы вашего приложения. Для этого нужно создать расширение класса BuildContext.



extension ApparenceKitThemeExt on BuildContext {
ApparenceKitColors get colors => Theme.of(this).extension<ApparenceKitColors>()!;
// Получение цветов темы
TextTheme get textTheme => Theme.of(this).textTheme;
// Получение текстовой темы
ApparenceKitTextTheme get fonts => Theme.of(this).extension<ApparenceKitTextTheme>()!;
// Получение шрифтов темы
ThemeData get theme => Theme.of(this);
// Получение данных темы
Brightness get brightness => Theme.of(this).brightness;
// Получение яркости темы
ApparenceKitThemeData get kitTheme => ThemeProvider.of(this).current.data;
// Получение данных темы ApparenceKit
}



Пример использования

До: сложный доступ к свойствам темы


class MyWidget extends StatelessWidget {
const MyWidget({super.key});

@override
Widget build(BuildContext context) {
return Container(
color: Theme.of(context).colorScheme.primary,
);
}
}



После: упрощенный доступ с расширением


class MyWidget extends StatelessWidget {
const MyWidget({super.key});

@override
Widget build(BuildContext context) {
return Container(
color: context.colors.primary,
);
}
}



Оцените новую рубрику по достоинству! 👍💬 Оставляйте ваши отзывы и предложения в комментариях! 💬👇

Все подобные новости можно найти по хэштегу #FlutterPulseTips

#flutter #dart #flutterpulse #FlutterPulseTips #MobileDevelopment #UIUX #CodingTips #AppDevelopment #SoftwareDevelopment
👍4
Локальная база данных
Когда вы хотите, чтобы ваше приложение работало офлайн 🔄

Шаг 1: Использование пакета Drift
Для работы с локальной базой данных мы будем использовать пакет Drift. 📦


dart pub add drift
dart pub add drift_flutter
dart pub add drift_dev



Шаг 2: Создание базы данных


@DriftDatabase(tables: [TaskTable])
class Database extends $Database {
Database([QueryExecutor? e]) : super(e ?? driftDatabase(
name: 'todo-app',
native: const DriftNativeOptions(),
databaseDirectory: getApplicationSupportDirectory,
));

@override
int get schemaVersion => 2; // Версия базы данных

@override
MigrationStrategy get migration {
return MigrationStrategy(
onCreate: (m) async {
await m.createAll();
// Добавьте миграции здесь, если версия новая
},
);
}
}



Шаг 3: Создание таблицы


@DataClassName('TaskEntry')
class TaskTable extends Table {
IntColumn get id => integer().autoIncrement()();
TextColumn get description => text()();

// Добавьте ваши запросы здесь
static Stream<List<TaskEntry>> getAllItems(Database database) =>
database.select(database.taskTable).watch();
}



Шаг 3: Создание или редактирование build.yaml
в корневой папке вашего Flutter-приложения 📁


targets:
$default:
builders:
drift_dev:
# Эти опции изменяют способ генерации кода
options:
databases:
default: lib/modules/drift/database.dart
sql:
dialect: sqlite
options:
version: "3.38"
modules: [fts5]


Запустите сборщик, чтобы регенерировать схему базы данных 🔄

Оцените новую рубрику! 👍💬
Все подобные новости можно найти по хэштегу #FlutterPulseTips
#flutter #dart #flutterpulse #FlutterPulseTips #MobileDevelopment #LocalDatabase #DriftPackage #FlutterTips #AppDevelopment
👍2🔥1
Сделайте текст выбираемым

По умолчанию текст не является выбираемым. 🤔

Почему? Виджет SelectionArea позволяет выбирать текст, указывая Flutter обрабатывать отрисовку и взаимодействие для выбора текста. 📝


return MaterialApp(
home: SelectionArea(
child: Scaffold(
appBar: AppBar(title: const Text('SelectionArea Sample')),
body: const Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('Row 1'),
Text('Row 2'),
Text('Row 3'),
],
),
),
),
),
);


ИЛИ 🔄


const SelectableText(
'Hello! How are you?',
textAlign: TextAlign.center,
style: TextStyle(fontWeight: FontWeight.bold),
)


Используйте SelectableText вместо Text 🔁

Как выбрать между SelectionArea и SelectableText? 🤔
Используйте selectionArea, если вы хотите включить выбор на нескольких виджетах, а не только на тексте. 📚
Для одного текста просто используйте SelectableText 👍

Оцените новую рубрику и напишите своё мнение! 💬

Все подобные новости можно найти по хэштегу #FlutterPulseTips 🔍

#flutter #dart #flutterpulse #FlutterPulseTips #MobileDevelopment #UIUX #CodingTips #AppDevelopment #FlutterTips
5👍1
Показываем версию вашего приложения
Полезно для поддержки клиентов или просто при тестировании новых сборок из магазинов

Отображение версии приложения может быть очень полезным, особенно когда вы тестируете новые сборки или оказываете поддержку клиентам. Для этого нам понадобится пакет package_info_plus. Установите его, добавив в ваш pubspec.yaml:


dependencies:
package_info_plus: ^latest_version



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


class AppVersion extends StatelessWidget {
const AppVersion({super.key});

Future<PackageInfo> _getAppVersion() async {
// Получаем информацию о пакете приложения
final packageInfo = await PackageInfo.fromPlatform();
return packageInfo;
}

@override
Widget build(BuildContext context) {
return FutureBuilder<PackageInfo>(
future: _getAppVersion(),
builder: (context, snapshot) {
// Проверяем состояние загрузки данных
if (snapshot.connectionState == ConnectionState.waiting || snapshot.hasError) {
return const SizedBox.shrink(); // Возвращаем пустой виджет, если данные ещё не загружены или произошла ошибка
} else {
// Отображаем версию приложения и номер сборки
return Text(
"Version ${snapshot.data?.version}(${snapshot.data?.buildNumber})",
textAlign: TextAlign.center,
style: context.textTheme.bodyMedium?.copyWith(
color: context.colors.onBackground.withOpacity(.6),
),
);
}
},
);
}
}



Оцените новую рубрику и напишите в комментариях, насколько она вам полезна! 👍💬

Все подобные новости можно найти по хэштегу #FlutterPulseTips
#flutter #dart #flutterpulse #FlutterPulseTips #MobileDevelopment #AppDevelopment #CodingTips #DevTips
👍1