[بالأرصفة] رفرفة. الجزء 5. لمطوري Xamarin.Forms

هذا هو الجزء الأخير من تفسير موجز لوثائق Flutter التي ستكون مفيدة لمطوري Xamarin.Forms. بالنظر إلى الوضع الحالي ، حان الوقت لتعلم شيء جديد! تحت هذا التخفيض ، يمكنك العثور على معلومات كافية لنفسك لتقييم ما إذا كان يستحق الانتقال من إطار عمل متعدد المنصات إلى آخر والمدة التي سيستغرقها.



إذا كانت هذه المعلومات غير كافية أو لديك خبرة في التطوير الأصلي لمنصة معينة ،

فأوصيك بالبحث في أجزاء أخرى: Flutter. الجزء 1. لمطوري أندرويد
Flutter. الجزء 2. لمطوري iOS
Flutter. الجزء 3. لمطوري رد فعل الأصلية
رفرفة. الجزء 4. لمطوري الويب
Flutter. الجزء 5. لمطوري Xamarin.Forms

المحتوى:


  1. مشروع

  2. Views



  3. Async UI





  4. Layouts



  5. ListView

  6. نص

  7. الإضافات Flutter

  8. رمز خاص بالنظام الأساسي

  9. تصحيح الأخطاء

  10. التخزين المحلي



مشروع


سؤال:


أين نقطة الدخول؟

إجابة:


الوظيفة main().

اختلافات:


في Xamarin.Forms هذا هو LoadApplication(new App());.

مثال:


void main() {
  runApp(new MyApp());
}

سؤال:


كيفية إنشاء صفحة أو عنصر ؟

إجابة:


رفرفة لا يوجد لديه مفهوم صفحة و العنصر على هذا النحو. جميع المكونات هي الحاجيات. يحتوي Flutter على نوعين من الأدوات: StatelessWidget و StatefulWidget . إنهم يعملون بنفس الطريقة ، والفرق الوحيد هو في حالة التقديم.

اختلافات:


StatelessWidget لديه حالة ثابتة. مناسب لعرض النص والشعار وما إلى ذلك. أولئك. إذا كان العنصر على الشاشة لا يجب أن يتغير خلال وقت العرض بأكمله ، فهو يناسبك. يمكن استخدامه أيضًا كحاوية للأدوات المصغرة. تحتوي

StatefulWidget على فئة الولاية ، التي تقوم بتخزين معلومات حول الحالة الحالية. إذا كنت ترغب في تغيير عنصر على الشاشة عند تنفيذ بعض الإجراءات (استجابة جاءت من الخادم ، نقر المستخدم على زر ، وما إلى ذلك) - هذا هو خيارك.

مثال:


StatelessWidget:
class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter Demo',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

StatefulWidget:
class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        // Take the value from the MyHomePage object that was created by
        // the App.build method, and use it to set the appbar title.
        title: new Text(widget.title),
      ),
      body: new Center(
        // Center is a layout widget. It takes a single child and positions it
        // in the middle of the parent.
        child: new Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            new Text(
              'You have pushed the button this many times:',
            ),
            new Text(
              '$_counter',
              style: Theme.of(context).textTheme.display1,
            ),
          ],
        ),
      ),
      floatingActionButton: new FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: new Icon(Icons.add),
      ),
    );
  }
}

الآراء


سؤال:


كيفية ترتيب الحاجيات؟ ما يعادل XAMLملف؟

إجابة:


في Flutter ، يتم التخطيط مباشرة في التعليمات البرمجية باستخدام شجرة القطعة.

فرق:


في Xamarin.Forms ، يتم التخطيط غالبًا في XAMLملف. Flutter ليس له مثيل.

معلومة اضافية:


يمكن الاطلاع على قائمة الأدوات هنا .

مثال:


@override
Widget build(BuildContext context) {
  return new Scaffold(
    appBar: new AppBar(
      title: new Text("Sample App"),
    ),
    body: new Center(
      child: new MaterialButton(
        onPressed: () {},
        child: new Text('Hello'),
        padding: new EdgeInsets.only(left: 10.0, right: 10.0),
      ),
    ),
  );
}

سؤال:


كيفية إضافة أو إزالة عنصر واجهة مستخدم من خلال التعليمات البرمجية؟

إجابة:


