Flutter Pulse
645 subscribers
402 photos
889 links
На канале будут новости про flutter с сайтов, информация об обновлении пакетов, а также авторский контент.
Download Telegram
Как создать таймер
Создание точного таймера с помощью Flutter

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

Проблема с обычным таймером:
- Задержки и тики могут быть не идеально точными, особенно при высокой нагрузке на CPU.

Мы используем специальные колбэки для обновления виджета с анимациями. Обновляем наш виджет каждую секунду и запускаем анимацию соответствующим образом.

Код контроллера таймера:


class TimerController {
Timer? _timer;
DateTime? timerEndTime;
DateTime? timerStartTime;
TimerState state;
Duration duration;
Duration? remaining;
VoidCallback? onInit;
VoidCallback? onStart;
VoidCallback? onPause;
TimerTick? onTick;
List<VoidCallback> onCompleteListener;
List<VoidCallback> _onTickListener;

BasicTimerController({
required this.state,
required this.duration,
required this.timerEndTime,
this.remaining,
this.timerStartTime,
}) : onCompleteListener = [],
_onTickListener = [] {
remaining ??= duration;
}

Duration? get elapsed {
if (remaining == null) {
return null;
}
return duration - remaining!;
}

void start() {
state = TimerState.running;
final isNewTimer = remaining == null;
if (isNewTimer) {
timerStartTime = DateTime.now();
timerEndTime = timerStartTime!.add(duration);
} else {
timerEndTime = DateTime.now().add(remaining!);
timerStartTime = timerEndTime!.subtract(remaining!);
}

onInit?.call();
onStart?.call();
remaining ??= duration;

// Мы могли бы обновлять чаще, но это было бы бесполезно
const timerFrequency = Duration(milliseconds: 1000);
_timer = Timer.periodic(timerFrequency, (timer) {
if (remaining == null || remaining! <= Duration.zero) {
stop();
return;
}
if (timerEndTime == null) {
return;
}
remaining = timerEndTime!.difference(DateTime.now());
onTick?.call(remaining!);
for (final listener in _onTickListener) {
listener();
}
});
}

@override
void pause() {
_timer?.cancel();
state = TimerState.paused;
}
}



Ключевые моменты:
- Если вы знаете, когда таймер должен начаться и закончиться, ваш таймер останется точным, даже если пользователь закроет приложение и вернется.

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

Все подобные новости можно найти по хэштегу #FlutterPulseTips
#flutter #dart #flutterpulse #FlutterPulseTips #MobileDevelopment #AppDevelopment #ProgrammingTips #Таймер #Точность #FlutterРазработка
👍5
Рисуем таймер
Создание точного таймера с помощью Flutter часть 2

Мы можем использовать шейдер в нашем кастомном рисовальщике (painter).

Мы рисуем полный круг, который будет отображаться постепенно.

Затем мы рисуем круг, который будет уменьшаться каждую секунду.

Мы перерисовываем только если прогресс изменился.

Ну а если вы хотите протестировать какой-то угол вручную...



class CircleTimerPainter extends CustomPainter {
final double progress;
final Color progressColor;
final Color backgroundColor;

CircleTimerPainter({
super.repaint,
required this.progress,
this.progressColor = Colors.blue,
this.backgroundColor = Colors.grey,
});

@override
void paint(Canvas canvas, Size size) {
final angle = 360 * progress; // примечание: Используйте напрямую радианы для лучшей производительности
final backgroundPaint = Paint()
..color = backgroundColor
..style = PaintingStyle.stroke
..strokeWidth = 28;

final progressPaint = Paint()
..shader = SweepGradient(
colors: [
progressColor,
Colors.red,
],
startAngle: 0 - 90.0.radians,
endAngle: angle.radians,
).createShader(
Rect.fromCircle(
center: Offset(size.width / 2, size.height / 2),
radius: size.width / 2),
)
..color = progressColor
..style = PaintingStyle.stroke
..strokeCap = StrokeCap.round
..strokeWidth = 20;

// Рисуем фоновый круг
canvas.drawCircle(
size.center(Offset.zero),
size.width / 2,
backgroundPaint,
);

canvas.drawArc(
Rect.fromLTWH(0, 0, size.width, size.height),
-90.0.radians,
angle.radians,
false,
progressPaint,
);
}

@override
bool shouldRepaint(covariant CircleTimerPainter oldDelegate) {
return oldDelegate.progress != progress;
}
}

