Flutter Pulse
644 subscribers
403 photos
892 links
На канале будут новости про flutter с сайтов, информация об обновлении пакетов, а также авторский контент.
Download Telegram
Использование ИИ в вашем приложении с помощью Gemini

Привет, разработчики Flutter! 🤖💻 Сегодня мы расскажем, как добавить Gemini в ваше приложение с помощью Firebase Functions безопасным способом 🔒.

Почему не стоит использовать плагин flutter_gemini?

Из соображений безопасности я настоятельно предпочитаю не раскрывать свой ключ API Gemini в приложении 🔑.

Шаги по интеграции Gemini с Firebase:

1. Создайте новый проект Firebase с помощью команды firebase init genkit или установите необходимые зависимости 📦.
- Установите следующие пакеты:
- @genkit-ai/ai
- @genkit-ai/core
- @genkit-ai/dotprompt
- @genkit-ai/firebase
- @genkit-ai/flow
- @genkit-ai/googleai
- zod

2. Установите genkit глобально: npm install -g genkit 🌐.

3. Инициализируйте gemini, используя configureGenkit 🔧.



import { initializeApp } from "firebase/app";
import { defineString } from "firebase-functions/params";
import { configureGenkit } from '@genkit-ai/core';
import { firebase } from '@genkit-ai/firebase';

defineString('GOOGLE_GENAI_API_KEY');
const firebaseApp = initializeApp();

configureGenkit({
plugins: [
firebase(),
googleAI({ apiKey: defineString('GOOGLE_GENAI_API_KEY') }),
],
// ...
enableTracingAndMetrics: true,
});



Добавьте ключ API в файл .env и не забудьте удалить .env из .gitignore, иначе Firebase не сможет его использовать 🚫.



export const suggestionFlow = onFlow({
name: "suggestionFlow",
httpsOptions: { cors: true },
region: "europe-west1",
inputSchema: z.object({ uid: z.string(), query: z.string(), language: z.string() }),
outputSchema: z.string(),
authPolicy: (auth, input) => {
// Проверка аутентификации пользователя
if (auth.uid != input.uid) {
throw new Error("You can only access your own data");
}
// Проверка поддерживаемого языка
if (input.language != "fr" && input.language != "en") {
throw new Error("Only French and English are supported for now");
}
// Разрешить доступ только аутентифицированным пользователям
return !!auth.uid;
},
}, async (input) => {
const exercicesContext = JSON.stringify(exercices);
const userLanguage = input.language;
const prompt = `You are an AI assistant that helps users with XXX. You will speak in the user's language: $userLanguage.
You will answer with the JSON format below:
{"days": [{"day": number, "steps": {...}, "description": string}]}
Here is the user query: ${input.query}`;

const llmResponse = await generate({
model: gemini15Flash,
prompt,
config: {
temperature: 1,
maxOutputTokens: 3000,
},
});

return llmResponse.text();
});



Разверните эту функцию на Firebase с помощью команды firebase deploy --only functions 🚀.

Вызов функции из Flutter:


Future<String> fetchStretchingSuggestionFlow(
String uid,
String query,
String userLanguage,
) async {
final callable = FirebaseFunctions.instance.httpsCallable('suggestionFlow');
final result = await callable.call<String>({
'uid': uid,
'query': query,
'language': userLanguage,
});
final data = (await decode(result.data)) as Map<String, dynamic>;
return AIexercice.fromJson(data);
}



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

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

#flutter #dart #flutterpulse #FlutterPulseTips #Firebase #Gemini #AI #FlutterTips #MobileDev #AppDev
Отслеживание видимости клавиатуры
Без каких-либо плагинов 😉

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

Проблема:
Иногда клавиатура заставляет некоторые элементы контента перемещаться вверх, и вы можете захотеть скрыть определенные элементы на экране, когда пользователь печатает. Я предпочитаю иметь статическую кнопку действия внизу. Однако проблема в том, что эта кнопка может перекрывать поле ввода, пока пользователь печатает. Поэтому я использую метод, чтобы скрыть кнопку действия, когда клавиатура открыта.