عن طريق تحديث حالة عنصر واجهة مستخدم ثم إعادة بناء شجرة عنصر واجهة المستخدم.

اختلافات:


في Xamarin.Forms ، يمكن القيام بذلك باستخدام خاصية Contentالعنصر أو الطرق Add()و Remove().

مثال:


class SampleApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Sample App',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new SampleAppPage(),
    );
  }
}

class SampleAppPage extends StatefulWidget {
  SampleAppPage({Key key}) : super(key: key);

  @override
  _SampleAppPageState createState() => new _SampleAppPageState();
}

class _SampleAppPageState extends State<SampleAppPage> {
  // Default value for toggle
  bool toggle = true;
  void _toggle() {
    setState(() {
      toggle = !toggle;
    });
  }

  _getToggleChild() {
    if (toggle) {
      return new Text('Toggle One');
    } else {
      return new CupertinoButton(
        onPressed: () {},
        child: new Text('Toggle Two'),
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text("Sample App"),
      ),
      body: new Center(
        child: _getToggleChild(),
      ),
      floatingActionButton: new FloatingActionButton(
        onPressed: _toggle,
        tooltip: 'Update Text',
        child: new Icon(Icons.update),
      ),
    );
  }
}

سؤال:


كيفية تحريك القطعة؟

إجابة:


باستخدام الرسوم المتحركة و AnimationController الطبقات .

اختلافات:


يستخدم Xamarin.Forms ViewExtensions وأساليب مثل FadeToأو TranslateTo.

معلومة اضافية:


اقرأ المزيد عن الرسوم المتحركة هنا .

مثال:


import 'package:flutter/material.dart';

void main() {
  runApp(new FadeAppTest());
}

class FadeAppTest extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Fade Demo',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new MyFadeTest(title: 'Fade Demo'),
    );
  }
}

class MyFadeTest extends StatefulWidget {
  MyFadeTest({Key key, this.title}) : super(key: key);
  final String title;
  @override
  _MyFadeTest createState() => new _MyFadeTest();
}

class _MyFadeTest extends State<MyFadeTest> with TickerProviderStateMixin {
  AnimationController controller;
  CurvedAnimation curve;

  @override
  void initState() {
    controller = new AnimationController(duration: const Duration(milliseconds: 2000), vsync: this);
    curve = new CurvedAnimation(parent: controller, curve: Curves.easeIn);
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text(widget.title),
      ),
      body: new Center(
          child: new Container(
              child: new FadeTransition(
                  opacity: curve,
                  child: new FlutterLogo(
                    size: 100.0,
                  )))),
      floatingActionButton: new FloatingActionButton(
        tooltip: 'Fade',
        child: new Icon(Icons.brush),
        onPressed: () {
          controller.forward();
        },
      ),
    );
  }
}

سؤال:


كيف ترسم على الشاشة؟

إجابة:


استخدام فئتي CustomPaint و CustomPainter .

اختلافات:


Xamarin.Forms يستخدم طرف ثالث SkiaSharp . في Flutter ، يتم استخدام Skia Canvas مباشرة من الصندوق.

مثال:


import 'package:flutter/material.dart';

void main() => runApp(new MaterialApp(home: new DemoApp()));

class DemoApp extends StatelessWidget {
  Widget build(BuildContext context) => new Scaffold(body: new Signature());
}

class Signature extends StatefulWidget {
  SignatureState createState() => new SignatureState();
}

class SignatureState extends State<Signature> {
  List<Offset> _points = <Offset>[];
  Widget build(BuildContext context) {
    return new GestureDetector(
      onPanUpdate: (DragUpdateDetails details) {
        setState(() {
          RenderBox referenceBox = context.findRenderObject();
          Offset localPosition =
          referenceBox.globalToLocal(details.globalPosition);
          _points = new List.from(_points)..add(localPosition);
        });
      },
      onPanEnd: (DragEndDetails details) => _points.add(null),
      child: new CustomPaint(painter: new SignaturePainter(_points), size: Size.infinite),
    );
  }
}

