بعد استراحة طويلة ، سأواصل الحديث عن إطار Flutter الشهير في شكل سؤال وجواب. يمكنك العثور على المقالة الأولى لمطوري Android
هنا ، واليوم ستكون هناك مواد مفيدة لمطوري نظام التشغيل iOS.
إذا كان لديك القليل من الوقت للدراسة المستقلة والمتعمقة للوثائق ، لكنك تريد أن تفهم ما هو رفرفة جيدة وكيفية استخدامها ، نلقي نظرة تحت القط.
رفرفة. الجزء 1. لمطوري أندرويدرفرفة. الجزء 2. لمطوري دائرة الرقابة الداخليةرفرفة. الجزء 3. للمطورين رد فعل الأصليةرفرفة. الجزء 4. لمطوري الويبرفرفة. الجزء 5. ل Xamarin.Forms المطورين
المحتويات:
- المشاهدات
- ملاحة
- خيوط وعدم التزامن
- هيكل المشروع والموارد
- ViewControllers
- تخطيطات
- الإيماءات والتعامل مع الحدث اللمس
- تصميم التطبيق
- شكل الإدخال
- الإضافات الرفرفة
- قواعد البيانات والتخزين المحلي
- إشعار
المشاهدات
السؤال:
ما هو
التناظرية UIView في رفرفة؟
الجواب هو:
القطعةالاختلافات:
UIView هو في الواقع ما سيكون على الشاشة. يتم استدعاء SetNeedsDisplay () لعرض التغييرات.
القطعة - وصف لما سيكون على الشاشة. من أجل التغيير يتم إنشاؤه من جديد.
معلومات اضافية:
يتضمن
Flutter مكتبة
Cupertino Widgets . أنه يحتوي على عناصر واجهة تعامل تطبيق
إرشادات Apple Design .
السؤال:
كيفية تحديث عرض الحاجيات؟
الجواب هو:
باستخدام
StatefulWidget وحالتها . يحتوي Flutter على نوعين من الحاجيات:
StatelessWidget و
StatefulWidget . أنها تعمل بنفس الطريقة ، والفرق الوحيد هو في حالة التقديم.
الاختلافات:
StatelessWidget لديه حالة غير قابلة للتغيير. مناسب لعرض النص والشعار ، إلخ. أي إذا كان يجب عدم تغيير العنصر على الشاشة خلال وقت العرض بالكامل ، فهذا يناسبك. كما يمكن استخدامه كحاوية لعناصر واجهة المستخدم.
يحتوي StatefulWidget على حالة الولاية ، التي تخزّن معلومات حول الحالة الحالية. إذا كنت ترغب في تغيير عنصر على الشاشة عند إجراء بعض الإجراءات (جاءت استجابة من الخادم ، فقد نقر المستخدم على زر ، وما إلى ذلك) - هذا هو خيارك.
مثال:
1) StatelessWidget - النص
Text( 'I like Flutter!', style: TextStyle(fontWeight: FontWeight.bold), );
2) StatefulWidget - عند النقر فوق الزر (FloatingActionButton) ، يتغير النص الموجود في عنصر واجهة تعامل النص من
I Like Flutter إلى
Flutter! import 'package:flutter/material.dart'; void main() { runApp(SampleApp()); } class SampleApp extends StatelessWidget {
السؤال:
كيفية تخطيط الشاشة مع الحاجيات؟ أين هي
لوحة العمل ؟
الجواب هو:
Flutter has no
القصة المصورة . كل شيء تنضيد في شجرة القطعة مباشرة في التعليمات البرمجية.
مثال:
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Sample App"), ), body: Center( child: CupertinoButton( onPressed: () { setState(() { _pressedCount += 1; }); }, child: Text('Hello'), padding: EdgeInsets.only(left: 10.0, right: 10.0), ), ), ); }
يمكن الاطلاع على جميع الحاجيات الافتراضية في Flutter في
كتالوج عنصر واجهة المستخدم .
السؤال:
كيفية إضافة أو إزالة مكون في التخطيط أثناء تشغيل التطبيق؟
الجواب هو:
من خلال وظيفة من شأنها أن ترجع القطعة المطلوبة اعتمادا على الدولة.
الاختلافات:
على نظام التشغيل iOS ، يمكنك القيام بـ addSubview () أو إزالةFromSuperview (). في الرفرفة ، هذا غير ممكن ، لأن الحاجيات لم تتغير. فقط حالتهم يمكن أن تتغير.
مثال:
تغيير النص إلى زر من خلال النقر على FloatingActionButton.
class SampleApp extends StatelessWidget {
السؤال:
كيفية تحريك الحاجيات؟
الجواب هو:
باستخدام فئة
AnimationController ، وهو سليل فئة الملخص
<T> المتحركة . بالإضافة إلى بدء تشغيل الرسوم المتحركة ، يمكنه إيقافها مؤقتًا والرجوع إليها والتوقف عنها وتشغيلها في الاتجاه المعاكس. يعمل مع
تكر ، الذي يبلغ عن إعادة رسم الشاشة.
الاختلافات:
على iOS ، يمكنك تحريك مشاهدة باستخدام تحريك (withDuration: animations :). في Flutter ، يجب كتابة الرسوم المتحركة في التعليمات البرمجية باستخدام AnimationController.
معلومات اضافية:
يمكنك معرفة المزيد في عناصر
الرسوم المتحركة والحركة ، والبرنامج
التعليمي للرسوم المتحركة ، والنظرة العامة للرسوم المتحركة .
مثال:
تتلاشى الرسوم المتحركة لشعار الرفرفة.
class SampleApp extends StatelessWidget {
السؤال:
كيفية استخدام
CoreGraphics ؟
الجواب هو:
يستخدم
Flutter واجهة برمجة تطبيقات Canvas على
محرك Skia ذي المستوى المنخفض بدلاً من CoreGraphics. يستخدم Android واجهة برمجة تطبيقات Canvas مماثلة.
معلومات اضافية:
يحتوي
Flutter على فئتين للرسم على Canvas:
CustomPaint و
CustomPainter . الثاني ينفذ خوارزمية التقديم.
اقرأ المزيد هنا:
StackOverflowمثال:
class SignaturePainter extends CustomPainter { SignaturePainter(this.points); final List<Offset> points; void paint(Canvas canvas, Size size) { var paint = Paint() ..color = Colors.black ..strokeCap = StrokeCap.round ..strokeWidth = 5.0; for (int i = 0; i < points.length - 1; i++) { if (points[i] != null && points[i + 1] != null) canvas.drawLine(points[i], points[i + 1], paint); } } bool shouldRepaint(SignaturePainter other) => other.points != points; } class Signature extends StatefulWidget { SignatureState createState() => SignatureState(); } class SignatureState extends State<Signature> { List<Offset> _points = <Offset>[]; Widget build(BuildContext context) { return GestureDetector( onPanUpdate: (DragUpdateDetails details) { setState(() { RenderBox referenceBox = context.findRenderObject(); Offset localPosition = referenceBox.globalToLocal(details.globalPosition); _points = List.from(_points)..add(localPosition); }); }, onPanEnd: (DragEndDetails details) => _points.add(null), child: CustomPaint(painter: SignaturePainter(_points), size: Size.infinite), ); } }
السؤال:
كيفية تغيير شفافية الحاجيات؟
الجواب هو:
التفاف في القطعة
العتامة .
الاختلافات:
على iOS ، كل المشاهدات لها .opacity أو .alpha. في Flutter ، يستبدل هذا الخيار عنصر واجهة المجمع.
السؤال:
كيفية إنشاء الحاجيات المخصصة؟
الجواب هو:
إنشاء الحاجيات داخل واحد (بدلا من الميراث).
الاختلافات:
في نظام التشغيل iOS ، يمكنك أن ترث من طريقة العرض التي نهتم بها ونضيف منطقك الخاص. في Flutter ، يتم توارث عنصر واجهة المستخدم دائمًا من StatelessWidget أو StatefulWidget. أي تحتاج إلى إنشاء عنصر واجهة مستخدم جديد واستخدامه في مجموعة عناصر واجهة المستخدم التي تحتاج إليها كمعلمات أو حقول.
مثال:
class CustomButton extends StatelessWidget { final String label; CustomButton(this.label); @override Widget build(BuildContext context) { return RaisedButton(onPressed: () {}, child: Text(label)); } } @override Widget build(BuildContext context) { return Center( child: CustomButton("Hello"), ); }
ملاحة
السؤال:
كيفية تنفيذ التنقل بين الشاشات في الرفرفة؟
الجواب هو:
للتنقل بين الشاشات ، يتم استخدام فئتي
Navigator و
Route .
الاختلافات:
لا يوجد لدى Flutter مفاهيم مثل UIViewController و UINavigationController. هناك المستكشف (المستكشف) والطرق (الطرق). يشبه Navigator أداة التحكم UINavigationController من حيث المبدأ. يمكنه القيام
بالدفع () أو
pop () إلى المسار الذي تحدده. Route هو نوع من UIViewController ، لكن في Flutter من المعتاد مقارنة ذلك بشاشة أو صفحة.
لدى Flutter طريقتان للملاحة:
- وصف الخريطة مع أسماء الطريق
- انتقل مباشرة إلى الطريق.
مثال:
void main() { runApp(CupertinoApp( home: MyAppHome(),
السؤال:
كيفية التنقل إلى تطبيق جهة خارجية؟
الجواب هو:
إما التفاعل مع طبقة iOS للتطبيق من خلال
MethodChannel ، أو باستخدام المكون الإضافي
لمشغل URL .
السؤال:
كيفية جعل البوب العودة في دائرة الرقابة الداخلية ViewController؟
الجواب هو:
عن طريق استدعاء SystemNavigator.pop ().
معلومات اضافية:
يستدعي SystemNavigator.pop () من رمز Dart التعليمة البرمجية التالية في iOS:
UIViewController* viewController = [UIApplication sharedApplication].keyWindow.rootViewController; if ([viewController isKindOfClass:[UINavigationController class]]) { [((UINavigationController*)viewController) popViewControllerAnimated:NO]; }
إذا لم يكن هذا هو ما تحتاجه ، فيمكنك القيام بالتنفيذ من خلال
MethodChannel .
خيوط وعدم التزامن
السؤال:
كيف تكتب كود غير متزامن في الرفرفة؟
الجواب هو:
تقوم Dart بتنفيذ نموذج تنفيذ أحادي الترابط يتم تشغيله على
Isolates . يستخدم التنفيذ غير المتزامن async / await ، والذي قد تكون على دراية به من coroutines C # أو JavaScript أو Kotlin.
مثال:
تلبية الطلب وإرجاع النتيجة لتحديث واجهة المستخدم:
loadData() async { String dataURL = "https://jsonplaceholder.typicode.com/posts"; http.Response response = await http.get(dataURL); setState(() { widgets = json.decode(response.body); }); }
عند تلقي استجابة الطلب ، تحتاج إلى استدعاء الأسلوب
setState () لإعادة رسم شجرة القطعة باستخدام البيانات الجديدة.
مثال:
تحميل وتحديث البيانات في
ListView :
import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; void main() { runApp(SampleApp()); } class SampleApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Sample App', theme: ThemeData( primarySwatch: Colors.blue, ), home: SampleAppPage(), ); } } class SampleAppPage extends StatefulWidget { SampleAppPage({Key key}) : super(key: key); @override _SampleAppPageState createState() => _SampleAppPageState(); } class _SampleAppPageState extends State<SampleAppPage> { List widgets = []; @override void initState() { super.initState(); loadData(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Sample App"), ), body: ListView.builder( itemCount: widgets.length, itemBuilder: (BuildContext context, int position) { return getRow(position); })); } Widget getRow(int i) { return Padding( padding: EdgeInsets.all(10.0), child: Text("Row ${widgets[i]["title"]}") ); } loadData() async { String dataURL = "https://jsonplaceholder.typicode.com/posts"; http.Response response = await http.get(dataURL); setState(() { widgets = json.decode(response.body); }); } }
السؤال:
كيفية تنفيذ التعليمات البرمجية في موضوع الخلفية؟
الجواب هو:
كما ذكر أعلاه - استخدام المتزامن / انتظار والعزلة (عزل).
الاختلافات:
من خارج منطقة الجزاء على iOS ، يمكنك استخدام العملية مع إعادة تعريف محتملة للطرق. في Flutter "خارج الصندوق" ، تحتاج فقط إلى استخدام المزامنة / الانتظار ، وسيتولى دارت الاهتمام بالباقي.
مثال:
هنا يتم عزل أسلوب dataLoader (). بمعزل ، يمكنك تشغيل عمليات ثقيلة مثل تحليل JSONs الكبيرة والتشفير ومعالجة الصور ، إلخ.
loadData() async { ReceivePort receivePort = ReceivePort(); await Isolate.spawn(dataLoader, receivePort.sendPort);
السؤال:
كيفية جعل طلبات الشبكة في رفرفة؟
الجواب هو:
لدى Flutter
حزمة HTTP الخاصة بها.
مثال:
لاستخدام حزمة HTTP ، أضفها كتبعية في pubspec.yaml:
dependencies: ... http: ^0.11.3+16
لتنفيذ الطلب ، يرجى الانتظار في وظيفة المتزامن http.get ():
import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; [...] loadData() async { String dataURL = "https://jsonplaceholder.typicode.com/posts"; http.Response response = await http.get(dataURL); setState(() { widgets = json.decode(response.body); }); } }
السؤال:
كيف تظهر التقدم؟
الجواب هو:
باستخدام أداة
ProgressIndicator .
مثال:
import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; void main() { runApp(SampleApp()); } class SampleApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Sample App', theme: ThemeData( primarySwatch: Colors.blue, ), home: SampleAppPage(), ); } } class SampleAppPage extends StatefulWidget { SampleAppPage({Key key}) : super(key: key); @override _SampleAppPageState createState() => _SampleAppPageState(); } class _SampleAppPageState extends State<SampleAppPage> { List widgets = []; @override void initState() { super.initState(); loadData(); } showLoadingDialog() { return widgets.length == 0; } getBody() { if (showLoadingDialog()) { return getProgressDialog(); } else { return getListView(); } } getProgressDialog() { return Center(child: CircularProgressIndicator()); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Sample App"), ), body: getBody()); } ListView getListView() => ListView.builder( itemCount: widgets.length, itemBuilder: (BuildContext context, int position) { return getRow(position); }); Widget getRow(int i) { return Padding(padding: EdgeInsets.all(10.0), child: Text("Row ${widgets[i]["title"]}")); } loadData() async { String dataURL = "https://jsonplaceholder.typicode.com/posts"; http.Response response = await http.get(dataURL); setState(() { widgets = json.decode(response.body); }); } }
هيكل المشروع والموارد
السؤال:
حيث لتخزين الموارد من قرارات مختلفة؟
الجواب هو:
في الأصول.
الاختلافات:
في iOS ، تحتوي الموارد الرسومية على Images.xcasset ، والتي توجد في مجلد الأصول. رفرفة لديها الأصول فقط. يمكن تحديد موقع مجلد الموارد في أي مكان في المشروع ، والأهم من ذلك ، كتابة المسار إليه في ملف pubspec.yaml.
معلومات اضافية:
أحجام الموارد الرسومية في iOS و Flutter متطابقة وتتبع التنسيق المستند إلى الكثافة.
موقع المورد:
images/my_icon.png // Base: 1.0x image images/2.0x/my_icon.png // 2.0x image images/3.0x/my_icon.png // 3.0x image
المسار في ملف pubspec.yaml:
assets: - images/my_icon.png
باستخدام
AssetImage :
return AssetImage("images/a_dot_burr.jpeg");
باستخدام الأصول مباشرة:
@override Widget build(BuildContext context) { return Image.asset("images/my_image.png"); }
السؤال:
حيث لتخزين السلاسل؟ كيفية توطينهم؟
الجواب هو:
تخزينها في الحقول الثابتة. توطين باستخدام
حزمة intl .
مثال:
class Strings { static String welcomeMessage = "Welcome To Flutter"; } Text(Strings.welcomeMessage)
السؤال:
ما هو نظيره ل CocoaPods؟ كيفية إضافة التبعيات؟
الجواب هو:
pubspec.yaml.
معلومات اضافية:
يقوم برنامج Flutter بتفويض الإنشاء إلى مُنشئي Android و iOS الأصليين. انظر قائمة بجميع المكتبات الشعبية لـ Flutter في
Pub .
ViewControllers
السؤال:
ما هو ما يعادل
ViewController في رفرفة؟
الجواب هو:
كل شيء في رفرفة هو الحاجيات. يتم لعب دور ViewController للعمل مع واجهة المستخدم بواسطة عناصر واجهة المستخدم. ودور الملاحة ، كما ذكر في الفقرة على الملاحة ، هو Navigator و Route.
السؤال:
كيفية التعامل مع أحداث دورة الحياة؟
الجواب هو:
باستخدام الأسلوب
WidgetsBinding و
didChangeAppLifecycleState () .
معلومات اضافية:
يستخدم Flutter FlutterAppDelegate في الكود الأصلي ، ويجعل محرك Flutter تغييرات حالة المعالجة غير واضحة قدر الإمكان. ولكن إذا كنت لا تزال بحاجة إلى القيام ببعض الأعمال حسب الحالة ، فدورة الحياة تختلف قليلاً:
- غير نشط - التطبيق غير نشط ولا يتلقى إدخال المستخدم. هذه الحالة موجودة فقط في نظام التشغيل iOS ، ولا يوجد في نظام Android أي تناظر ؛
- تم الإيقاف مؤقتًا - التطبيق غير مرئي حاليًا للمستخدم ، ولا يستجيب لإدخالات المستخدم ، ولكنه يعمل في الخلفية ؛
- تم استئناف - التطبيق مرئي ويستجيب لإدخال المستخدم ؛
- تعليق - التطبيق في عملية التوقف. هذه الحالة موجودة فقط على نظام Android ، في نظام iOS لا يوجد نظير لها.
تم توضيح ذلك بمزيد من التفاصيل في
وثائق AppLifecycleStatus .
مثال:
import 'package:flutter/widgets.dart'; class LifecycleWatcher extends StatefulWidget { @override _LifecycleWatcherState createState() => _LifecycleWatcherState(); } class _LifecycleWatcherState extends State<LifecycleWatcher> with WidgetsBindingObserver { AppLifecycleState _lastLifecycleState; @override void initState() { super.initState(); WidgetsBinding.instance.addObserver(this); } @override void dispose() { WidgetsBinding.instance.removeObserver(this); super.dispose(); } @override void didChangeAppLifecycleState(AppLifecycleState state) { setState(() { _lastLifecycleState = state; }); } @override Widget build(BuildContext context) { if (_lastLifecycleState == null) return Text('This widget has not observed any lifecycle changes.', textDirection: TextDirection.ltr); return Text('The most recent lifecycle state this widget observed was: $_lastLifecycleState.', textDirection: TextDirection.ltr); } } void main() { runApp(Center(child: LifecycleWatcher())); }
تخطيطات
السؤال:
ما هو ما يعادل
UITableView و
UICollectionView ؟
الجواب هو:
يكون ListView .
مثال:
import 'package:flutter/material.dart'; void main() { runApp(SampleApp()); } class SampleApp extends StatelessWidget {
السؤال:
كيف أعرف عنصر القائمة الذي تم النقر عليه؟
الجواب هو:
يجب أن يتعامل عنصر واجهة المستخدم ، وهو عنصر في القائمة ، مع النقر فوقه.
الاختلافات:
في نظام التشغيل iOS ، يعرض الجدول المنفصل: didSelectRowAtIndexPath: الطريقة مسؤولة عن ذلك. في Flutter ، يجب لف عنصر القائمة في عنصر واجهة
تعامل النقرات ، مثل
GestureDetector .
السؤال:
كيفية تحديث
ListView بشكل حيوي؟
الجواب هو:
قم بتحديث قائمة البيانات واستدعاء setState ().
الاختلافات:
في نظام iOS ، تحتاج إلى تحديث البيانات واستدعاء طريقة إعادة تحميل البيانات. في Flutter ، بعد setState () ، سيتم إعادة رسم القطعة مرة أخرى.
مثال:
import 'package:flutter/material.dart'; void main() { runApp(SampleApp()); } class SampleApp extends StatelessWidget {
معلومات اضافية:
لإنشاء قائمة ، يوصى باستخدام
ListView.Builder .
مثال:
import 'package:flutter/material.dart'; void main() { runApp(SampleApp()); } class SampleApp extends StatelessWidget {
السؤال:
ما هو التناظرية من
UIScrollView ؟
الجواب هو:
ListView مع الحاجيات.
مثال:
@override Widget build(BuildContext context) { return ListView( children: <Widget>[ Text('Row One'), Text('Row Two'), Text('Row Three'), Text('Row Four'), ], ); }
معلومات اضافية:
مزيد من التفاصيل
هنا .
الإيماءات والتعامل مع الحدث اللمس
السؤال:
كيفية إضافة onClick المستمع لعنصر واجهة المستخدم في رفرفة؟
الجواب هو:
إذا كانت القطعة تدعم النقرات ، فحينها onPressed (). إن لم يكن ، ثم في onTap ().
مثال:
في onPressed ():
@override Widget build(BuildContext context) { return RaisedButton( onPressed: () { print("click"); }, child: Text("Button"), ); }
في onTap ():
class SampleApp extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( body: Center( child: GestureDetector( child: FlutterLogo( size: 200.0, ), onTap: () { print("tap"); }, ), ), ); } }
السؤال:
كيفية التعامل مع الإيماءات الأخرى على الحاجيات؟
الجواب هو:
باستخدام
GestureDetector . يمكنهم التعامل مع الإجراءات التالية:
صنبور
انقر نقرا مزدوجا
الضغط لفترة طويلة
السحب الرأسي
السحب الأفقي
مثال:
معالجة onDoubleTap:
AnimationController controller; CurvedAnimation curve; @override void initState() { controller = AnimationController(duration: const Duration(milliseconds: 2000), vsync: this); curve = CurvedAnimation(parent: controller, curve: Curves.easeIn); } class SampleApp extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( body: Center( child: GestureDetector( child: RotationTransition( turns: curve, child: FlutterLogo( size: 200.0, )), onDoubleTap: () { if (controller.isCompleted) { controller.reverse(); } else { controller.forward(); } }, ), ), ); } }
تصميم التطبيق
السؤال:
كيفية استخدام السمة (السمة) في التطبيق؟
الجواب هو:
باستخدام أداة MaterialApp أو WidgetApp كجذر في التطبيق.
مثال:
class SampleApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Sample App', theme: ThemeData( primarySwatch: Colors.blue, textSelectionColor: Colors.red ), home: SampleAppPage(), ); } }
السؤال:
كيفية استخدام الخطوط المخصصة؟
الجواب هو:
تحتاج فقط إلى وضع ملف الخط في المجلد (فكر في الاسم بنفسك) والإشارة إلى المسار إلى pubspec.yaml.
مثال:
fonts: - family: MyCustomFont fonts: - asset: fonts/MyCustomFont.ttf - style: italic
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Sample App"), ), body: Center( child: Text( 'This is a custom font text', style: TextStyle(fontFamily: 'MyCustomFont'), ), ), ); }
السؤال:
كيفية نمط الحاجيات النص؟
الجواب هو:
باستخدام المعلمات:
- اللون.
- الديكور.
- decorationColor.
- decorationStyle.
- fontFamily.
- حجم الخط.
- fontStyle.
- fontWeight.
- شفرة التجزئة.
- ارتفاع.
- وراثة.
- letterSpacing.
- textBaseline.
- wordSpacing.
شكل الإدخال
السؤال:
كيفية الحصول على نتيجة إدخال المستخدم؟
الجواب هو:
باستخدام
TextEditingController .
مثال:
class _MyFormState extends State<MyForm> {
:
Retrieve the value of a text field .
:
hint
TextInput ?
:
InputDecoration , .
مثال:
body: Center( child: TextField( decoration: InputDecoration(hintText: "This is a hint"), ), )
:
?
:
—
InputDecoration .
مثال:
class SampleApp extends StatelessWidget {
Flutter
:
GPS?
:
geolocator .
:
?
:
image_picker .
:
Facebook?
:
flutter_facebook_login .
:
Firebase?
:
Firebase
Flutter first party plugins :
:
() ?
:
Flutter EventBus . :
developing packages and plugins .
:
UserDefault?
:
Shared_Preferences plugin ( Shared Preferences Android ).
مثال:
import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; void main() { runApp( MaterialApp( home: Scaffold( body: Center( child: RaisedButton( onPressed: _incrementCounter, child: Text('Increment Counter'), ), ), ), ), ); } _incrementCounter() async { SharedPreferences prefs = await SharedPreferences.getInstance(); int counter = (prefs.getInt('counter') ?? 0) + 1; print('Pressed $counter times.'); prefs.setInt('counter', counter); }
:
Core Data ?
:
SQFlite .
:
push-?
:
Firebase_Messaging .
استنتاج
. , , . « » . «-» . , ? 2016 Kotlin, - 2017. , , . , .
2016 Flutter Dart. , 2018 . . ! , , , . ( Google Fuchsia , , , Flutter ). — ! , — . . Apple Store!