Решение:
Для отслеживания состояния клавиатуры мы можем использовать виджет KeyboardVisibility, который не требует установки дополнительных плагинов.



import 'package:flutter/material.dart';

// состояние клавиатуры
enum KeyboardVisibilityState { visible, hidden }

// определение функции слушателя
typedef OnKeyboardStateChanged = void Function(KeyboardVisibilityState state);

// stateful виджет для отслеживания изменения видимости клавиатуры
class KeyboardVisibility extends StatefulWidget {
final Widget child;
final OnKeyboardStateChanged onKeyboardStateChanged;

const KeyboardVisibility({
super.key,
required this.child,
required this.onKeyboardStateChanged,
});

@override
State<KeyboardVisibility> createState() => _KeyboardVisibilityState();
}

class _KeyboardVisibilityState extends State<KeyboardVisibility> with WidgetsBindingObserver {
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}

@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}

@override
void didChangeMetrics() {
super.didChangeMetrics();
checkState();
}

void checkState() {
final value = WidgetsBinding.instance.platformDispatcher.views.first.viewInsets.bottom;
switch (value != 0.0) {
case true:
widget.onKeyboardStateChanged(KeyboardVisibilityState.visible);
case false:
widget.onKeyboardStateChanged(KeyboardVisibilityState.hidden);
}
}

@override
Widget build(BuildContext context) {
return widget.child;
}
}



Использование:
Виджет KeyboardVisibility можно использовать следующим образом:



KeyboardVisibility(
onKeyboardStateChanged: (state) => _showOrHideBottomAction(state),
child: Form(...),
)



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

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

#flutter #dart #flutterpulse #FlutterPulseTips #MobileDev #UIUX #CodingTips #AppDev #DevTips
1👍1
Создание изображения из виджета

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

Шаг 1: Добавьте RepaintBoundary поверх виджета, который хотите экспортировать

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



final GlobalKey _repaintBoundaryKey = GlobalKey();

RepaintBoundary(
key: _repaintBoundaryKey,
child: CustomPaint(
painter: MyPainter(),
...
),
)



Этот ключ позволит нам найти объект рендеринга и вызвать метод toImage. 📚 Для более глубокого понимания можно изучить, что такое Widget tree, Element tree и RenderObject tree.

Шаг 2: Вызовите метод для экспорта изображения в галерею телефона

Теперь напишем функцию, которая будет экспортировать изображение:



import 'package:image_gallery_saver/image_gallery_saver.dart';

Future<void> exportImage() async {
try {
RenderRepaintBoundary boundary = _repaintBoundaryKey.currentContext!.findRenderObject() as RenderRepaintBoundary;
ui.Image image = await boundary.toImage(pixelRatio: 3.0);
ByteData? byteData = await image.toByteData(format: ui.ImageByteFormat.png);
Uint8List pngBytes = byteData!.buffer.asUint8List();

final directory = await getDownloadsDirectory();
final imgName = 'myapp-${DateTime.now().microsecondsSinceEpoch}';
final result = await ImageGallerySaver.saveImage(pngBytes, quality: 100, name: imgName);

if (result['isSuccess']) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Изображение экспортировано')),
);
}
} catch (e) {
// Обработайте ошибку (покажите сообщение пользователю, сохраните отчет о сбое)
}
}



Мы используем пакет image_gallery_saver, чтобы сохранить изображение в галерею телефона. 📁📸

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

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

#flutter #dart #flutterpulse #FlutterPulseTips #MobileDev #AppDev #CodingTips #UIUX #FlutterTips
🔥1
Сохранение позиции прокрутки страницы

Привет, разработчики Flutter! 👋 Сегодня мы поделимся полезным советом о том, как сохранить позицию прокрутки страницы при навигации между разными экранами. 📱💻

