Перейти к основному содержимому

Общие примеры кода

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

Отказ от ответственности

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

Например, новая пользовательская функция обычно включает следующие пакеты и файлы. Изменения в коде пользовательской функции должны использовать только эти пакеты и файлы:

import 'dart:convert';
import 'dart:math' as math;

import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:intl/intl.dart';
import 'package:timeago/timeago.dart' as timeago;
import 'lat_lng.dart';
import 'place.dart';
import 'uploaded_file.dart';
import '/backend/backend.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import '/backend/schema/structs/index.dart';
import '/backend/schema/enums/enums.dart';
import '/auth/firebase_auth/auth_util.dart';

Доступ к сгенерированным классам FlutterFlow

FlutterFlow генерирует полный код Flutter для вас по мере создания приложений на его платформе. Часть этого кода включает пользовательские классы, предназначенные для упрощения распространенных задач и инкапсуляции повторно используемых свойств или логики.

Например:

  • Виджеты кнопок: FlutterFlow предоставляет пользовательские классы кнопок, такие как FFButton, которые имеют встроенное оформление и поведение.
  • Google Places: Класс FFPlace инкапсулирует свойства места Google, такие как название, адрес и координаты.
  • Загрузка файлов: Класс FFUploadedFile представляет файлы, загруженные в ваше приложение, инкапсулируя свойства, такие как имя файла, байты и URL.
Что такое класс?

В программировании класс — это шаблон для создания объектов. Он определяет свойства (данные) и методы (функции), принадлежащие объектам этого типа.

Например,

  • Класс Car может иметь свойства, такие как color и speed, и методы, такие как drive() и stop().
  • В FlutterFlow класс, такой как FFPlace, может иметь свойства, такие как address и latLng, а также методы для манипуляции или получения этих значений.

Эти пользовательские классы FlutterFlow в сгенерированном коде в основном имеют префикс FF<ClassName> или FlutterFlow<ClassName>. Если вам нужно получить доступ к этим классам в вашем пользовательском коде, просто введите "FF" или "FlutterFlow" в редакторе кода, чтобы быстро их найти.

suggestions-dropdown.png

Использование компонентов в пользовательском виджете

Статические компоненты против динамических

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

В пользовательском виджете вы можете интегрировать ранее созданный компонент FlutterFlow напрямую, что избавляет от необходимости повторно создавать содержимое дочерних элементов в коде. Например, если вы создаете пользовательский виджет для отображения пользовательских диалоговых окон или нижних панелей с использованием пакета из pub.dev, вы можете просто вернуть существующий компонент, созданный на холсте, вместо написания нового с нуля.

Импорты

При ссылке на класс компонента в вашем коде FlutterFlow автоматически добавит необходимое предложение import.

return-widget-custom-code.png

Получение темы FlutterFlow в пользовательском виджете

При создании пользовательских виджетов часто требуется стилизовать части виджета, например, устанавливать цвета. Вместо использования жестко заданных значений цветов вы можете напрямую обращаться к теме FlutterFlow. Эта тема обеспечивает единообразное оформление по всему приложению и отражает цвета, установленные вами или разработчиком проекта.

Для доступа к цветам темы в вашем пользовательском виджете используйте метод FlutterFlowTheme.of(context). Это позволяет получить любое свойство темы, такое как стандартный primary, primaryBackground или другие пользовательские цвета, а также стили текста, такие как bodyLarge или bodyMedium, обеспечивая соответствие пользовательского виджета общей теме приложения.

Вот пример того, как использовать основной цвет из темы FlutterFlow в пользовательском виджете:

Импорты

Убедитесь, что вы импортировали import '../flutter_flow/flutter_flow_theme.dart'; при доступе к FlutterFlowTheme в ваших пользовательских виджетах.

class CustomButton extends StatefulWidget {
final String label;

CustomButton({required this.label});

@override
_CustomButtonState createState() => _CustomButtonState();
}

class _CustomButtonState extends State<CustomButton> {
bool isPressed = false;

void toggleButton() {
setState(() {
isPressed = !isPressed;
});
}

@override
Widget build(BuildContext context) {
return ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: isPressed
? FlutterFlowTheme.of(context).primary // Primary color when pressed
: FlutterFlowTheme.of(context).secondaryBackground, // Default color
foregroundColor: FlutterFlowTheme.of(context).secondaryText, // Text color
),
onPressed: toggleButton,
child: Text(
widget.label,
style: FlutterFlowTheme.of(context).bodyText1, // Themed text style
),
);
}
}

Изменение состояния приложения из пользовательского кода

В FlutterFlow вы можете обращаться к состоянию приложения или обновлять его напрямую из редактора потоков действий. Однако в определенных сценариях может потребоваться доступ или изменение состояния приложения в пользовательском коде для большего контроля над потоком операций. Класс FFAppState также предоставляет дополнительные вспомогательные функции для изменения значений состояния приложения. Давайте рассмотрим несколько примеров:

Импорты

Убедитесь, что вы импортировали import '../../flutter_flow/flutter_flow_util.dart'; при доступе к FFAppState в ресурсах пользовательского кода.

  • Получение значения состояния приложения в пользовательском коде

Future getCartItems() async {
// Retrieve the current cart items from AppState
final currentCartItems = FFAppState().cartItems;
print('Current Cart Items: $currentCartItems');
}
  • Обновление значений состояния приложения в пользовательском коде
Future enableDarkMode() async {
// Enable dark mode in AppState
FFAppState().update(() {
FFAppState().enableDarkMode = true;
});
print('Dark mode enabled');
}
  • Изменение списка в состоянии приложения с использованием вспомогательных функций

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

Future addLocation(LatLng value) async {
// Add a new location to the LatLng list
FFAppState().addToLatLngList(value);
}

Future removeLocation(LatLng value) async {
// Remove a specific location from the LatLng list
FFAppState().removeFromLatLngList(value);
}

Future removeLocationAtIndex(int index) async {
// Remove a location at a specific index from the LatLng list
FFAppState().removeAtIndexFromLatLngList(index);
}

Future updateLocationAtIndex(int index, LatLng Function(LatLng) updateFn) async {
// Update a location at a specific index in the LatLng list
FFAppState().updateLatLngListAtIndex(index, updateFn);
}

Future insertLocationAtIndex(int index, LatLng value) async {
// Insert a new location at a specific index in the LatLng list
FFAppState().insertAtIndexInLatLngList(index, value);
}

Использование пользовательских типов данных

При создании пользовательского типа данных в FlutterFlow генерируется соответствующий класс <Name>Struct. В пользовательском коде FlutterFlow вы можете создавать новые экземпляры таких типов данных, передавать экземпляры обратно в действие или манипулировать и получать информацию из существующих объектов. Вот несколько примеров, иллюстрирующих работу с примером класса ProductStruct.

Пример 1: Создание нового экземпляра ProductStruct

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

// Create a new instance of ProductStruct
final newProduct = ProductStruct(
productId: '123',
name: 'Example Product',
description: 'A sample product description.',
category: 'Electronics',
subCategory: 'Mobile Phones',
price: PriceStruct(amount: 299.99, currency: 'USD'),
sizes: ['Small', 'Medium', 'Large'],
colors: [ColorsStruct(colorName: 'Red', colorHex: '#FF0000')],
images: [ImagesStruct(thumbnail: 'https://example.com/image.jpg')],
stockStatus: StockStatusStruct(xs: 0, small: 2),
reviews: [ReviewsStruct(rating: 4, comment: 'Great product!')],
);

Пример 2: Получение свойств существующего объекта ProductStruct

Если у вас есть существующий объект ProductStruct (например, полученный из списка продуктов), вы можете получить доступ к его свойствам или вернуть конкретные значения обратно в вызывающее действие.

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

  • Возврат одного поля из ProductStruct

Эта функция получает и возвращает название продукта. Тип возвращаемого значения — String?, чтобы учесть возможность null-значения.

// Function to return the product name from a ProductStruct instance
String? getProductName(ProductStruct product) {
// Get and return the product name
return product.name;
}
  • Проверка существования поля в объекте ProductStruct Эта функция определяет, содержит ли объект ProductStruct ненулевое значение для конкретного поля, такого как description. Она возвращает true, если поле существует и не является null, и false в противном случае.
// Function to check if the description field exists in a ProductStruct instance
bool hasDescription(ProductStruct product) {
// Return true if the description is not null, false otherwise
return product.description != null;
}
  • Возврат списка комментариев отзывов из ProductStruct

Эта функция получает список комментариев отзывов из поля reviews в ProductStruct. Тип возвращаемого значения — List<String>, поскольку возвращается список комментариев (или пустой список, если отзывов нет).

// Function to return a list of review comments from a ProductStruct instance
List<String> getProductReviewComments(ProductStruct product) {
// Check if reviews are present and return a list of review comments
return product.reviews?.map((review) => review.comment ?? '').toList() ?? [];
}

Пример 3: Изменение свойств существующего объекта ProductStruct

Вы также можете изменять свойства существующего объекта ProductStruct. Это может быть полезно, если вы хотите обновить поле перед сохранением данных обратно в Firebase или передачей в действие.

  • Простое изменение свойства В этом примере мы изменим одно свойство, такое как productName, существующего объекта ProductStruct. Этот пример прост и демонстрирует, как обновить базовое поле в объекте.
// Function to update the product name of a ProductStruct instance
Future updateProductName(ProductStruct product, String newProductName) {
// Update the product name with the new value
product.productName = newProductName;
}
  • Сложное изменение свойства — обновление вложенного объекта В этом более сложном примере мы изменим вложенное свойство в ProductStruct, такое как обновление цены (которая сама является объектом PriceStruct). Это показывает, как обновить свойство, которое само содержит несколько полей.
