Создаем собственный экран ошибок
Вам надоело видеть красный или серый экран при возникновении ошибки? 🤔
Это поведение Flutter-приложения по умолчанию. 📱
Примечание: Если вы хотите, чтобы Flutter перестал показывать красный экран в режиме отладки или серый в production-режиме, просто удалите функцию
Вы можете переопределить виджет ошибки по умолчанию или вообще не показывать ничего... 🤷♂️
Хорошим решением может быть перенаправление пользователя и отображение ошибки в виде всплывающего сообщения. 📢
Оцените нашу новую рубрику! 👍💬 Оставляйте ваши отзывы в комментариях! 💬👇
Все подобные новости можно найти по хэштегу #FlutterPulseTips
#flutter #dart #flutterpulse #FlutterPulseTips #MobileDevelopment #AppDevelopment #ErrorHandling #CustomErrorScreen #FlutterTips
Вам надоело видеть красный или серый экран при возникновении ошибки? 🤔
Это поведение 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-трюк, который поможет вам создать круглый индикатор прогресса с помощью
Вы можете использовать виджет
В этом примере мы используем
Оцените новую рубрику и напишите в комментариях, какие темы вам интересны 🔥
Все подобные новости можно найти по хэштегу #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