Вы когда-нибудь сталкивались с ситуацией, когда пользователь прокручивал список или контент на странице, а затем возвращался обратно, и страница снова оказывалась в самом верху? 😒 Это может быть неудобно для пользователей, особенно если они хотят вернуться к тому месту, где они остановились.

Решение: использование PageStorage и PageStorageBucket

Чтобы решить эту проблему, мы можем использовать PageStorage и PageStorageBucket. Эти инструменты позволяют сохранять состояние прокрутки страницы и восстанавливать его при возвращении на эту страницу.

Вот пример кода:


final PageStorageBucket _bucket = PageStorageBucket(); // Создание хранилища для страниц

final pages = <Widget>[ // Список страниц
Page1(key: const PageStorageKey('page1'), ...), // Первая страница с уникальным ключом
Page2(key: const PageStorageKey('page2'), ...), // Вторая страница с уникальным ключом
];

@override
Widget build(BuildContext context) {
return Scaffold( // Основной виджет страницы
body: PageStorage( // Обертка для сохранения состояния прокрутки
child: pages[currentTab], // Текущая отображаемая страница
bucket: _bucket, // Передача хранилища
),
);
}



Как это работает?

1. Мы создаем экземпляр PageStorageBucket, который будет хранить состояние наших страниц.
2. Каждой странице присваиваем уникальный ключ с помощью PageStorageKey. Это позволяет PageStorage идентифицировать каждую страницу и сохранять её состояние.
3. Обернём наши страницы в виджет PageStorage, передав туда текущего ребёнка (текущую страницу) и наше хранилище (_bucket).

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

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

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

#flutter #dart #flutterpulse #FlutterPulseTips #MobileDev #AppDev #UIUX #DevTips
👍4
Правило 8 для интервалов в дизайне

Генерация визуальной гармонии на подсознательном уровне

Вы когда-нибудь задумывались, что делает дизайн визуально приятным? 🤔 Одним из секретов является соблюдение правила 8 при проектировании интервалов между элементами! 📐

Что такое правило 8?

Теория довольно проста: все элементы в вашем дизайне кратны 8 по ширине и высоте, как и расстояния между ними. 📏 Это создает ощущение гармонии и порядка, делая интерфейс более интуитивным и комфортным для пользователя. 😌

Давайте рассмотрим пример реализации этого правила во Flutter:


class AppSpacer extends StatelessWidget {
final double? width;
final double? height;

const AppSpacer._({Key? key, this.width, this.height}) : super(key: key);

factory AppSpacer.p32() => const AppSpacer._(height: 32, width: 32);
factory AppSpacer.p24() => const AppSpacer._(height: 24, width: 24);
factory AppSpacer.p16() => const AppSpacer._(height: 16, width: 16);
factory AppSpacer.p8() => const AppSpacer._(height: 8, width: 8);

@override
Widget build(BuildContext context) {
return SizedBox(
width: width,
height: height,
);
}
}



Этот код определяет виджет AppSpacer, который можно использовать для создания интервалов, кратных 8. 📝 Просто используйте один из фабричных конструкторов, таких как AppSpacer.p8(), AppSpacer.p16() и т.д., чтобы добавить нужный интервал в вашем интерфейсе. 👍

Оцените новую рубрику лайком 👍, если считаете её полезной! 💬 Поделитесь своими мыслями в комментариях! 💬

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

#flutter #dart #flutterpulse #FlutterPulseTips #SpacingDesign #DesignTips #FlutterTips #UIUX #MobileDev #AppDev
👍4
Воспроизведение видео на весь экран
Покажите полноэкранное видео с правильным соотношением сторон 🤩

Чтобы показать видео на весь экран с сохранением правильного соотношения сторон, следуйте этим простым шагам:

1. Установите пакет video_player 📦
2. Встройте видеоплеер внутрь виджета VideoContainer 📺

Обеспечьте, чтобы содержимое занимало весь экран 📱