// Function to update the price of a ProductStruct instance
Future updateProductPrice(ProductStruct product, double newAmount, String currency) {
// Check if price is not null
if (product.price != null) {
// Update only the amount field
product.price!.amount = newAmount;
} else {
// If price is null, optionally initialize it if needed
product.price = PriceStruct(
amount: newAmount,
currency: currency,
);
}
}
  • Сложное изменение свойства — обновление свойства списка В этом примере мы добавим новые элементы в свойство списка, например, новые комментарии отзывов в список reviews в ProductStruct. Этот пример показывает, как работать со списком вложенных объектов.
Future addNewReviews(ProductStruct product) {
product.reviews ??= []; // Initialize the reviews list if it's null
product.reviews!.addAll([
ReviewStruct(rating: 5, comment: 'Excellent product!'),
ReviewStruct(rating: 4, comment: 'Good quality, but a bit expensive.'),
ReviewStruct(rating: 3, comment: 'Satisfactory, meets expectations.'),
]);
}

или если новый список отзывов предоставляется в пользовательское действие, то:

Future addDynamicReviews(ProductStruct product, List<ReviewStruct> newReviews) {
product.reviews ??= []; // Initialize the reviews list if it's null
product.reviews!.addAll(newReviews); // Add the new reviews
}

Использование переменных аутентификации Firebase в пользовательском коде

При использовании аутентификации Firebase в вашем приложении FlutterFlow предоставляет доступ к ключевым данным аутентификации, таким как currentUserDisplayName, currentUserUid и другие. Эти переменные можно использовать в ваших пользовательских действиях для создания дополнительных функций, требующих таких распространенных данных от аутентифицированных пользователей.

Например, вы можете проверить, подтвержден ли адрес электронной почты пользователя, перед выполнением определенных действий:

if (currentUserEmailVerified) {
// Perform action for verified users
}

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

String directoryPath = '/users/' + currentUserUid + '/files';

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

  • currentUserEmail — адрес электронной почты текущего пользователя.

  • currentUserUid — уникальный идентификатор текущего пользователя.

  • currentUserDisplayName — отображаемое имя, установленное пользователем.

  • currentUserPhoto — URL фотографии профиля текущего пользователя.

  • currentPhoneNumber — номер телефона пользователя, если доступен.

  • currentJwtToken — JWT-токен текущего пользователя для безопасных запросов.

  • currentUserEmailVerified — булево значение, указывающее, подтверждена ли электронная почта пользователя.

  • Эти переменные упрощают интеграцию данных аутентификации Firebase в пользовательскую функциональность, улучшая пользовательский опыт.

Получение значений среды разработки в пользовательском коде

Аналогично FFAppState, FlutterFlow генерирует синглтон-класс FFDevEnvironmentValues в сгенерированном коде FlutterFlow, если вы используете среды разработки. Этот класс также можно получить из пользовательского кода, если это необходимо. Он генерируется на основе среды, выбранной пользователем на момент генерации кода.

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

Future getWebhookId() async {
// Add your function code here!
return FFDevEnvironmentValues().webhookId;
}

Доступ к компонентам библиотеки в пользовательском коде

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

Получение значений библиотеки

Аналогично классу FFAppState или FFDevEnvironmentValues, FlutterFlow генерирует синглтон-класс FFLibraryValues для проектов библиотек, который предоставляет прямой доступ к значениям библиотеки.

Для прямого доступа к значениям библиотеки в пользовательском коде:

Future getSchema(StateStruct? syncStatus) async {
print(FFLibraryValues().schema);
}

Получение пользовательского кода библиотеки

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

Например, если у вас есть библиотека с идентификатором проекта library_hybw3o, FlutterFlow добавит следующий импорт в ваш проект:

import 'package:library_hybw3o/flutter_flow/custom_functions.dart' as library_hybw3o_functions;

Теперь давайте используем пользовательские функции библиотеки в пользовательской функции проекта пользователя:

int getRandomIndex(List<int> indexList) {
final item = library_hybw3o_functions.getRandomItem(); // Library's custom function
// get Random Index
final randomNumber = math.Random();
return ...
}

Ручное добавление импортов библиотеки

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

Например, давайте импортируем пользовательские действия библиотеки в ресурс пользовательского виджета проекта пользователя.

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

// Custom import
import 'package:library_hybw3o/custom_code/actions/index.dart' as library_hybw3o_actions; // Assigning a custom alias to the import

// Example Widget code
class CustomDialog extends StatefulWidget {
const CustomDialog({
super.key,
this.width,
this.height,
});

final double? width;
final double? height;

@override
State<CustomDialog> createState() => _CustomDialogState();
}

class _CustomDialogState extends State<CustomDialog> {
@override
void initState() {
library_hybw3o_actions.getSchema(StateStruct()); // calling library custom action
super.initState();
}
@override
Widget build(BuildContext context) {
return Container(height: 50, width: 50);
}
}