extension RadianExt on double {
double get radians => this * (math.pi / 180);
}



Оцените новую рубрику! 👍💬
Все подобные новости можно найти по хэштегу #FlutterPulseTips
#flutter #dart #flutterpulse #FlutterPulseTips #MobileDevelopment #AppDevelopment #ProgrammingTips #UIUX #FlutterCommunity
👍4
Получение данных с использованием http-клиента
Как получить данные с удаленного сервера, используя http-клиент 🤔

Шаг 1: Установите пакет http 📦


Future<T> request<T>({
required String endpoint,
Map<String, String>? headers,
Map<String, String>? queryParams,
}) async {
final url = Uri(
scheme: config.baseUrlScheme, // http или https
host: config.baseUrlHost, // localhost или mydomain.com
path: endpoint, // /api/articles
queryParameters: queryParams,
port: config.baseUrlPort, // порт вашего бэкенда
);

final response = await http.get(
url,
headers: {
...?headers, // Предоставление пользовательских заголовков, например, токена API
},
);

if (response.statusCode != 200) {
throw Exception('Запрос к API завершился неудачей: ${response.statusCode} ${response.reasonPhrase}');
}

return json.decode(response.body) as T; // Возвращение обобщенного типа T
}


* Возвращение обобщенного типа T, чтобы можно было напрямую возвращать другой тип. Рекомендуется использовать пакет json_serializable для легкого парсинга объектов 📄
* Предоставление пользовательских заголовков, таких как токен API 🔒
* Улучшение: отправка пользовательских ошибок в зависимости от кода состояния ⚠️

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

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

#flutter #dart #flutterpulse #FlutterPulseTips #MobileDevelopment #AppDevelopment #ProgrammingTips #Coding #SoftwareDevelopment
👍1👎1
Шпаргалка по форматированию цен

Вы можете легко форматировать цены, используя пакет intl. Вот наиболее распространенные методы:


import 'package:intl/intl.dart';

// Форматирование с указанием локали и символа валюты
NumberFormat.currency(locale: 'en_US', symbol: '\$').format(12.2);
// $12.2

// Форматирование валюты с использованием текущей локали устройства
NumberFormat.currency().format(12.2);
// US 12.2 или EUR 12.2 в зависимости от локали устройства

// Форматирование валюты без десятичных знаков
NumberFormat.currency(decimalDigits: 0).format(12.2);
// US 12

// Простое форматирование валюты
NumberFormat.simpleCurrency().format(12.2);
// $12.2

// Компактное форматирование больших чисел
NumberFormat.compactSimpleCurrency().format(1200000);
// $1.2M


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

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

#flutter #dart #flutterpulse #FlutterPulseTips #MobileDevelopment #AppDevelopment #ProgrammingTips #Coding #FlutterTips
👍4
Как правильно обрабатывать результат диалога

Не пытайтесь выполнить код напрямую после закрытия диалога! 🚫💻

При работе с диалогами важно правильно обрабатывать их результат. Давайте рассмотрим два примера кода на Dart, чтобы понять, как это сделать корректно. 💡

Неправильный способ: 🚫

Future<void> showRatingDialog(BuildContext context) {
return showDialog<RatingResult>(
context: context,
barrierDismissible: false,
builder: (context) {
return AlertDialog(
title: const Text('Rate the app'),
content: const Text('Please rate the app'),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
// не пытайтесь выполнить что-либо здесь
// потому что диалог отклонен
},
child: const Text('Rate'),
),
TextButton(
onPressed: () {
Navigator.of(context).pop();
// не пытайтесь выполнить что-либо здесь
// потому что диалог отклонен
},
child: const Text('Improve'),
),
],
);
},
);
}


Правильный способ:

enum RatingResult {
rate,
improve,
never,
}

Future<RatingResult?> showRatingDialog(BuildContext context) {
return showDialog<RatingResult>(
context: context,
barrierDismissible: false,
builder: (context) {
return AlertDialog(
title: const Text('Rate the app'),
content: const Text('Please rate the app'),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop(RatingResult.rate);
},
child: const Text('Rate'),
),
TextButton(
onPressed: () {
Navigator.of(context).pop(RatingResult.improve);
},
child: const Text('Improve'),
),
],
);
},
);
}