return Scaffold(
appBar: AppBar(
backgroundColor: Colors.transparent,
elevation: 0,
),
extendBodyBehindAppBar: true,
body: Stack(
children: [
Positioned.fill(
child: GestureDetector(
onTap: () => videoListener?.pauseOrResume(),
child: VideoContainer.fromController(_controller!),
),
),
],
),
);


Код виджета VideoContainer:

import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart';

class VideoContainer extends StatelessWidget {
final Widget child;
final double ratio;
final Size contentsSize;

const VideoContainer({
super.key,
required this.child,
required this.ratio,
required this.contentsSize,
});

factory VideoContainer.fromController(VideoPlayerController controller) =>
VideoContainer(
ratio: controller.value.aspectRatio,
contentsSize: controller.value.size,
child: VideoPlayer(controller),
);

@override
Widget build(BuildContext context) {
return FittedBox(
fit: BoxFit.cover,
child: AspectRatio(
aspectRatio: ratio,
child: child,
),
);
}
}


Оцените новую рубрику FlutterPulseTips 👍💬
Все подобные новости можно найти по хэштегу #FlutterPulseTips

#flutter #dart #flutterpulse #FlutterPulseTips #mobiledev #appdev #codingtips #uiux #videostreaming #fullscreenvideo
👍1
Запуск анимации при изменении свойства
Привет, подписчики! 👋 Сегодня мы рассмотрим интересный вопрос: как запустить анимацию каждый раз, когда меняется определенное свойство? 🤔

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

Для этого мы можем использовать метод didUpdateWidget в StatefulWidget. Этот метод вызывается каждый раз, когда виджет обновляется. 🔄

Пример кода:


@override
void didUpdateWidget(covariant UploadedAvatarAnimation oldWidget) {
super.didUpdateWidget(oldWidget);
final (wasUploading, isUploading) = (oldWidget.isUploading, widget.isUploading);
switch ((wasUploading, isUploading)) {
case (false, true):
_controller.forward(from: 0);
_initScaleAnim(0, pt);
case (true, false):
_controller.reverse(from: 1);
default:
}
}



В этом примере мы проверяем, изменилось ли свойство isUploading, и запускаем анимацию соответствующим образом. 🔮

Как это работает?
1. Мы используем метод didUpdateWidget, чтобы отслеживать изменения виджета.
2. Мы сравниваем старое и новое значения свойства isUploading.
3. В зависимости от изменения, мы запускаем анимацию вперед или назад.

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

Все подобные новости можно найти по хэштегу #FlutterPulseTips 👍
#flutter #dart #flutterpulse #FlutterPulseTips #mobiledev #appdev #animation #ui #ux #codingtips #programming #softwaredevelopment
👍4
Добавьте кастомные переходы страниц с GoRouter

Переходы между страницами важны для пользовательского опыта

Добавьте этот небольшой помощник, чтобы определить кастомный переход страницы:


Page<dynamic> Function(BuildContext, GoRouterState) buildPageTransition(
Widget child,
) => (BuildContext context, GoRouterState state) {
return CustomTransitionPage(
key: state.pageKey,
child: child,
transitionsBuilder: (context, animation, secondaryAnimation, child) =>
FadeThroughTransition( // можно создать свой собственный переход или использовать из пакета animations на pub.dev
animation: animation,
secondaryAnimation: secondaryAnimation,
child: child,
),
);
};


Теперь оберните свою страницу в переход, используя pageBuilder для вашего маршрута:


GoRoute(
path: '/signin',
builder: (context, state) => const SigninPage(),
pageBuilder: buildPageTransition(const SigninPage()),
),


Вы также можете настроить стандартный переход страницы прямо в вашей теме:


pageTransitionsTheme: PageTransitionsTheme(
builders: {
TargetPlatform.android: const ZoomPageTransitionsBuilder(),
TargetPlatform.iOS: const CupertinoPageTransitionsBuilder(),
},
),


Оцените нашу новую рубрику! 👍💡
Все подобные новости можно найти по хэштегу #FlutterPulseTips
#flutter #dart #flutterpulse #FlutterPulseTips #MobileDev #AppDev #UIUX #FlutterTips
👍5
Принудительный портретный режим
Когда вы в последний раз использовали приложение в ландшафтном режиме? 🤔

