Создаём круглый индикатор прогресса
Привет, подписчики! 👋 Сегодня мы рассмотрим интересный Flutter-трюк, который поможет вам создать круглый индикатор прогресса с помощью
Вы можете использовать виджет
В этом примере мы используем
Оцените новую рубрику и напишите в комментариях, какие темы вам интересны 🔥
Все подобные новости можно найти по хэштегу #FlutterPulseTips 🤓
#flutter #dart #flutterpulse #FlutterPulseTips #MobileDevelopment #UIUX #ProgressIndicator #FlutterTips #CodingTricks #AppDevelopment
Привет, подписчики! 👋 Сегодня мы рассмотрим интересный 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 и отслеживанию прогресса загрузки. 📈
Код для скачивания файла:
Ключевые моменты:
- Проверка разрешений: Используем
- Сохранение в папку загрузок: Файл сохраняется в папку "Download" на Android.
- Замена существующего файла: Если файл уже существует, он будет удален и заменен новым.
- Отслеживание прогресса: Используем
Чтобы получить текущий прогресс, можно использовать:
Оцените нашу новую рубрику советов по Flutter! 👍 Ваши отзывы помогут нам сделать ее еще лучше. 💬
Все подобные советы вы можете найти по хэштегу #FlutterPulseTips.
#flutter #dart #flutterpulse #FlutterPulseTips #Firebase #MobileDevelopment #FlutterTips #AppDevelopment #CodingTips
Привет, разработчики 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 и добавьте это:
4. Запустите приложение:
Важно:
- FlutterFire cli добавляет нативную зависимость на iOS/Android.
- Удалите конфигурацию Firebase из папок android и iOS.
- На Android удалите службы Google из build.gradle.
Оцените новую рубрику! 👍 Оставляйте ваши отзывы в комментариях! 💬
Все подобные новости можно найти по хэштегу #FlutterPulseTips
#flutter #dart #flutterpulse #FlutterPulseTips #Firestore #Firebase #FlutterTips #MobileDevelopment #AppDevelopment
Вы, возможно, пропустили это... Плагин 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
Оптимизация генерации кода
Ускорьте генерацию кода Flutter ⚡️
Заметка: Что такое генерация кода в Flutter?
Flutter позволяет генерировать шаблонный код с помощью аннотаций над классом/методом.
Это особенно полезно для генерации JSON-объектов (пакет json_serializable) или внедрения сервисов (gate_generator).
Как запустить генерацию кода?
1. Установите пакет build_runner и пакет, генерирующий код (см. примечание выше)
2. Выполните команду:
1 - Создайте файл
Включайте папки, содержащие файлы с аннотациями.
Генераторы кода будут сканировать только эти папки.
Вы можете легко исключать папки или файлы для каждого генератора кода.
Оцените новую рубрику и напишите своё мнение! 👍💬
Все подобные новости можно найти по хэштегу #FlutterPulseTips
#flutter #dart #flutterpulse #FlutterPulseTips #FlutterTips #CodeGeneration #OptimizeCode #FlutterDevelopment #MobileDevelopment #ProgrammingTips #DevelopmentTips
Ускорьте генерацию кода Flutter ⚡️
Заметка: Что такое генерация кода в Flutter?
Flutter позволяет генерировать шаблонный код с помощью аннотаций над классом/методом.
Это особенно полезно для генерации JSON-объектов (пакет json_serializable) или внедрения сервисов (gate_generator).
Как запустить генерацию кода?
1. Установите пакет build_runner и пакет, генерирующий код (см. примечание выше)
2. Выполните команду:
flutter packages pub run build_runner build --delete-conflicting-outputs
1 - Создайте файл
build.yaml
в корне проекта, как этот:
targets:
$default:
builders:
gate_generator:gate_schema:
enabled: true
generate_for:
include:
- "lib/gate/**.dart"
- "lib/services/**/**.dart"
- "lib/data/repositories/**.dart"
- "lib/ui/**/**.dart"
exclude:
- "lib/data/entities/**.freezed.dart"
- "lib/data/entities/**.g.dart"
freezed:
enabled: true
generate_for:
exclude:
- test
include:
- lib/data/entities/**
source_gen|combining_builder:
options:
ignore_for_file:
- "type=lint"
Включайте папки, содержащие файлы с аннотациями.
Генераторы кода будут сканировать только эти папки.
Вы можете легко исключать папки или файлы для каждого генератора кода.
Оцените новую рубрику и напишите своё мнение! 👍💬
Все подобные новости можно найти по хэштегу #FlutterPulseTips
#flutter #dart #flutterpulse #FlutterPulseTips #FlutterTips #CodeGeneration #OptimizeCode #FlutterDevelopment #MobileDevelopment #ProgrammingTips #DevelopmentTips
👍2🔥2
Кнопка с градиентом и анимацией
Привет, подписчики! 👋 Сегодня мы рассмотрим интересный пример создания анимированной кнопки с градиентным фоном во Flutter. 📱✨
Основная идея:
Мы создадим кнопку, у которой при нажатии будет изменяться градиентный фон с анимацией. Для этого мы используем
Код примера:
Как это работает:
1. Мы оборачиваем
2. При нажатии на кнопку запускается анимация, которая изменяет градиент от исходного к целевому.
3.
Перспективы:
- Можно создать собственный объект рендеринга.
- Полностью переработать кнопку без использования
- Расширить
Оцените новую рубрику и напишите в комментариях, что хотели бы увидеть дальше! 👍 Оцените пост и подпишитесь 😉
Все подобные новости можно найти по хэштегу #FlutterPulseTips
#flutter #dart #flutterpulse #FlutterPulseTips #MobileDevelopment #UIUX #Animation #FlutterTips #DartLang #GradientButton #AnimatedButton
Привет, подписчики! 👋 Сегодня мы рассмотрим интересный пример создания анимированной кнопки с градиентным фоном во Flutter. 📱✨
Основная идея:
Мы создадим кнопку, у которой при нажатии будет изменяться градиентный фон с анимацией. Для этого мы используем
AnimatedGradientButton
, который будет обрабатывать анимацию.Код примера:
class AnimatedGradientButton extends StatefulWidget {
final Text? label;
final Gradient gradient;
final Gradient onPushGradient;
final Icon? icon;
final Function()? onPressed;
AnimatedGradientButton({
this.label,
required this.gradient,
required this.onPushGradient,
this.icon,
this.onPressed,
});
@override
_AnimatedGradientButtonState createState() => _AnimatedGradientButtonState();
}
class _AnimatedGradientButtonState extends State<AnimatedGradientButton>
with TickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _animation;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: Duration(milliseconds: 1000),
vsync: this,
);
_animation = CurvedAnimation(curve: Curves.decelerate, parent: _controller);
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _controller,
builder: (context, child) {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(24),
gradient: LinearGradient(
colors: widget.gradient.colors.map((color) => Color.lerp(
color,
widget.onPushGradient.colors[widget.gradient.colors.indexOf(color)],
_animation.value,
)).toList(),
),
),
child: MaterialButton(
onPressed: () {
_controller.forward();
widget.onPressed?.call();
_controller.reverse();
},
child: widget.label,
),
);
},
);
}
}
Как это работает:
1. Мы оборачиваем
MaterialButton
в контейнер с градиентным фоном.2. При нажатии на кнопку запускается анимация, которая изменяет градиент от исходного к целевому.
3.
Color.lerp
используется для плавного перехода между цветами градиента.Перспективы:
- Можно создать собственный объект рендеринга.
- Полностью переработать кнопку без использования
MaterialButton
.- Расширить
ButtonStyleButton
как обычные кнопки.Оцените новую рубрику и напишите в комментариях, что хотели бы увидеть дальше! 👍 Оцените пост и подпишитесь 😉
Все подобные новости можно найти по хэштегу #FlutterPulseTips
#flutter #dart #flutterpulse #FlutterPulseTips #MobileDevelopment #UIUX #Animation #FlutterTips #DartLang #GradientButton #AnimatedButton
🔥2👍1
🚀 Расширяем возможности Flutter с помощью FFI: Вызываем функции из GO!
Привет, Flutter-энтузиасты! Руслан подготовил 🔥горячее видео, которое откроет вам мир межъязыкового взаимодействия. Узнайте, как заставить Dart и Go работать в тандеме через FFI (Foreign Function Interface)!
👉 Смотрите видео здесь:
Расширяем возможности Flutter с помощью FFI. Вызываем функции из GO
В этом выпуске вы узнаете:
🔹 Как передавать строки между Dart и Go (и обратно!)
🔹 Особенности работы с памятью и Garbage Collector
🔹 Магию горутин (goroutine) и defer
🔹 Практические примеры вызова Go-кода из Flutter-приложений
✨ Почему это важно?
Вы сможете использовать сильные стороны Go (например, многопоточность через горутины) в своих Flutter-проектах! Автор наглядно показывает процесс компиляции, преобразования типов и управления памятью.
💡 В следующих выпусках:
- Работа с Rust, Python и C++ через FFI
- Продвинутые техники оптимизации
🔥P.S. Увидите, как Go-горутины ускоряют вычисления в сравнении с Dart-изолятами!
#Flutter #Dart #FlutterPulse #FlutterPulseTips #FlutterPulseYoutube
#FFI #Golang #MobileDevelopment #CrossPlatform
👉 Больше полезного в плейлисте: #FlutterPulseYoutube
Привет, Flutter-энтузиасты! Руслан подготовил 🔥горячее видео, которое откроет вам мир межъязыкового взаимодействия. Узнайте, как заставить Dart и Go работать в тандеме через FFI (Foreign Function Interface)!
👉 Смотрите видео здесь:
Расширяем возможности Flutter с помощью FFI. Вызываем функции из GO
В этом выпуске вы узнаете:
🔹 Как передавать строки между Dart и Go (и обратно!)
🔹 Особенности работы с памятью и Garbage Collector
🔹 Магию горутин (goroutine) и defer
🔹 Практические примеры вызова Go-кода из Flutter-приложений
✨ Почему это важно?
Вы сможете использовать сильные стороны Go (например, многопоточность через горутины) в своих Flutter-проектах! Автор наглядно показывает процесс компиляции, преобразования типов и управления памятью.
💡 В следующих выпусках:
- Работа с Rust, Python и C++ через FFI
- Продвинутые техники оптимизации
🔥
#Flutter #Dart #FlutterPulse #FlutterPulseTips #FlutterPulseYoutube
#FFI #Golang #MobileDevelopment #CrossPlatform
👉 Больше полезного в плейлисте: #FlutterPulseYoutube
Шпаргалка по Dart map
Maps are fast - Карты работают быстро
Карта - это коллекция пар ключ/значение. Значение извлекается из карты с помощью связанного с ним ключа.
В Dart существует 3 типа карт:
- HashMap - неупорядоченная
- LinkedHashMap - упорядоченная по порядку вставки
- SplayTreeMap - упорядоченная по ключам
Преобразование списка в карту
Зачем использовать карту?
Доступ к элементу в списке с использованием
Доступ к элементу или проверка его наличия в карте занимает O(1).
Карты выигрывают в этом
Как создать неизменяемую карту?
https://pub.dev/packages/built_collection - Этот пакет предоставляет способы создания неизменяемых карт (разработан командой Dart).
Функции карты
Оцените новую рубрику! 👍💬
Все подобные новости можно найти по хэштегу #FlutterPulseTips
#flutter #dart #flutterpulse #FlutterPulseTips #DartTips #MobileDevelopment #ProgrammingTips #Coding #FlutterCommunity
Maps are fast - Карты работают быстро
Карта - это коллекция пар ключ/значение. Значение извлекается из карты с помощью связанного с ним ключа.
В Dart существует 3 типа карт:
- HashMap - неупорядоченная
- LinkedHashMap - упорядоченная по порядку вставки
- SplayTreeMap - упорядоченная по ключам
// Простая карта со строковым ключом: строковым значением
var data = {'name': 'John Doe', 'occupation': 'gardener'};
// карта, типизированная с помощью конструктора Map<String, String>()
var data2 = <int, String>{1: 'sky', 2: 'falcon', 3: 'rock'};
Преобразование списка в карту
// преобразование списка в карту
var resultMap = Map.fromIterable(list, key: (v) => v[0], value: (v) => v[1]);
// или
var result = { for (var v in list) v[0]: v[1] };
// или просто используя метод asMap() для автоматического индексирования
var result = ["test","test2","test3"].asMap(); // {0: test, 1: test2, 2: test3}
Зачем использовать карту?
Доступ к элементу в списке с использованием
indexOf
или contains
имеет сложность O(n).Доступ к элементу или проверка его наличия в карте занимает O(1).
Карты выигрывают в этом
Как создать неизменяемую карту?
https://pub.dev/packages/built_collection - Этот пакет предоставляет способы создания неизменяемых карт (разработан командой Dart).
Функции карты
var details = {'Usrname': 'bruce', 'Password': 'mypas'};
// добавление
details['Uid'] = '3802983209A';
// обновление
details.putIfAbsent("Uid", () => "3802983209A");
// преобразование в другую карту
details.map((key, value) => MapEntry(key, "$key:$value"));
// приведение к другому типу
details.cast<int, int>();
// проверка наличия ключа
details.containsKey("key"); // сложность O(1)
// копирование
var copy = {...details};
// обновление
details.update("Usrname", (value) => "joker");
Оцените новую рубрику! 👍💬
Все подобные новости можно найти по хэштегу #FlutterPulseTips
#flutter #dart #flutterpulse #FlutterPulseTips #DartTips #MobileDevelopment #ProgrammingTips #Coding #FlutterCommunity
👍3
Создаем чистую круглую кнопку
Как сделать свою собственную круглую кнопку в Flutter? 🤔
В этом совете мы покажем, как создать красивую и простую круглую кнопку для вашего Flutter-приложения. 📱
Давайте разберем пример кода:
Оцените новую рубрику и напишите свое мнение в комментариях! 💬
Все подобные новости можно найти по хэштегу #FlutterPulseTips
#flutter #dart #flutterpulse #FlutterPulseTips #mobiledevelopment #uiux #fluttertutorial #codingtips
Как сделать свою собственную круглую кнопку в Flutter? 🤔
В этом совете мы покажем, как создать красивую и простую круглую кнопку для вашего Flutter-приложения. 📱
Давайте разберем пример кода:
const CircleButton({
super.key,
required this.bgColor, // Цвет фона кнопки
required this.borderColor, // Цвет границы кнопки
required this.iconColor, // Цвет иконки
required this.onTap, // Обработчик нажатия
required this.radius, // Радиус кнопки
required this.iconSize, // Размер иконки
required this.borderWidth, // Ширина границы
required this.icon, // Иконка
this.disabled = false, // Флаг блокировки кнопки
});
@override
Widget build(BuildContext context) {
return Opacity(
opacity: disabled ? 0.5 : 1, // Изменяем прозрачность, если кнопка заблокирована
child: ClipOval(
child: Material(
color: Colors.transparent, // Прозрачный фон для эффекта Ink
// Ink покажет эффект касания, который вы видите на всех кнопках Flutter
child: Ink(
width: radius,
height: radius,
decoration: BoxDecoration(
shape: BoxShape.circle, // Круглая форма
color: bgColor, // Цвет фона
border: Border.all(color: borderColor, width: borderWidth), // Граница кнопки
),
child: InkWell(
onTap: () {
if (disabled) {
return; // Ничего не делаем, если кнопка заблокирована
}
// Даем легкую вибрационную обратную связь
HapticFeedback.lightImpact();
// Вызываем метод onTap
onTap();
},
child: Icon(icon, color: iconColor, size: iconSize), // Иконка внутри кнопки
),
),
),
),
);
}
Оцените новую рубрику и напишите свое мнение в комментариях! 💬
Все подобные новости можно найти по хэштегу #FlutterPulseTips
#flutter #dart #flutterpulse #FlutterPulseTips #mobiledevelopment #uiux #fluttertutorial #codingtips
👍1
Рисуем и анимируем круглый прогресс-бар с помощью Custom Painter
В этом совете мы рассмотрим, как создать анимированный круглый прогресс-бар, используя виджет
Основные моменты:
1️⃣ Передача анимации в конструктор
2️⃣ При обновлении прогресса мы изменяем начало и конец анимации, а затем запускаем её. Поскольку время загрузки предсказать невозможно, анимация прогресс-бара продолжается после обновления прогресса.
Пример кода:
Оцените новую рубрику и напишите в комментариях, что вы хотели бы увидеть в следующих постах! 👍💬
Все подобные новости можно найти по хэштегу #FlutterPulseTips
#flutter #dart #flutterpulse #FlutterPulseTips #MobileDevelopment #UI #Animation #CustomPainter #ProgressBar #LoadingAnimation #FlutterTips
В этом совете мы рассмотрим, как создать анимированный круглый прогресс-бар, используя виджет
CustomPaint
во Flutter. Такой прогресс-бар можно использовать, например, для индикации загрузки.Основные моменты:
1️⃣ Передача анимации в конструктор
CustomPainter
автоматически вызывает перерисовку.2️⃣ При обновлении прогресса мы изменяем начало и конец анимации, а затем запускаем её. Поскольку время загрузки предсказать невозможно, анимация прогресс-бара продолжается после обновления прогресса.
Пример кода:
class RoundProgressPainter extends CustomPainter {
final double radius;
final double progress;
final Color color;
final Animation<double> animation;
final double strokeWidth;
RoundProgressPainter({
required this.radius,
required this.progress,
required this.color,
required this.animation,
required this.strokeWidth,
}) : super(repaint: animation);
@override
void paint(Canvas canvas, Size size) {
final center = Offset(size.width / 2, size.height / 2);
final progressAngle = math.pi * 2 * progress;
final progressPaint = Paint()
..color = color
..strokeWidth = strokeWidth
..style = PaintingStyle.stroke
..strokeCap = StrokeCap.round;
canvas.drawCircle(
center,
radius - strokeWidth / 2,
Paint()
..color = color.withOpacity(0.1)
..strokeWidth = strokeWidth
..style = PaintingStyle.stroke,
);
canvas.drawArc(
Rect.fromCircle(center: center, radius: radius),
-math.pi / 2,
progressAngle,
false,
progressPaint,
);
}
@override
bool shouldRepaint(RoundProgressPainter oldDelegate) =>
progress != oldDelegate.progress || color != oldDelegate.color;
}
class RoundProgress extends StatefulWidget {
final double radius;
final double progress;
final Color color;
final Widget? child;
final double strokeWidth;
const RoundProgress({
super.key,
required this.radius,
required this.progress,
required this.color,
this.child,
this.strokeWidth = 4.0,
});
@override
_RoundProgressState createState() => _RoundProgressState();
}
class _RoundProgressState extends State<RoundProgress> with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _animation;
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 300),
);
_animation = Tween(begin: 0.0, end: 1.0).animate(
CurvedAnimation(parent: _controller, curve: Curves.decelerate),
);
_controller.forward(from: 0);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
void didUpdateWidget(covariant RoundProgress oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.progress != oldWidget.progress && widget.progress != null) {
_animation = Tween(begin: oldWidget.progress, end: widget.progress).animate(
CurvedAnimation(parent: _controller, curve: Curves.easeIn),
);
_controller.forward(from: 0);
}
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _animation,
builder: (context, child) => CustomPaint(
size: Size(widget.radius * 2, widget.radius * 2),
painter: RoundProgressPainter(
radius: widget.radius,
progress: widget.progress,
color: widget.color,
animation: _animation,
strokeWidth: widget.strokeWidth,
),
child: widget.child,
),
);
}
}
Оцените новую рубрику и напишите в комментариях, что вы хотели бы увидеть в следующих постах! 👍💬
Все подобные новости можно найти по хэштегу #FlutterPulseTips
#flutter #dart #flutterpulse #FlutterPulseTips #MobileDevelopment #UI #Animation #CustomPainter #ProgressBar #LoadingAnimation #FlutterTips
👍2
Правильно называйте свои классы
🤔 Название класса должно отражать его сущность, а не выполняемые им действия! 💡
При именовании классов важно следовать правилу: класс должен называться тем, чем он является, а не тем, что он делает. Это делает ваш код более читаемым и понятным. 📚
👀 Рассмотрим пример на Dart:
✅ В первом примере класс назван
✅ Во втором примере класс назван
👍 Оцените новую рубрику и напишите своё мнение! 💬
Все подобные советы можно найти по хэштегу #FlutterPulseTips
#flutter #dart #flutterpulse #FlutterPulseTips #CodingTips #MobileDevelopment #CleanCode #ProgrammingTips
🤔 Название класса должно отражать его сущность, а не выполняемые им действия! 💡
При именовании классов важно следовать правилу: класс должен называться тем, чем он является, а не тем, что он делает. Это делает ваш код более читаемым и понятным. 📚
👀 Рассмотрим пример на Dart:
class EmailValidator { // Неправильное название, так как оно описывает действие
EmailValidator();
void validate(String email) {
const pattern = r'...'; // Регулярное выражение для проверки email
final regex = RegExp(pattern);
final isValidEmail = regex.hasMatch(email);
if (!isValidEmail) {
throw const EmailException("Email not valid"); // Ошибка, если email не валиден
}
}
}
class Email { // Правильное название, отражает сущность класса
final String _value;
Email(String email) : _value = email.trim();
void validate() {
const pattern = r'...'; // Регулярное выражение для проверки email
final regex = RegExp(pattern);
final isValidEmail = regex.hasMatch(_value);
if (!isValidEmail) {
throw const EmailException("Email not valid"); // Ошибка, если email не валиден
}
}
}
✅ В первом примере класс назван
EmailValidator
, что указывает на выполняемое действие (валидация email). Это не отражает суть класса. 🔴✅ Во втором примере класс назван
Email
, что отражает его сущность (email). Это делает код более логичным и понятным. 🟢👍 Оцените новую рубрику и напишите своё мнение! 💬
Все подобные советы можно найти по хэштегу #FlutterPulseTips
#flutter #dart #flutterpulse #FlutterPulseTips #CodingTips #MobileDevelopment #CleanCode #ProgrammingTips
Эффективная передача стиля текста виджетам
Привет, разработчики Flutter! 👋 Сегодня мы поделимся с вами полезным советом о том, как эффективно передавать стиль текста вашим виджетам. 📝
Вы когда-нибудь сталкивались с ситуацией, когда приходилось копировать стиль текста для дочерних элементов? 🤔 Теперь вы можете этого избежать! 😉
Использование DefaultTextStyle.merge
Преимущества использования DefaultTextStyle.merge:
• Позволяет задать только те свойства текста, которые вы хотите переопределить при использовании вашего виджета.
• Упрощает код и делает его более читаемым.
👍 Оцените новую рубрику FlutterPulseTips и поделитесь своими мыслями! 🤔
Все подобные новости можно найти по хэштегу #FlutterPulseTips
#flutter #dart #flutterpulse #FlutterPulseTips #MobileDevelopment #UIUX #CodingTips #AppDevelopment
Привет, разработчики 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
Как протестировать Изолят
Запуск функции изолята в модульных тестах
При написании модульных тестов для Flutter-приложений часто возникает необходимость протестировать функции, выполняющиеся в изоляте. Изолят - это отдельный поток выполнения в Dart, который может выполняться параллельно с основным потоком. Однако тестирование таких функций может быть проблематичным.
Рассмотрим пример неправильного тестирования изолята:
Такой тест зависнет и никогда не завершится, поскольку функция
Решение: Используйте tester.runAsync() для запуска асинхронного кода в тесте:
Таким образом, вы сможете корректно протестировать функции, выполняющиеся в изоляте.
Оцените новую рубрику и напишите своё мнение! 👍💬
Все подобные новости можно найти по хэштегу #FlutterPulseTips
#flutter #dart #flutterpulse #FlutterPulseTips #MobileDevelopment #Testing #Isolate #FlutterTips #DartTips
Запуск функции изолята в модульных тестах
При написании модульных тестов для Flutter-приложений часто возникает необходимость протестировать функции, выполняющиеся в изоляте. Изолят - это отдельный поток выполнения в Dart, который может выполняться параллельно с основным потоком. Однако тестирование таких функций может быть проблематичным.
Рассмотрим пример неправильного тестирования изолята:
testWidgets('upload file and save avatar', (tester) async {
final file = await rootBundle.load('assets/images/splashscreen.png');
final bytes = file.buffer.asUint8List();
final xfile = XFile.fromData(bytes);
final jpgData = await compute(_avatarThumbnail, file);
}
// Функция, выполняющаяся в изоляте
Future<Uint8List> _avatarThumbnail(XFile file) {
return file.toJpeg(file, 300, 80);
}
Такой тест зависнет и никогда не завершится, поскольку функция
compute
запускает _avatarThumbnail в изоляте, но тест не ожидает завершения изолята.Решение: Используйте tester.runAsync() для запуска асинхронного кода в тесте:
testWidgets('upload file and save avatar', (tester) async {
await tester.runAsync(() async {
final file = await rootBundle.load('assets/images/splashscreen.png');
final bytes = file.buffer.asUint8List();
final xfile = XFile.fromData(bytes);
final jpgData = await compute(_avatarThumbnail, file);
});
});
// Функция, выполняющаяся в изоляте
Future<Uint8List> _avatarThumbnail(XFile file) {
return file.toJpeg(file, 300, 80);
}
Таким образом, вы сможете корректно протестировать функции, выполняющиеся в изоляте.
Оцените новую рубрику и напишите своё мнение! 👍💬
Все подобные новости можно найти по хэштегу #FlutterPulseTips
#flutter #dart #flutterpulse #FlutterPulseTips #MobileDevelopment #Testing #Isolate #FlutterTips #DartTips
👍1
Глупый и умный: создаём "глупый" конструктор и умные фабрики
Привет, друзья! 👋 Сегодня мы поговорим о том, как улучшить ваш код на Flutter/Dart, используя "глупые" конструкторы и умные фабрики. 📈
Что такое "глупый" конструктор?
"Глупый" конструктор - это конструктор, который только присваивает данные. Он не должен делать ничего другого! 🚫
Пример плохого конструктора:
Пример хорошего "глупого" конструктора:
Зачем использовать фабрики?
Фабрики идеально подходят для более сложных присвоений значений. Они позволяют создавать объекты более гибко и читаемо. 🌟
Пример фабрики:
Вывод:
- Конструкторы должны быть "глупыми" и только присваивать данные.
- Для более сложных операций используйте фабрики.
Оцените нашу новую рубрику! 👍 Нам важно ваше мнение. Оставляйте свои комментарии и предложения. 💬
Все подобные новости вы можете найти по хэштегу #FlutterPulseTips
#flutter #dart #flutterpulse #FlutterPulseTips #MobileDevelopment #CodingTips #Programming #SoftwareDevelopment
Привет, друзья! 👋 Сегодня мы поговорим о том, как улучшить ваш код на Flutter/Dart, используя "глупые" конструкторы и умные фабрики. 📈
Что такое "глупый" конструктор?
"Глупый" конструктор - это конструктор, который только присваивает данные. Он не должен делать ничего другого! 🚫
Пример плохого конструктора:
class Device {
String? id;
String? name;
OperatingSystem? platform;
Device({
this.id,
}) :
// Плохая практика - присвоение значений в теле конструктора
name = null,
platform = null {
final deviceInfo = ...; // Получение информации об устройстве
name = deviceInfo.name;
platform = deviceInfo.platform;
}
}
Пример хорошего "глупого" конструктора:
class Device {
String? id;
String name; // Теперь обязательное поле
OperatingSystem platform; // Теперь обязательное поле
Device({
this.id,
required this.name, // Требуем имя устройства
required this.platform, // Требуем платформу устройства
});
}
Зачем использовать фабрики?
Фабрики идеально подходят для более сложных присвоений значений. Они позволяют создавать объекты более гибко и читаемо. 🌟
Пример фабрики:
factory Device.current() {
final deviceInfo = ...; // Получение информации об устройстве
return Device(
name: deviceInfo.name, // Присваиваем имя устройства
platform: deviceInfo.platform, // Присваиваем платформу устройства
);
}
Вывод:
- Конструкторы должны быть "глупыми" и только присваивать данные.
- Для более сложных операций используйте фабрики.
Оцените нашу новую рубрику! 👍 Нам важно ваше мнение. Оставляйте свои комментарии и предложения. 💬
Все подобные новости вы можете найти по хэштегу #FlutterPulseTips
#flutter #dart #flutterpulse #FlutterPulseTips #MobileDevelopment #CodingTips #Programming #SoftwareDevelopment
👍3❤1
Избегайте тестирования с помощью моков
Моки отражают вашу реализацию
Лучшие тесты не отражают вашу реализацию.
Они позволяют рефакторить код, не задумываясь о том, как они работают.
Вы тестируете то, что они возвращают, а не как они это делают.
Таким образом, вы можете рефакторить код, пока они продолжают работать.
Наш тест не знает ничего о том, как мы используем
👋 Прощай, mockito!
Оцените новую рубрику и напишите своё мнение! 👍
Все подобные новости можно найти по хэштегу #FlutterPulseTips
#flutter #dart #flutterpulse #FlutterPulseTips #MobileDevelopment #TestingTips #CodingBestPractices
Моки отражают вашу реализацию
Лучшие тесты не отражают вашу реализацию.
Они позволяют рефакторить код, не задумываясь о том, как они работают.
Вы тестируете то, что они возвращают, а не как они это делают.
Таким образом, вы можете рефакторить код, пока они продолжают работать.
test('on receive message, should dispatch as a notification', () async {
final repository = AppNotificationsRepository(
notificationsApi: fakeNotificationsApi,
notificationPublisher: dispatcher,
);
Notification? receivedNotification;
dispatcher.subscribe((notification) => receivedNotification = notification);
fakeNotificationsApi.sendForegroundMessage(
const RemoteMessage(
data: {
'title': 'title',
'body': 'example body',
},
),
);
await Future.delayed(const Duration(milliseconds: 100));
expect(receivedNotification, isNotNull);
expect(receivedNotification!.title, 'title');
expect(receivedNotification!.body, 'example body');
});
class FakeNotificationsApi implements NotificationsApi {
OnRemoteMessage? _foregroundHandler;
@override
void setForegroundHandler(OnRemoteMessage handler) {
_foregroundHandler = handler;
}
void sendForegroundMessage(RemoteMessage message) {
_foregroundHandler?.call(message);
}
}
Наш тест не знает ничего о том, как мы используем
NotificationsApi
.Mockito
заставил бы нас имитировать каждый метод и проверять, как мы их используем.👋 Прощай, mockito!
Оцените новую рубрику и напишите своё мнение! 👍
Все подобные новости можно найти по хэштегу #FlutterPulseTips
#flutter #dart #flutterpulse #FlutterPulseTips #MobileDevelopment #TestingTips #CodingBestPractices
💯2
Создаём кастомную панель приложений
Потому что вы можете 😉
Вы можете создать кастомную AppBar, реализовав интерфейс PreferredSizeWidget. Это даст вам гибкость в настройке панели приложений под нужды вашего приложения.
Чтобы использовать эту кастомную AppBar, просто передайте её в свойство appBar виджета Scaffold:
Оцените нашу новую рубрику по Flutter советам 👍! Все подобные новости можно найти по хэштегу #FlutterPulseTips
#flutter #dart #flutterpulse #FlutterPulseTips #MobileDevelopment #CustomAppBar #AppBarDesign #FlutterTips
Потому что вы можете 😉
Вы можете создать кастомную AppBar, реализовав интерфейс PreferredSizeWidget. Это даст вам гибкость в настройке панели приложений под нужды вашего приложения.
class EditorAppBar extends StatelessWidget implements PreferredSizeWidget {
const EditorAppBar({
super.key,
});
@override
Widget build(BuildContext context) {
return Row(...); // Здесь вы можете настроить свой собственный дизайн
}
@override
Size get preferredSize => const Size.fromHeight(kToolbarHeight);
// Используйте эту константу для рекомендуемой высоты
}
Чтобы использовать эту кастомную AppBar, просто передайте её в свойство appBar виджета Scaffold:
child: Scaffold(
appBar: EditorAppBar(),
...
),
Оцените нашу новую рубрику по Flutter советам 👍! Все подобные новости можно найти по хэштегу #FlutterPulseTips
#flutter #dart #flutterpulse #FlutterPulseTips #MobileDevelopment #CustomAppBar #AppBarDesign #FlutterTips
👍3❤1
Создай расширение темы
Упростите доступ к свойствам темы вашего приложения 💻
Расширение темы позволяет упростить доступ к свойствам темы вашего приложения. Для этого нужно создать расширение класса
Пример использования
До: сложный доступ к свойствам темы
После: упрощенный доступ с расширением
Оцените новую рубрику по достоинству! 👍💬 Оставляйте ваши отзывы и предложения в комментариях! 💬👇
Все подобные новости можно найти по хэштегу #FlutterPulseTips
#flutter #dart #flutterpulse #FlutterPulseTips #MobileDevelopment #UIUX #CodingTips #AppDevelopment #SoftwareDevelopment
Упростите доступ к свойствам темы вашего приложения 💻
Расширение темы позволяет упростить доступ к свойствам темы вашего приложения. Для этого нужно создать расширение класса
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
👍5
Локальная база данных
Когда вы хотите, чтобы ваше приложение работало офлайн 🔄
Шаг 1: Использование пакета Drift
Для работы с локальной базой данных мы будем использовать пакет Drift. 📦
Шаг 2: Создание базы данных
Шаг 3: Создание таблицы
Шаг 3: Создание или редактирование build.yaml
в корневой папке вашего Flutter-приложения 📁
Запустите сборщик, чтобы регенерировать схему базы данных 🔄
Оцените новую рубрику! 👍💬
Все подобные новости можно найти по хэштегу #FlutterPulseTips
#flutter #dart #flutterpulse #FlutterPulseTips #MobileDevelopment #LocalDatabase #DriftPackage #FlutterTips #AppDevelopment
Когда вы хотите, чтобы ваше приложение работало офлайн 🔄
Шаг 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 и SelectableText? 🤔
Используйте
Для одного текста просто используйте
Оцените новую рубрику и напишите своё мнение! 💬
Все подобные новости можно найти по хэштегу #FlutterPulseTips 🔍
#flutter #dart #flutterpulse #FlutterPulseTips #MobileDevelopment #UIUX #CodingTips #AppDevelopment #FlutterTips
По умолчанию текст не является выбираемым. 🤔
Почему? Виджет
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
🚀 Расширяем возможности Flutter с помощью FFI: бинарники и компиляция под капотом!
🔥 Готовы погрузиться в мир нативной магии? В новом видео от эксперта Руслана Цицера — ключевые секреты интеграции C/C++ библиотек во Flutter через FFI! Узнайте, как избежать подводных камней и заставить "железо" работать на вас.
👉 СМОТРЕТЬ ВИДЕО 👈
💡 В этом выпуске:
🔧 Две главные проблемы FFI и их элегантные решения:
1️⃣ Выбор компилятора — почему для iOS, Android и macOS нужны разные инструменты и как их настроить
2️⃣ Интеграция бинарников — куда поместить скомпилированные библиотеки, чтобы Flutter их "увидел"
📦 Практические примеры:
- Работа с Makefile и скриптами сборки
- Особенности подключения под Android (
- Автоматизация переноса бинарников
🚨Внимание, лайфхак! Для iOS показан работающий метод подключения через "кустарные" CocoaPods — минимум конфигурации, максимум результата!
🔗 Ресурсы:
- GitHub с примерами кода
💬 "Если вы работаете с нативным кодом — это видео сэкономит вам часы поисков!"
👍 Не пропустите! Узнайте, как:
- Собрать универсальные бинарники под любую платформу
- Избежать ошибок ABI-совместимости
- Оптимизировать процесс сборки
👉 Подписывайтесь на канал, жмите 🔔 колокольчик, чтобы не пропустить новые выпуски! Ваши лайки и комментарии — лучшая мотивация для автора 💙
И про реакции на нашем канале тоже не забывайте!) 👍
#Flutter #Dart #FlutterPulse #FlutterPulseTips #FlutterPulseYoutube #FFI #Rust #NativeCode #MobileDevelopment
🔥 Готовы погрузиться в мир нативной магии? В новом видео от эксперта Руслана Цицера — ключевые секреты интеграции C/C++ библиотек во Flutter через FFI! Узнайте, как избежать подводных камней и заставить "железо" работать на вас.
👉 СМОТРЕТЬ ВИДЕО 👈
💡 В этом выпуске:
🔧 Две главные проблемы FFI и их элегантные решения:
1️⃣ Выбор компилятора — почему для iOS, Android и macOS нужны разные инструменты и как их настроить
2️⃣ Интеграция бинарников — куда поместить скомпилированные библиотеки, чтобы Flutter их "увидел"
📦 Практические примеры:
- Работа с Makefile и скриптами сборки
- Особенности подключения под Android (
jniLibs
) и iOS (Framework + Info.plist)- Автоматизация переноса бинарников
🚨
🔗 Ресурсы:
- GitHub с примерами кода
💬 "Если вы работаете с нативным кодом — это видео сэкономит вам часы поисков!"
👍 Не пропустите! Узнайте, как:
- Собрать универсальные бинарники под любую платформу
- Избежать ошибок ABI-совместимости
- Оптимизировать процесс сборки
👉 Подписывайтесь на канал, жмите 🔔 колокольчик, чтобы не пропустить новые выпуски! Ваши лайки и комментарии — лучшая мотивация для автора 💙
И про реакции на нашем канале тоже не забывайте!) 👍
#Flutter #Dart #FlutterPulse #FlutterPulseTips #FlutterPulseYoutube #FFI #Rust #NativeCode #MobileDevelopment
❤1