В первом примере при нажатии на кнопки "Rate" или "Improve" диалог закрывается, но результат не возвращается. Во втором примере при нажатии на кнопки возвращается соответствующее значение из enum `RatingResult`, что позволяет корректно обработать результат.

Оцените новую рубрику и напишите в комментариях, что вы думаете о ней! 🤔💬

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

#flutter #dart #flutterpulse #FlutterPulseTips #MobileDevelopment #AppDevelopment #ProgrammingTips #UIUX #SoftwareDevelopment
👍31🤔1
Перегрузка операторов
Ещё один отличный способ улучшить читаемость кода 😉

Вы знаете, что в Dart можно перегружать операторы? 🤔 Это очень полезная функция, которая позволяет сделать ваш код более интуитивным и понятным.

Давайте рассмотрим пример с классом Vector. Мы хотим складывать векторы с помощью оператора +. Для этого нам нужно перегрузить этот оператор в нашем классе.


class Vector {
final int x, y;
Vector(this.x, this.y);

// Перегружаем оператор +
Vector operator +(Vector other) => Vector(x + other.x, y + other.y);
}

void main() {
final v1 = Vector(1, 2);
final v2 = Vector(3, 4);

final result = v1 + v2; // Теперь мы можем складывать векторы с помощью оператора +
print('(${result.x}, ${result.y})'); // Вывод: (4, 6)
}


Таким образом, мы можем перегружать любые операторы, такие как -, *, / и другие, чтобы сделать наш код более удобным и читаемым. 👍

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

Все подобные новости можно найти по хэштегу #FlutterPulseTips
#flutter #dart #flutterpulse #FlutterPulseTips #codingTips #mobileDevelopment #programmingTips
👍2
Проверка разрешений

iOS и Android требуют, чтобы вы запрашивали разрешение перед выполнением определенных действий, таких как съемка фотографии, сохранение в галерею пользователя или запись звука.

1. Установка и импорт плагина permission_handler


import 'package:permission_handler/permission_handler.dart';


2. Как использовать


// Запрос одного разрешения
[Permission.camera].request()

// Запрос нескольких разрешений (цепочка запросов)
[Permission.camera, Permission.microphone].request()

// Просто проверка статуса разрешения
final cameraPermission = await Permission.camera.status;
final microphonePermission = await Permission.microphone.status;


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


@override
Widget build(BuildContext context) {
return CameraPermission(
child: CameraAwesomeBuilder.custom(
builder: (state, preview) {
...
},
),
);
}


Создайте виджет (CameraPermission) здесь. Перед запуском камеры мы проверяем, дал ли пользователь все необходимые разрешения. В противном случае мы показываем виджет, который вежливо просит разрешить доступ + кнопку для открытия настроек.

Оцените новую рубрику! 👍💬 Нам важно ваше мнение! 🤔

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

#flutter #dart #flutterpulse #FlutterPulseTips #MobileDev #AppDev #ProgrammingTips #DevTips
👍7
1..2..3... Гонка Future

Представьте, что вы ждёте ответ от нескольких источников. Но вам нужен только один ответ. Ладно, такое случается не часто, но представьте...

Ждём только 1 ответ

Будьте осторожны, если первый запрос выдаёт ошибку до того, как придёт второй ответ... Future завершится с ошибкой. Значит, вам нужно игнорировать эту ошибку в вашем будущем запросе.


import 'dart:async';
import 'package:http/http.dart' as http;

void main() async {
await Future.any([
getPost(SERVER_1), // первый сервер
getPost(SERVER_2), // второй сервер
]);
}

Future<String> getPost(String url) async {
final response = await http.get(Uri.parse('....'));
if (response.statusCode == 200) {
return response.body; // возвращаем тело ответа
} else {
throw Exception('Не удалось загрузить пост'); // выбрасываем исключение
}
}


Что возвращает Future.any?
Он возвращает Future, который завершается с первым результатом. Вы можете передать несколько Future разных типов.

Оцените новую рубрику! 👍💡 Все подобные новости можно найти по хэштегу #FlutterPulseTips
#flutter #dart #flutterpulse #FlutterPulseTips #FutureAny #AsyncProgramming #FlutterTips #MobileDevelopment #ProgrammingTips
👍4