Фиксация ориентации экрана в Flutter
Чтобы заставить приложение работать только в портретном режиме, добавьте следующий код в функцию main() перед запуском приложения:


SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp, // Портретная ориентация вверх
DeviceOrientation.portraitDown, // Портретная ориентация вниз
]);


Теперь приложение не сможет перейти в ландшафтный режим 📱💻

Результат:
Приложение останется в портретном режиме 👍

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

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

#flutter #dart #flutterpulse #FlutterPulseTips #MobileDev #AppDev #ProgrammingTips #UIUX #DevTips
👍3
Загрузка байтов изображения и отображение на холсте
Не так сложно сделать с помощью Flutter 😉

Вы когда-нибудь задумывались, как можно загрузить изображение и отобразить его на холсте в Flutter? 🤔 Давайте разберемся в этом вместе! 💡

Шаг 1: Загрузка изображения
Сначала нам нужно загрузить изображение из наших ресурсов. Для этого мы используем метод load класса rootBundle:


import 'dart:ui' as ui;
import 'package:flutter/services.dart';

// Загружаем изображение из ресурсов
final ByteData data = await rootBundle.load(path);
// Преобразуем в Uint8List
final Uint8List bytes = data.buffer.asUint8List();
// Преобразуем в ui.Image
final ui.Image image = await decodeImageFromList(bytes);



Шаг 2: Отображение на холсте
Теперь, когда у нас есть изображение в формате ui.Image, мы можем отобразить его на холсте. Для этого создадим собственный класс CustomPainter:


// Создаем новый CustomPainter
class MyPainter extends CustomPainter {
final ui.Image image;

MyPainter(this.image);

@override
void paint(Canvas canvas, Size size) {
// Рисуем изображение на холсте
canvas.drawImageRect(image, srcRect, dstRect, Paint());
}
}



Вот и все! Теперь вы знаете, как загрузить байты изображения и отобразить их на холсте во Flutter. Просто и эффективно, не правда ли? 😊

Оцените нашу новую рубрику и оставьте свои комментарии! 👇

Все подобные новости можно найти по хэштегу #FlutterPulseTips
#flutter #dart #flutterpulse #FlutterPulseTips #mobiledev #appdev #codingtips #FlutterTips
👍3🔥1
Хранение настроек пользователя

Используйте плагин shared preferences только для некритичных данных!

Почему не стоит хранить всё в SharedPreferences:
• Shared preferences предназначены для хранения простых данных в формате ключ-значение.
• Они не подходят для хранения сложных структур данных.
• Они не оптимизированы для высокопроизводительных операций чтения/записи.
• Не храните конфиденциальные данные, так как нет гарантии, что запись будет сохранена на диске (иногда всё может быть потеряно).


// getInstance возвращает Future
// Хорошей практикой является инициализация в начале работы приложения,
// а затем использование уже инициализированного экземпляра
final SharedPreferences prefs = await SharedPreferences.getInstance();


Если вы используете Provider или Riverpod, рассмотрите возможность сделать следующее:
вызовите метод init перед отображением чего-либо и используйте SharedPreferencesBuilder
для доступа к sharedPreferences.


import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:shared_preferences/shared_preferences.dart';

final sharedPreferencesProvider = Provider<SharedPreferencesBuilder>((ref) => SharedPreferencesBuilder(),
);

class SharedPreferencesBuilder implements OnStartService {
SharedPreferences? _sharedPreferences;

@override
Future<void> init() async {
if (_sharedPreferences != null) {
return;
}
_sharedPreferences = await SharedPreferences.getInstance();
}

SharedPreferences get prefs {
if (_sharedPreferences == null) {
throw Exception('SharedPreferences not loaded');
}
return _sharedPreferences!;
}
}


Prefer SharedPreferencesAsync or SharedPreferencesWithCache,
так как SharedPreferences будет объявлен устаревшим в будущих обновлениях.

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

