ویجت Flutter سفارشی
با این ویجت میتوانید کد Dart یک رابط Flutter را داخل صفحهٔ اپادیتور قرار دهید؛ مثلاً ماشینحساب، بازی، ابزار نمایش داده یا کنترل اختصاصی بسازید. ویجت سفارشی در چیدمان صفحه مانند دیگر ویجتها قرار میگیرد و از طریق API ارتباطی، متغیرهای اپ را میخواند و عملکردهای تعریفشده در پنل را اجرا میکند.
برای استفاده از فایلهای آمادهٔ این راهنما، کافی است فایل Dart و پارامترهای نمونه را وارد کنید. برای تغییر رفتار کد، آشنایی با Dart و Flutter لازم است.
کد هنگام ساخت خروجی اپ کامپایل میشود. شبیهساز داخل پنل فعلاً جای ویجت و پیام ساخت خروجی را نمایش میدهد؛ کد سفارشی را اجرا نمیکند. برای دیدن نتیجه باید خروجی جدید بسازید و آن را اجرا کنید.
شروع سریع
- صفحهٔ موردنظر را باز کنید و داخل یک گروه روی دکمهٔ افزودن ویجت بزنید.
- ویجت Flutter سفارشی را انتخاب کنید.
- نامی برای تشخیص ویجت در فهرست بنویسید.
- کد را در ویرایشگر قرار دهید یا با بارگذاری فایل دارت، فایل
.dartرا وارد کنید. - اگر نمونه پارامتر دارد، آبجکت آن را در پارامترهای JSON بنویسید.
- در صورت نیاز، عملکردها را در فهرست عملکردهای همان ویجت با شناسهٔ مشخص اضافه کنید.
- در تنظیمات چیدمان، عرض و ارتفاع مناسب بدهید؛ برای نمونههای کارتمانند معمولاً عرض «به اندازه والد» و ارتفاع «به اندازه محتوا» مناسب است.
- ویجت و صفحه را ذخیره کنید، خروجی جدید بسازید و در اپ اجرا کنید.
برای اولین تجربه، ماشینحساب یا شمارنده را امتحان کنید.
تنظیمات فرم ویجت
| گزینه | کاربرد |
|---|---|
| نام ویجت | نام قابلشناسایی در فهرست ویجتهای صفحه؛ عنوان داخل رابط را خود کد تعیین میکند |
| ویرایشگر کد | نوشتن یا ویرایش سورس Dart همان ویجت |
| بارگذاری فایل دارت | واردکردن محتوای یک فایل .dart به ویرایشگر |
| نمونه بازی 2048 | قراردادن سورس آمادهٔ بازی و پارامتر ارتفاع آن در فرم |
| بزرگکردن ویرایشگر | بزرگکردن پنجرهٔ تنظیمات برای ویرایش راحتتر |
| پارامترهای JSON | تنظیمات ورودی مخصوص همین نمونه از ویجت |
| فهرست عملکردها | تعریف عملکردهای قابلفراخوانی از کد، با شناسهٔ دلخواه |
تنظیمات عمومی مانند اندازه، فاصله، پسزمینه، شرط نمایش و انیمیشن از بخشهای معمول تنظیمات ویجت در دسترساند. تعاملهایی مثل دکمه و کشیدن انگشت داخل رابط سفارشی را در کد خود ویجت تعریف کنید.
قرارداد فایل Dart
فایل باید تابعی با این نام و امضا داشته باشد:
import 'package:flutter/material.dart';
import 'package:my_app/appeditor/custom/AppEditorWidgetContext.dart';
Widget buildCustomWidget(
BuildContext context,
AppEditorWidgetContext app,
) {
return Padding(
padding: const EdgeInsets.all(16),
child: Text(app.params['title'] as String? ?? 'سلام از Flutter'),
);
}
پارامترهای این نمونه:
{
"title": "اولین ویجت من"
}
- تابع باید یک
Widgetبرگرداند. نام تابع و نوع ورودیها را تغییر ندهید. - به
main،runAppوMaterialAppجداگانه نیاز نیست؛ صفحه و پوستهٔ اپ از قبل وجود دارند. - میتوانید کلاسهای
StatelessWidget،StatefulWidgetو کلاسهای کمکی را در همان فایل تعریف کنید. - پروژههای چندفایلی را فعلاً باید در یک فایل جمع کنید؛ import فایل نسبی و
partپشتیبانی نمیشود. - سقف حجم کد هر ویجت ۲۵۶ کیلوبایت است.
- برای سازگاری با پوستهٔ اپ، از
Theme.of(context)استفاده کنید. جهت متن و چیدمان را در صورت نیاز باDirectionalityتعیین کنید.
ویجت دارای وضعیت
برای ورودی، شمارنده، انیمیشن یا بازی، تابع را به یک StatefulWidget وصل کنید:
import 'package:flutter/material.dart';
import 'package:my_app/appeditor/custom/AppEditorWidgetContext.dart';
Widget buildCustomWidget(BuildContext context, AppEditorWidgetContext app) {
return TapWidget(app: app);
}
class TapWidget extends StatefulWidget {
const TapWidget({super.key, required this.app});
final AppEditorWidgetContext app;
State<TapWidget> createState() => _TapWidgetState();
}
class _TapWidgetState extends State<TapWidget> {
int count = 0;
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () => setState(() => count++),
child: Text('تعداد لمس: $count'),
);
}
}
این شمارنده فقط در وضعیت داخلی ویجت نگهداری میشود. برای اشتراک با دیگر بخشهای اپ و ذخیرهٔ دائمی، نمونهٔ شمارندهٔ متصل به متغیر را ببینید.
پارامترهای JSON
پارامترها تنظیمات هر نمونه از ویجتاند و از app.params خوانده میشوند. کد یکسان میتواند در دو ویجت قرار بگیرد، اما عنوان، رنگ، نام متغیر و رفتار متفاوت داشته باشد.
{
"title": "شمارنده سفارشها",
"step": 5,
"storeOnDevice": true,
"variable": "order_count"
}
final title = app.params['title'] as String? ?? 'شمارنده';
final step = (app.params['step'] as num?)?.toDouble() ?? 1;
final storeOnDevice = app.params['storeOnDevice'] == true;
| نوع تنظیم | نمونهٔ کاربرد |
|---|---|
| ظاهر و متن | عنوان، متن دکمه، اندازهٔ قلم، فاصله و رنگ |
| رفتار | گام افزایش، سرعت انیمیشن، نمایش یک کنترل یا حالت دستی |
| اتصال به داده | نام متغیر ورودی یا خروجی برای هر نمونهٔ ویجت |
| دادهٔ اولیه | مقدار آغازین، گزینههای فهرست یا تنظیمات یک بازی |
پارامتر فقط زمانی اثر دارد که کد آن را بخواند. مثلاً اضافهکردن allowUndo به JSON بازی 2048 فعلی، دکمهٔ برگشت را غیرفعال نمیکند؛ کد نمونه فقط پارامتر height را مصرف میکند.
نکات نوشتن JSON:
- مقدار اصلی باید یک آبجکت باشد؛
{}برای بدون پارامتر معتبر است. - نام کلید و رشتهها را با کوتیشن دوتایی بنویسید.
- عدد را بدون کوتیشن و بولی را بهصورت
trueیاfalseبنویسید. - از کامنت، ویرگول اضافه در پایان و کوتیشن تکی استفاده نکنید.
- نام کلیدها به بزرگی و کوچکی حروف حساس است.
- هنگام تغییر نام متغیر در یک نمونه، مطمئن شوید کد امکان اتصال مجدد را دارد؛ نمونههای شمارنده، قطبنما و تراز این اتصال را انجام میدهند.
پارامترها محل نگهداری رمز و اطلاعات محرمانه نیستند؛ آنها بخشی از دادهٔ صفحهاند. مقدار زنده و قابلتغییر مثل امتیاز را در متغیر اپ قرار دهید.
API ارتباط با اپ
| API | کاربرد |
|---|---|
app.params | خواندن آبجکت پارامترهای همین ویجت؛ این Map در سطح اول فقطخواندنی است |
app.getVar(name) | خواندن مقدار خام یک متغیر، با زمینهٔ همان صفحه و ردیف لیست پویا |
app.hasVar(name) | بررسی وجود متغیر |
await app.setVar(name, value) | تغییر مقدار متغیری که قبلاً ساخته شده است |
await app.addVar(name: ..., value: ...) | ساخت متغیر؛ پیشفرض موقت و بدون بازنویسی مقدار قبلی |
app.watchVar(name) | Stream مقدار فعلی و تغییرات بعدی |
app.hasAction(name) | بررسی تعریفشدن شناسهٔ عملکرد در همین ویجت |
await app.runAction(name) | فراخوانی عملکرد نامدار با زمینهٔ همان صفحه |
app.showMessage(text) | نمایش پیام کوتاه |
app.pageId | شناسهٔ صفحهٔ میزبان؛ ممکن است null باشد |
app.mounted | فعالبودن نمونه و صفحهٔ میزبان |
app.preview | تشخیص حالت پیشنمایش؛ پیشنمایش فعلی کد سفارشی را اجرا نمیکند |
خواندن متغیر
final name = app.getVar('customer_name')?.toString() ?? 'کاربر';
final rawScore = app.getVar('score');
final score = rawScore is num ? rawScore.toDouble() : 0.0;
مقدار متغیر لزوماً رشته نیست؛ ممکن است عدد، بولی، Map، List یا null باشد. خواندن با getVar بهتنهایی رابط را هنگام تغییر مقدار بازسازی نمیکند؛ برای نمایش زنده از watchVar استفاده کنید.
ساخت، تغییر و ذخیرهٔ متغیر
await app.addVar(name: 'score', value: 0);
await app.setVar('score', 10);
await app.addVar(
name: 'best_score',
value: 120,
storeOnDevice: true,
overwrite: true,
);
storeOnDevice: false، پیشفرض: مقدار موقت است و برای حفظ بین اجراهای اپ مناسب نیست.storeOnDevice: true: مقدار روی همان دستگاه ذخیره میشود؛ بهمعنای ذخیره در سرور یا همگامشدن حساب کاربر نیست.overwrite: false، پیشفرض: اگر متغیر در همان نوع ذخیره وجود داشته باشد، مقدار قبلی حفظ میشود.overwrite: true: مقدار جدید جایگزین میشود.setVarمتغیر جدید نمیسازد. ابتدا با پنل یاaddVarآن را ایجاد کنید.- برای
addVarنام ساده مانندcalculator_resultانتخاب کنید؛ نقطه، مسیر آرایه و نام سیستمی برای ساخت متغیر مناسب نیست. - نام متغیرهای اپ مشترک است. دو نمونه با نام یکسان، دادهٔ یکدیگر را میبینند. برای استقلال، نامهای متفاوت بدهید.
- یک نام را همزمان برای متغیر موقت و دستگاه استفاده نکنید. تغییر پارامتر نوع ذخیره، دادهٔ قبلی را به نوع جدید منتقل نمیکند.
نمایش زنده با StreamBuilder
final values = app.watchVar('score');
// داخل build یک StatefulWidget که values را در initState نگه داشته است:
return StreamBuilder<dynamic>(
stream: values,
builder: (context, snapshot) {
return Text('امتیاز: ${snapshot.data ?? 0}');
},
);
در یک StatefulWidget، Stream را در initState بسازید و در فیلد نگه دارید؛ در هر build یک Stream جدید نسازید. اگر نام متغیر یا شیء app تغییر کرد، در didUpdateWidget اتصال را بهروز کنید. StreamBuilder هنگام تعویض Stream یا حذف ویجت، اشتراک قبلی را لغو میکند. نمونههای آماده این الگو را نشان میدهند.
اجرای عملکردهای پنل
- در فهرست عملکردهای ویجت، یک عملکرد اضافه کنید؛ مثلاً بازکردن صفحه، نمایش پیام یا تغییر متغیر.
- در ستون شناسه، نامی مانند
onResultبنویسید. - همین نام را با رعایت حروف بزرگ و کوچک در کد فراخوانی کنید.
if (app.hasAction('onResult')) {
await app.runAction('onResult');
}
شناسه، نام اتصال داخل همین ویجت است؛ لازم نیست کد Dart تنظیمات عملکرد را بداند. مثلاً در ماشینحساب، پس از نوشتن نتیجه در متغیر، onResult اجرا میشود. با تغییر عملکرد پنل، میتوانید نتیجه را در صفحهٔ دیگری نمایش دهید.
شرطها و زمینهٔ صفحه در مسیر عادی اجرای عملکرد اعمال میشوند. عملکردی که شرطش برقرار نباشد ممکن است اجرا نشود. فراخوانی نام تعریفنشده خطا ایجاد میکند؛ برای عملکرد اختیاری از hasAction استفاده کنید. await فراخوانی را مرتب میکند، اما لزوماً بهمعنای پایان همهٔ اثرهای بعدی مثل انیمیشن یا کارهای پسزمینهٔ آن عملکرد نیست.
try {
await app.runAction('onResult');
} catch (error) {
app.showMessage('اجرای عملکرد ممکن نشد.');
}
امکانات تکمیلی Context
| API | رفتار |
|---|---|
app.interpolate(text) | جایگذاری متغیرهای متن با زمینهٔ صفحه و ردیف فعلی |
await app.removeVar(name) | حذف متغیر؛ متغیر سیستمی حذف نمیشود |
await app.openPage(id, query: ..., replace: false) | بازکردن صفحه؛ پشتیبانی از removeUntil، displayMode: 'dialog' / 'sheet'، widthRatio، heightRatio و dismissible |
app.closePage() | بستن صفحه یا لایهٔ دیالوگ/شیت فعلی |
await app.openLink(url, inner: false, useCustomTab: false) | بازکردن لینک با جایگذاری متغیرها |
await app.showDialog(title: ..., message: ..., buttonText: ...) | دیالوگ ساده |
await app.copyText(text)، await app.pasteText() | نوشتن و خواندن کلیپبورد؛ خواندن ممکن است null برگرداند |
await app.shareText(text) | اشتراک متن |
await app.vibrate(duration: 500) | لرزش با مدت میلیثانیه |
await app.openDialer(number) | بازکردن شمارهگیر؛ نتیجهٔ bool |
await app.openEmail(email, subject: ..., body: ...) | بازکردن برنامهٔ ایمیل؛ نتیجهٔ bool |
await app.openImage(src, shareAble: true) | نمایش تصویر |
await app.openVideo(src, position: ..., shareAble: true, saveAble: true) | نمایش ویدئو؛ position از نوع Duration |
app.preview | آیا برنامه در حالت پیشنمایش است |
این توابع از عملکردهای موجود Act استفاده میکنند و محدودیت پلتفرم همان
عملکردها را دارند؛ مثلاً کپی و اشتراک متن در وب توسط Act اجرا نمیشود.
عملیات پس از dispose اجرا نمیشوند؛ ارسال درخواست در این وضعیت StateError
میدهد. درخواست شروعشده با dispose لغو نمیشود؛ پیش از تغییر UI بعد از await،
app.mounted و mounted ویجت خودتان را بررسی کنید.
ارسال درخواست
request از Requester مشترک اپ استفاده میکند و sys.rest.loading را بهروز
میکند. مقدار پیشفرض متد GET و نوع بدنه JSON است. متدهای RequestType.Get،
Post، Put، Patch و Delete پشتیبانی میشوند. این نوعها و MyResponse،
ResponseErrorType، FormData و MultipartFile از فایل Context export شدهاند.
final result = await app.request(
'https://example.com/api/items',
method: RequestType.Post,
queryParameters: {'page': 1},
headers: {'Authorization': 'Bearer ${app.getVar('token')}'},
data: {'title': 'عنوان جدید'},
);
if (!app.mounted) return;
if (result.success) {
await app.setVar('items', result.data);
} else {
app.showMessage('خطای درخواست: ${result.errorType}');
}
queryParameters برای همهٔ متدها قابل استفاده است و کلیدهای همنام در URL را
جایگزین میکند. URL باید کامل و HTTP/HTTPS باشد؛ متغیرهای URL با زمینهٔ صفحه
جایگذاری میشوند. مقادیر بدنه و هدر را مستقیماً با getVar یا interpolate
بسازید. توکن ورود اپ خودکار به سرویس مقصد ارسال نمیشود.
برای فرم معمولی contentType: 'application/x-www-form-urlencoded' و data
بدهید. برای آپلود، formData: FormData.fromMap({...}) بدهید؛ نوع محتوا خودکار
multipart میشود و نباید همزمان data بدهید. پارامتر responseType یکی از
json (پیشفرض؛ آبجکت یا آرایه)، raw (دادهٔ پردازششدهٔ Dio) یا xml است.
پاسخ شامل data، success، hasError، errorType و response است؛ کد HTTP
در result.response?.statusCode قرار دارد. خطاهای شبکه و HTTP در همین نتیجه
برمیگردند. خطاهای آرگومان استثنا میدهند.
زمانهای انتظار مثبت و برحسب ثانیهاند: connectTimeoutSeconds: 10،
sendTimeoutSeconds: 10 و receiveTimeoutSeconds: 30.
در خروجی وب، سرویس مقصد باید CORS مناسب داشته باشد.
نمونههای آماده
هر نمونه فایل مستقل Dart، پارامترهای پیشنهادی و روش استفاده دارد:
| نمونه | چه چیزی یاد میگیرید؟ | وضعیت |
|---|---|---|
| ماشینحساب | ورودی، محاسبه، نوشتن نتیجه و اجرای عملکرد | بدون وابستگی جدید |
| شمارنده | خواندن زنده، متغیر مشترک و ذخیره روی دستگاه | بدون وابستگی جدید |
| قطبنما | نمایش زاویه، اتصال به متغیر و کنترل دستی | حالت دستی و سنسور |
| تراز | دو ورودی زنده، آستانه و نمایش شیب | حالت دستی و سنسور |
| سنسورها | دادهٔ زنده، وضعیت، شروع و توقف و خطا | متصل به عملکرد سنسور پنل |
| بازی 2048 | تبدیل بازی به ویجت، امتیاز، رکورد و رویدادها | نمونهٔ آمادهٔ پنل |
پکیجها، پلاگینها و سنسورها
نسخهٔ فعلی فقط اجازهٔ استفاده از پکیجهای موجود در همان خروجی و با همان نسخهها را میدهد. این ویجت تنظیمی برای افزودن پکیج یا تغییر pubspec، Gradle، Manifest و فایلهای بومی ندارد.
- import کتابخانههای Dart مانند
dart:mathوdart:asyncو APIهای Flutter مجاز است. - از پکیج موجود میتوانید استفاده کنید؛ مثلاً
dio،shared_preferencesیاflutter_svg، اگر در همان خروجی حاضر باشد. - برای پکیجهای شرطی، فعالبودن قابلیت مربوط در خروجی اهمیت دارد.
- از فایلهای داخلی اپادیتور فقط SDK ویجت با مسیر معرفیشده قابل import است.
- import نسبی،
partو پکیج نصبنشده پذیرفته نمیشود. - موجودبودن یک پکیج بهمعنای پشتیبانی تمام قابلیتهای آن روی همهٔ پلتفرمها نیست. قابلیتی که به تنظیم بومی جدید نیاز دارد در این مرحله قابل اضافهکردن نیست.
sensors_plus: 6.1.2 فعال است. عملکردهای «شروع سنسور» و «توقف سنسور» دادهٔ شتابسنج، شتاب حرکت، ژیروسکوپ و تکان را در متغیر موقت مینویسند؛ با watchVar آن را بخوانید یا عملکرد را با runAction اجرا کنید. Context متد مستقلی مثل startSensor ندارد. تراز این راهنما به خروجی شتابسنج وصل میشود و قطبنما در حالت sensor: true مستقیماً مغناطیسسنج پکیج را میخواند.
پکیجهای فعال در خروجی
فهرست زیر از تنظیمات سازندهٔ فعلی اپادیتور استخراج شده است؛ نسخهها نسخهٔ
خروجی هستند، نه الزاماً آخرین انتشار پکیج. در خروجی قدیمی ممکن است متفاوت
باشند. SDKهای Dart و Flutter (از جمله material.dart، widgets.dart،
services.dart، dart:async، dart:math و dart:convert) نیز در دسترساند.
برای هر پکیج، import عمومی خود آن را بنویسید؛ برای مثال:
import 'package:sensors_plus/sensors_plus.dart';
import 'package:flutter_svg/flutter_svg.dart';
| پکیج فعال | نسخه در سازنده |
|---|---|
cupertino_icons | 1.0.8 |
path_provider | 2.1.5 |
dio | 5.9.0 |
xml | 6.6.1 |
webfeed_plus | 1.1.2 |
flutter_widget_from_html | 0.17.1 |
flutter_widget_from_html_core | 0.17.0 |
flutter_inappwebview | 6.1.5 |
validators | 3.0.0 |
cached_network_image | 3.4.1 |
flutter_svg | 2.2.2 |
flutter_sequence_animation | 4.0.0-nullsafety |
shared_preferences | 2.5.3 |
flutter_spinkit | 5.2.2 |
flutter_xlider | 3.5.0 |
photo_view | 0.15.0 |
card_swiper | 3.0.1 |
flutter_custom_tabs | 2.4.0 |
mime | 2.0.0 |
internet_connection_checker_plus | 3.1.1 |
connectivity_plus | 7.3.1 |
just_audio | 0.10.5 |
audio_session | 0.2.2 |
audio_service | 0.18.18 |
rxdart | 0.28.0 |
percent_indicator | 4.2.5 |
device_info_plus | 11.5.0 |
simple_barcode_scanner | 0.6.0 |
wakelock_plus | 1.4.0 |
video_player | 2.10.1 |
chewie | 1.13.0 |
sqflite | 2.4.3 |
pinput | 1.2.2 |
image | 4.5.4 |
image_picker | 1.1.2 |
image_cropper | 11.0.0 |
flutter_secure_storage | 9.2.4 |
shamsi_date | 1.1.1 |
timeago | 3.7.1 |
intl | 0.19.0 |
encrypt | 5.0.3 |
archive | 4.0.7 |
substring_highlight | 1.0.33 |
page_route_animator | 1.0.4 |
share_plus | 12.0.1 |
permission_handler | 12.0.3 |
vibration | 3.2.1 |
sensors_plus | 6.1.2 |
flutter_local_notifications | 22.2.0 |
flutter_timezone | 5.0.1 |
timezone | 0.11.1 |
flutter_js | 0.8.7 |
sqflite_common_ffi | 2.4.1 |
sqflite_common_ffi_web | 1.1.2 |
syncfusion_flutter_pdfviewer | 30.2.7 |
window_manager | 0.5.1 |
پکیجهای زیر شرطی هستند و صرفِ وجود ویجت سفارشی آنها را فعال نمیکند:
| پکیج | نسخه | شرط فعالشدن |
|---|---|---|
adivery | 4.9.0 | تبلیغات ادیوری در خروجی فعال باشد |
tapsell_plus | 2.3.2 | تبلیغات تپسل در خروجی فعال باشد |
firebase_core، firebase_messaging | 4.13.0، 16.5.0 | قابلیت اعلان مربوط در سازنده فعال و خروجی Android باشد |
flutter_poolakey | 2.2.0+1.0.0 | پرداخت درونبرنامهای بازار با سیستم پرداخت فروشگاه |
myket_iap | 1.1.12 | پرداخت درونبرنامهای مایکت با سیستم پرداخت فروشگاه |
flutter_compass در این فهرست نیست. برای مثال قطبنما از مغناطیسسنج
sensors_plus استفاده شده است. وابستگیهای غیرمستقیم و پکیجهای تست را
قرارداد ثابت ویجت در نظر نگیرید. حضور پکیج بهمعنای آمادهبودن تنظیمات بومی،
مجوزها یا پشتیبانی همهٔ APIها در وب/Windows نیست. نمونهٔ سنسورها و
راهنمای رسمی نسخهٔ پکیج
محدودیتهای سنسور را توضیح میدهند.
چیدمان و چرخهٔ عمر
- برای ابزارهای کارتمانند، ارتفاع «به اندازه محتوا» را انتخاب کنید.
- برای بازی یا رابطی با صفحهٔ کامل، ارتفاع مشخص یا اندازهٔ مناسب والد بدهید؛
Expandedداخل ارتفاع نامحدود خطا ایجاد میکند. - پیش از استفاده از
LayoutBuilderیا اندازهٔ صفحه، محدودیتهای والد را در نظر بگیرید؛ نمونهٔ 2048 برای ارتفاع آزاد مقدار جایگزین دارد. - متغیر را داخل
buildتغییر ندهید و از آنجا عملکرد اجرا نکنید؛ بازسازیهای رابط ممکن است این کار را چندبار تکرار کنند. - کار آغازین را در
initStateو در صورت نیاز پس از اولین frame انجام دهید. - پس از
await، قبل ازsetStateیا ادامهٔ کار رابط،mountedرا بررسی کنید. Timer،StreamSubscription،TextEditingControllerوAnimationControllerهای خودتان را درdisposeآزاد کنید.
ذخیره، انتشار آنلاین و ساخت خروجی
| تغییر | آیا خروجی جدید لازم است؟ |
|---|---|
| تغییر کد Dart، حتی عنوانی که داخل سورس نوشته شده | بله |
| تغییر مقدار پارامتری که کد موجود از قبل مصرف میکند | خیر؛ ذخیره و انتشار صفحه کافی است، بهشرط دریافت نسخهٔ جدید صفحه توسط اپ |
| تغییر عملکردهای نامدار | معمولاً خیر؛ اگر قابلیت یا منابع لازم در خروجی قبلی موجود باشد |
| تغییر مقدار متغیر در اپ | خیر |
| افزودن پکیج یا تنظیم بومی جدید | در این قابلیت پشتیبانی نمیشود |
متن سورس با تنظیمات ویجت در پنل ذخیره میشود. در خروجی ساختهشده، کد به فایل Dart تبدیل میشود و دادهٔ صفحه فقط شناسهٔ کد کامپایلشده را دارد. انتشار آنلاین سورس جدید، آن را روی نسخهٔ قدیمی نصبشده قابلاجرا نمیکند؛ اپ برای کد ناشناخته پیام ساخت خروجی جدید نمایش میدهد.
چند ویجت با سورس یکسان از یک فایل کامپایلشده استفاده میکنند. وضعیت معمول StatefulWidget و پارامترهای هر نمونه جداست، اما متغیرهای سراسری و static در فایل Dart مشترکاند؛ برای دادهٔ مخصوص یک نمونه از آنها استفاده نکنید.
رفع اشکال
| مشکل | بررسی پیشنهادی |
|---|---|
| شبیهساز فقط پیام نشان میدهد | رفتار فعلی است؛ نمونه را در خروجی ساختهشده اجرا کنید |
| «کد این ویجت در این نسخه از اپ وجود ندارد» | سورس صفحه با خروجی نصبشده متفاوت است؛ خروجی جدید بسازید |
خطای تابع buildCustomWidget | نام، امضا و نوع بازگشتی را با نمونهٔ قرارداد مقایسه کنید |
| خطای وابستگی نامجاز | پکیج باید از قبل در همان خروجی موجود باشد؛ import نسبی و part را حذف کنید |
| خطای کامپایل Dart | گزارش ساخت را بخوانید؛ امضاها، نوع دادهها و API پکیجها را بررسی کنید |
| پارامتر اثر ندارد | کلید و نوع مقدار را بررسی کنید و مطمئن شوید کد آن را مصرف میکند |
| متغیر نمایش داده نمیشود | نام دقیق، ایجادشدن متغیر، نوع داده و استفاده از watchVar را بررسی کنید |
| عملکرد اجرا نمیشود | شناسه، تعریف آن در همان ویجت، شرط عملکرد و فعالبودن صفحه را بررسی کنید |
| خطای اندازه یا overflow | محدودیت والد، ارتفاع آزاد، Expanded و اندازهٔ ثابت را بررسی کنید |
| قطبنما یا تراز با حرکت گوشی تغییر نمیکند | برای تراز sensorVariable و عملکرد شروع سنسور، برای قطبنما sensor: true و وجود مغناطیسسنج دستگاه را بررسی کنید |
خطا در ساخت اولیهٔ ویجت ممکن است با پیام خطا نمایش داده شود؛ خطاهای فرزندان، callbackها و عملیات غیرهمزمان همچنان به رسیدگی داخل کد نیاز دارند. کد سفارشی بخشی از خود اپ است و محیط اجرای جدا و محدودشده ندارد؛ فایلهایی را وارد کنید که رفتارشان را میشناسید.