class SignaturePainter extends CustomPainter {
  SignaturePainter(this.points);
  final List<Offset> points;
  void paint(Canvas canvas, Size size) {
    var paint = new 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;
}

سؤال:


كيف تغير الشفافية؟

إجابة:


باستخدام عنصر واجهة التعتيم .

اختلافات:


Xamarin.Forms الاستخدامات و التعتيم من VisualElement . في Flutter ، تحتاج فقط إلى التفاف القطعة المطلوبة في التعتيم .

سؤال:


كيفية إنشاء الحاجيات المخصصة؟

إجابة:


يؤلفها داخل واحد (بدلاً من الميراث).

اختلافات:


في Xamarin.Forms ، يمكنك أن ترث من VisualElement الذي يهمنا وإضافة منطقك الخاص. في Flutter ، يتم دائمًا توريث عنصر واجهة المستخدم من StatelessWidget و StatefulWidget . أولئك. تحتاج إلى إنشاء عنصر واجهة مستخدم جديد واستخدام مجموعة الأدوات الضرورية فيه كمعلمات أو حقول.

مثال:


class CustomButton extends StatelessWidget {
  final String label;

  CustomButton(this.label);

  @override
  Widget build(BuildContext context) {
    return new RaisedButton(onPressed: () {}, child: new Text(label));
  }
}

التنقل


سؤال:


كيف تتنقل بين الشاشات؟

إجابة:


للتنقل بين الشاشات ، يتم استخدام فئات Navigator و Route .

اختلافات:


يستخدم Xamarin.Forms NavigationPage .

يحتوي Flutter على طريقتين للتنقل مشابهتين لصفحة التنقل :

  1. تعيين الأسماء لوصف الطريق ؛
  2. انتقل مباشرة إلى المسار .

يمكن أن يقوم المستكشف بدفع () أو pop () إلى المسار الذي تحدده.

مثال:


void main() {
  runApp(CupertinoApp(
    home: MyAppHome(), // becomes the route named '/'
    routes: <String, WidgetBuilder> {
      '/a': (BuildContext context) => MyPage(title: 'page A'),
      '/b': (BuildContext context) => MyPage(title: 'page B'),
      '/c': (BuildContext context) => MyPage(title: 'page C'),
    },
  ));
}

Navigator.of(context).pushNamed('/b');

سؤال:


كيفية التنقل إلى تطبيق طرف ثالث؟

إجابة:


استخدام التطبيقات الأصلية عبر MethodChannel أو url_launcher plugin .

واجهة مستخدم غير متزامنة


سؤال:


ما هو ما يعادل Device.BeginInvokeOnMainThread () ؟ كيفية تنفيذ التعليمات البرمجية بشكل غير متزامن؟

إجابة:


يطبق Dart نموذج تنفيذ أحادي الخيوط يعمل على عزل . للتنفيذ غير المتزامن ، استخدم المتزامن / الانتظار ، الذي تعرفه من C #.

مثال:


تلبية الطلب وإرجاع النتيجة لتحديث واجهة المستخدم:
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);
    });
  }
}

سؤال:


كيفية تقديم طلبات الشبكة؟

إجابة:


باستخدام البرنامج المساعد http .

مثال:


ربط التبعية عبر pubspec.yaml:
dependencies:
  ...
  http: ^0.11.3+16

تحقيق:
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 .

اختلافات:


في Xamarin.Forms ، يمكن القيام بذلك مباشرة عن طريق وضع مؤشر التقدم فيه XAML.

مثال:


import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

void main() {
  runApp(new SampleApp());
}

class SampleApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Sample App',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new SampleAppPage(),
    );
  }
}

class SampleAppPage extends StatefulWidget {
  SampleAppPage({Key key}) : super(key: key);

  @override
  _SampleAppPageState createState() => new _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 new Center(child: new CircularProgressIndicator());
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        appBar: new AppBar(
          title: new Text("Sample App"),
        ),
        body: getBody());
  }

  ListView getListView() => new ListView.builder(
      itemCount: widgets.length,
      itemBuilder: (BuildContext context, int position) {
        return getRow(position);
      });

  Widget getRow(int i) {
    return new Padding(padding: new EdgeInsets.all(10.0), child: new 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);
    });
  }
}

هيكل المشروع والموارد


سؤال:


أين يتم تخزين موارد قرارات مختلفة؟

إجابة:


في assets.

اختلافات:


لا يحتوي Xamarin.Forms على مساحة تخزين موحدة لموارد النظام الأساسي ، لذلك يجب عليك تخزينها في مجلدات النظام الأساسي بشكل منفصل. هناك رفرفة assets. assetsيمكن وضع المجلد في أي مكان في المشروع ، والأهم من ذلك ، اكتب المسار إليه في الملف pubspec.yaml.

معلومة اضافية:


مقارنة بين أحجام الموارد الرسومية في Android و Flutter.
مؤهل كثافة Androidنسبة بكسل رفرفة
ldpi0.75 مرة
mdpi1.0x
hdpi1.5 مرة
xhdpi2.0x
xxhdpi3.0x
xxxhdpi4.0x
مثال تخطيط الموارد:
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.jpeg

مثال على استخدام AssetImage :
return AssetImage("images/a_dot_burr.jpeg");

مثال للاستخدام المباشر asset:
@override
Widget build(BuildContext context) {
  return Image.asset("images/my_image.png");
}

سؤال:


أين يتم تخزين الخيوط؟ كيفية توطينهم؟

إجابة:


Flutter ليس لديه مكان محدد لتخزين السلاسل في الوقت الحالي. يقترح تخزينها كحقول ثابتة في فصل منفصل. يتم استخدام المكونات الإضافية للترجمة ، على سبيل المثال flutter_localifications أو l10n .

اختلافات:


يستخدم Xamarin.Forms ملف resx.

مثال:


تخزين:
class Strings {
  static String welcomeMessage = "Welcome To Flutter";
}

باستخدام:
new Text(Strings.welcomeMessage)

الموقع:
dependencies:
  # ...
  flutter_localizations:
    sdk: flutter
  intl: "^0.15.6"

import 'package:flutter_localizations/flutter_localizations.dart';

new MaterialApp(
 localizationsDelegates: [
   // Add app-specific localization delegate[s] here.
   GlobalMaterialLocalizations.delegate,
   GlobalWidgetsLocalizations.delegate,
 ],
 supportedLocales: [
    const Locale('en', 'US'), // English
    const Locale('he', 'IL'), // Hebrew
    // ... other locales the app supports
  ],
  // ...
)

سؤال:


أين ملف المشروع؟

إجابة:


Flutter ليس لديه ملف مشروع لفتح هذا المشروع في بيئة التطوير. أقرب ملف مشابه - pubspec.yaml- يعتمد على الإضافات وتفاصيل المشروع.

دورة حياة التطبيق


سؤال:


كيف تتعامل مع أحداث دورة الحياة؟

إجابة:


استخدام أسلوب WidgetsBinding و didChangeAppLifecycleState () .

معلومة اضافية:


يستخدم Flutter FlutterActivity في كود Android و FlutterAppDelegate في iOS ، بسبب محرك Flutter هذا يجعل تغييرات حالة المعالجة غير واضحة قدر الإمكان. ولكن إذا كنت لا تزال بحاجة إلى القيام ببعض الأعمال اعتمادًا على الحالة ، فإن دورة الحياة تختلف قليلاً:
  • غير نشط - هذه الطريقة موجودة فقط في iOS ، ولا يوجد في Android نظير ؛
  • متوقف مؤقتًا - مشابهًا لـ onPause () في Android ؛
  • تم الاستئناف - على غرار onPostResume () في Android ؛
  • تعليق - على غرار onStop في 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()));
}

التخطيطات


سؤال:


ما هو نظير StackLayout ؟

إجابة:


التناظرية من StackLayout مع الاتجاه الرأسي هو العمود ، ومع الأفقي - الصف .

مثال:


عمود:
@override
Widget build(BuildContext context) {
  return new Column(
    mainAxisAlignment: MainAxisAlignment.center,
    children: <Widget>[
      new Text('Column One'),
      new Text('Column Two'),
      new Text('Column Three'),
      new Text('Column Four'),
    ],
  );
}

صف:
@override
Widget build(BuildContext context) {
  return new Row(
    mainAxisAlignment: MainAxisAlignment.center,
    children: <Widget>[
      new Text('Row One'),
      new Text('Row Two'),
      new Text('Row Three'),
      new Text('Row Four'),
    ],
  );
}

سؤال:


ما هو التناظرية للشبكة ؟

إجابة:


GridView .

مثال:


GridView.count(
  // Create a grid with 2 columns. If you change the scrollDirection to
  // horizontal, this would produce 2 rows.
  crossAxisCount: 2,
  // Generate 100 widgets that display their index in the List
  children: List.generate(100, (index) {
    return Center(
      child: Text(
        'Item $index',
        style: Theme.of(context).textTheme.headline,
      ),
    );
  }),
);

سؤال:


ما هو التناظرية من ScrollView ؟

إجابة:


أقرب تماثلي هو SingleChildScrollView . لكن Flutter غالبًا ما يستخدم ListView لإنشاء محتوى يزحف .

مثال:


SingleChildScrollView:
@override
Widget build(BuildContext context) {
  return new SingleChildScrollView(
    child: new Text('Long Content'),
  );
}

عرض القائمة:
@override
Widget build(BuildContext context) {
  return new ListView(
    children: <Widget>[
      new Text('Row One'),
      new Text('Row Two'),
      new Text('Row Three'),
      new Text('Row Four'),
    ],
  );
}

التعامل مع الإيماءات


سؤال:


كيفية التعامل مع النقرات؟

إجابة:


إذا كانت الأداة تدعم الطريقة onPressed، فيمكنك معالجة النقر باستخدامها. خلاف ذلك ، يمكن القيام بذلك من خلال GestureDetector .

مثال:


onPressed:
@override
Widget build(BuildContext context) {
  return new RaisedButton(
      onPressed: () {
        print("click");
      },
      child: new Text("Button"));
}

كاشف الإيماءة:
class SampleApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        body: new Center(
      child: new GestureDetector(
        child: new FlutterLogo(
          size: 200.0,
        ),
        onTap: () {
          print("tap");
        },
      ),
    ));
  }
}

سؤال:


كيف تتعامل مع الإيماءات؟

إجابة:


باستخدام GestureDetector . يمكنهم التعامل مع الإجراءات التالية:

صنبور



انقر مرّتين



ضغطة طويلة



سحب عمودي



السحب الأفقي



مثال:


AnimationController controller;
CurvedAnimation curve;

@override
void initState() {
  controller = new AnimationController(duration: const Duration(milliseconds: 2000), vsync: this);
  curve = new CurvedAnimation(parent: controller, curve: Curves.easeIn);
}

class SampleApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        body: new Center(
          child: new GestureDetector(
            child: new RotationTransition(
                turns: curve,
                child: new FlutterLogo(
                  size: 200.0,
                )),
            onDoubleTap: () {
              if (controller.isCompleted) {
                controller.reverse();
              } else {
                controller.forward();
              }
            },
        ),
    ));
  }
}

ListView والمحولات


سؤال:


ما هو التناظرية من ListView ؟

إجابة:


ListView .

اختلافات:


في Xamarin.Forms ، تحتاج إلى إنشاء ViewCell و (في أغلب الأحيان) DataTemplateSelector وتمريرها إلى ListView . في Flutter ، ما عليك سوى تمرير قائمة الأدوات لعرضها.

مثال:


import 'package:flutter/material.dart';

void main() {
  runApp(new SampleApp());
}

class SampleApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Sample App',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new SampleAppPage(),
    );
  }
}

class SampleAppPage extends StatefulWidget {
  SampleAppPage({Key key}) : super(key: key);

  @override
  _SampleAppPageState createState() => new _SampleAppPageState();
}

class _SampleAppPageState extends State<SampleAppPage> {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text("Sample App"),
      ),
      body: new ListView(children: _getListData()),
    );
  }

  _getListData() {
    List<Widget> widgets = [];
    for (int i = 0; i < 100; i++) {
      widgets.add(new Padding(padding: new EdgeInsets.all(10.0), child: new Text("Row $i")));
    }
    return widgets;
  }
}

سؤال:


كيفية تحديد العنصر الذي تم النقر عليه؟

إجابة:


في Flutter ، يجب أن تتعامل عنصر واجهة مستخدم عنصر النقرة نفسها.

اختلافات:


Xamarin.Forms يستخدم ItemTapped الأكثر شيوعًا .

مثال:


import 'package:flutter/material.dart';

void main() {
  runApp(new SampleApp());
}

class SampleApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Sample App',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new SampleAppPage(),
    );
  }
}

class SampleAppPage extends StatefulWidget {
  SampleAppPage({Key key}) : super(key: key);