Все подобные новости можно найти по хэштегу #FlutterPulseTips
#flutter #dart #flutterpulse #FlutterPulseTips #MobileDev #AppDev #ProgrammingTips #DevTips
👍3
Детали для улучшения формы

Ничто не раздражает так сильно, как невозможность закрыть клавиатуру. Пользователь нажимает в любом месте... и клавиатура остаётся. Вместо этого вы можете просто сделать так:


final _formKey = GlobalKey<FormState>();

class SigninPage extends StatelessWidget {
const SigninPage({super.key, this.canDismiss = true});

@override
Widget build(BuildContext context) {
final translations = Translations.of(context).signin;

return GestureDetector(
onTap: () => FocusScope.of(context).unfocus(), // Убираем фокус с полей при нажатии вне их
child: PopScope(
canPop: canDismiss,
child: TopImgBackground(
bgImagePath: 'assets/images/signin/signin_background.png',
child: Scaffold(
backgroundColor: Colors.transparent,
appBar: AppBar(
backgroundColor: Colors.transparent,
automaticallyImplyLeading: canDismiss,
foregroundColor: context.colors.background,
),
resizeToAvoidBottomInset: false,
body: Form(
autovalidateMode: AutovalidateMode.disabled,
key: _formKey,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24.0),
child: ListView(
children: [
const SizedBox(height: 150),
Text(
translations.title,
style: Theme.of(context).textTheme.titleLarge?.copyWith(
fontWeight: FontWeight.bold,
),
),
],
),
),
),
),
),
),
);
}
}


Решение: Оберните всю страницу в GestureDetector, а затем снимите фокус со всех элементов, используя функцию FocusScope. Это позволит автоматически убрать клавиатуру при нажатии вне текстовых полей.

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

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

#flutter #dart #flutterpulse #FlutterPulseTips #MobileDev #UIUX #AppDev #CodingTips #DevTips #FlutterTips
👍4
Supabase: Привязка анонимного пользователя к аутентифицированному

Анонимный пользователь - это действительно здорово. Вы автоматически создаете нового пользователя в своей базе данных каждый раз, когда кто-то впервые запускает ваше приложение.
Затем вы можете позволить ему подписаться, начать работать с вашим приложением, не беспокоя его просьбой ввести email...
А затем, когда он действительно вовлечется в процесс, вы можете привязать его учетную запись.



@override
Future<Credentials> signup(String email, String password) async {
if (client.auth.currentUser?.isAnonymous == true) {
// Обновляем анонимного пользователя с помощью email и password
final res = await client.auth.updateUser(UserAttributes(email: email, password: password));
if (res.user != null) {
return Credentials(id: res.user!.id);
} else {
throw 'Ошибка при обновлении пользователя';
}
}
return client.auth
.signUp(email: email, password: password)
.then(
(value) => Credentials(id: value.user!.id),
onError: (error) {
Logger().e("Ошибка при регистрации: $error");
throw SignupException();
},
);
}



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

Все подобные новости можно найти по хэштегу #FlutterPulseTips
#flutter #dart #flutterpulse #FlutterPulseTips #Supabase #MobileDev #AppDev #CodingTips #DevTips
👍1🔥1
Проверка разрешений

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. Создайте StatefulWidget.
2. В методе initState вызовите WidgetsBinding.instance.addPostFrameCallback.


@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
// ваш код здесь
});
}


Преимущества использования addPostFrameCallback:
- Гарантия, что код выполнится после полной готовности представления.
- Избежание случайных задержек, которые могут не сработать в нужный момент.

Не злоупотребляйте этим методом! В большинстве случаев можно найти альтернативные решения, которые позволят выполнить код позже без использования addPostFrameCallback.

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

Все подобные советы ищите по хэштегу #FlutterPulseTips
#flutter #dart #flutterpulse #FlutterPulseTips #MobileDevTips #AppDev #FlutterTips #DartLang
👍5