  @override
  _SampleAppPageState createState() => new _SampleAppPageState();
}

class _SampleAppPageState extends State<SampleAppPage> {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text("Sample App"),
      ),
      body: new ListView(children: _getListData()),
    );
  }

  _getListData() {
    List<Widget> widgets = [];
    for (int i = 0; i < 100; i++) {
      widgets.add(new GestureDetector(
        child: new Padding(
            padding: new EdgeInsets.all(10.0),
            child: new Text("Row $i")),
        onTap: () {
          print('row tapped');
        },
      ));
    }
    return widgets;
  }
}

سؤال:


كيفية تحديث ListView بشكل حيوي ؟

إجابة:


قم بتحديث قائمة البيانات والاتصال setState().

اختلافات:


Xamarin.Forms يستخدم ItemsSource لهذا الغرض . في Flutter ، بعد setState()إعادة رسم الأداة مرة أخرى.

مثال:


import 'package:flutter/material.dart';

void main() {
  runApp(SampleApp());
}

class SampleApp extends StatelessWidget {
  // This widget is the root of your application.
  @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();
    for (int i = 0; i < 100; i++) {
      widgets.add(getRow(i));
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Sample App"),
      ),
      body: ListView(children: widgets),
    );
  }

  Widget getRow(int i) {
    return GestureDetector(
      child: Padding(
        padding: EdgeInsets.all(10.0),
        child: Text("Row $i"),
      ),
      onTap: () {
        setState(() {
          widgets = List.from(widgets);
          widgets.add(getRow(widgets.length + 1));
          print('row $i');
        });
      },
    );
  }
}

معلومة اضافية:


لإنشاء قائمة ، يوصى باستخدام ListView.Builder .

مثال:


import 'package:flutter/material.dart';

void main() {
  runApp(SampleApp());
}

class SampleApp extends StatelessWidget {
  // This widget is the root of your application.
  @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();
    for (int i = 0; i < 100; i++) {
      widgets.add(getRow(i));
    }
  }

  @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 GestureDetector(
      child: Padding(
        padding: EdgeInsets.all(10.0),
        child: Text("Row $i"),
      ),
      onTap: () {
        setState(() {
          widgets.add(getRow(widgets.length + 1));
          print('row $i');
        });
      },
    );
  }
}

نص


سؤال:


كيفية استخدام الخطوط المخصصة؟

إجابة:


ملف الخط الذي تحتاجه فقط لوضعه في مجلد (فكر في اسم لنفسك) ويشير إلى المسار إليه 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'),
      ),
    ),
  );
}

سؤال:


كيفية تصميم الحاجيات النصية؟

إجابة:


باستخدام المعلمات:

  • اللون؛
  • زخرفة؛
  • الزخرفة
  • الديكور
  • خط العائلة؛
  • حجم الخط؛
  • نوع الخط؛
  • الوزن
  • رمز التجزئة ؛
  • ارتفاع؛
  • يرث؛
  • letterSpacing ؛
  • النص الأساسي ؛
  • تباعد الكلمات.

سؤال:


ما هو المكافئ للعنصر النائب ؟

إجابة:


و hintText الملكية من InputDecoration .

مثال:


body: new Center(
  child: new TextField(
    decoration: new InputDecoration(hintText: "This is a hint"),
  )
)

سؤال:


كيفية إظهار أخطاء التحقق من الصحة؟

إجابة:


كل نفس مع InputDecoration وحالته.

مثال:


class SampleApp extends StatelessWidget {
  // This widget is the root of your application.
  @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> {
  String _errorText;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Sample App"),
      ),
      body: Center(
        child: TextField(
          onSubmitted: (String text) {
            setState(() {
              if (!isEmail(text)) {
                _errorText = 'Error: This is not an email';
              } else {
                _errorText = null;
              }
            });
          },
          decoration: InputDecoration(hintText: "This is a hint", errorText: _getErrorText()),
        ),
      ),
    );
  }

  _getErrorText() {
    return _errorText;
  }

  bool isEmail(String emailString) {
    String emailRegexp =
        r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$';

    RegExp regExp = RegExp(emailRegexp);

    return regExp.hasMatch(emailString);
  }
}

الإضافات Flutter


سؤال:


كيفية الوصول إلى GPS؟

إجابة:


باستخدام المساعد الجغرافي .

سؤال:


كيفية الوصول إلى الكاميرا؟

إجابة:


استخدام المكوّن الإضافي image_picker .

سؤال:


كيفية تسجيل الدخول عبر Facebook؟

إجابة:


استخدام البرنامج المساعد flutter_facebook_login .

سؤال:


كيفية استخدام Firebase؟

إجابة:


يدعم Firebase المكونات الإضافية للطرف الأول من Flutter :

رمز خاص بالنظام الأساسي


سؤال:


كيفية تحديد النظام الأساسي الذي تعمل عليه الشفرة؟

إجابة:


استخدام فئة الحقل platformفي السمة أو فئة النظام الأساسي .

مثال:


حقل platform:
if (Theme.of(context).platform == TargetPlatform.iOS) {
  return 'iOS';
} else if (Theme.of(context).platform == TargetPlatform.android) {
  return 'android';
} else if (Theme.of(context).platform == TargetPlatform.fuchsia) {
  return 'fuchsia';
} else {
  return 'not recognised ';
}

فئة المنصة:
if (Platform.isIOS) {
  return 'iOS';
} else if (Platform.isAndroid) {
  return 'android';
} else if (Platform.isFuchsia) {
  return 'fuchsia';
} else {
  return 'not recognised ';
}

سؤال:


كيفية استدعاء رمز النظام الأساسي الأصلي؟

إجابة:


عبر MethodChannel .

معلومة اضافية:


مزيد من التفاصيل هنا .

تصحيح الأخطاء


سؤال:


ما هي أدوات تصحيح التطبيق؟

إجابة:


DevTools .

سؤال:


كيف تفعل hot reload؟

إجابة:


إذا تم تشغيل التطبيق من IntelliJ IDE أو Android Studio أو VSCode ، ثم عن طريق الجمع ⌘s/ctrl-sأو النقر فوق الرمز hot reload. إذا بدأت من الصالة ، بإدخال خطاب r.

سؤال:


كيفية الوصول إلى قائمة المطور في التطبيق؟

إجابة:


إذا كان الإطلاق من IDE ، فاستخدم أدوات IDE. إذا كان من وحدة التحكم ، فاستخدم h.

معلومة اضافية:


قائمة كاملة بالأوامر:

فعلفريق في المحطةالوظائف والمجالات
التسلسل الهرمي القطعةثdebugDumpApp ()
تجعل شجرةرdebugDumpRenderTree ()
الطبقاتلامdebugDumpLayerTree ()
إمكانية الوصولS (أمر اجتياز) أو U (أمر اختبار نتيجة عكسية)debugDumpSemantics ()
مفتش القطعةأناWidgetsApp.showWidgetInspectorOverride
عرض خطوط البناءصdebugPaintSizeEnabled
محاكاة أنظمة تشغيل مختلفةسdefaultTargetPlatform
أداءصWidgetsApp. showPerformanceOverlay
لقطة شاشة flutter.pngس
إغلاق التطبيقس

التخزين المحلي


سؤال:


كيفية تخزين key-valueالبيانات في التطبيق؟

إجابة:


استخدام البرنامج المساعد Shared_preferences .

اختلافات:


في Xamarin.Forms يستخدم Xam.Plugins.Settings.

مثال:


تبعية الاتصال:
dependencies:
  flutter:
    sdk: flutter
  shared_preferences: ^0.4.3

باستخدام:
SharedPreferences prefs = await SharedPreferences.getInstance();
_counter = prefs.getInt('counter');
prefs.setInt('counter', ++_counter);
setState(() {
  _counter = _counter;
});

سؤال:


كيفية تخزين البيانات المعقدة؟

إجابة:


استخدام ملحقات قاعدة البيانات مثل sqflite أو الخلية .

هنا ربما إجابات على الأسئلة الأساسية. بهذا نختتم سلسلة التفسيرات. آمل أن تكون مفيدة لجميع المطورين المهتمين بهذا الإطار. ربما بدأت في الكتابة على Flutter وجندتك في مجتمع ودود من مطوري Flutter. وسأفكر في مقالات جديدة من أجل تطوير المجتمع وجعل عالم التطبيقات مكانًا أفضل. نرجو أن لا تكسر نماذجك Xamarin!

All Articles