[By the docks] Flutter. Part 5. For Xamarin.Forms Developers

This is the final part of a concise interpretation of Flutter documentation that will be useful to Xamarin.Forms developers. Given the current situation, now is the time to learn something new! Under the cut, you can find enough information for yourself to assess whether it is worth moving from one cross-platform framework to another and how long it will take.



If this information is not enough or you have experience in native development for a specific platform, then I recommend to look in other parts:

Flutter. Part 1. For Android developers
Flutter. Part 2. For iOS developers
Flutter. Part 3. For React Native
Flutter developers . Part 4. For Flutter web developers
. Part 5. For Xamarin.Forms Developers

Content:


  1. Project

  2. Views



  3. Async UI





  4. Layouts



  5. ListView

  6. Text

  7. Flutter Plugins

  8. Platform-specific code

  9. Debugging

  10. Local storage



Project


Question:


Where is the entry point?

Answer:


Function main().

Differences:


In Xamarin.Forms this is LoadApplication(new App());.

Example:


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

Question:


How to create a Page or Element ?

Answer:


Flutter has no concept of Page and Element as such. All components are widgets. Flutter has 2 kinds of widgets: StatelessWidget and StatefulWidget . They work the same way, the only difference is in the rendering state.

Differences:


StatelessWidget has an immutable state. Suitable for displaying text, logo, etc. Those. if the element on the screen should not change during the entire display time, then it suits you. It can also be used as a container for stateful widgets.

StatefulWidget has the State class , which stores information about the current state. If you want to change an element on the screen when performing some action (a response came from the server, the user clicked on a button, etc.) - this is your option.

Example:


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),
      ),
    );
  }
}

Views


Question:


How to arrange widgets? What is the equivalent of a XAMLfile?

Answer:


In Flutter, layout is done directly in the code using the widget tree.

Difference:


In Xamarin.Forms, most often layout is done in a XAML.file. Flutter has no equivalent.

Additional Information:


The list of widgets can be viewed here .

Example:


@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),
      ),
    ),
  );
}

Question:


How to add or remove a widget through code?

Answer:


By updating the state of the parent widget and then rebuilding the widget tree.

Differences:


In Xamarin.Forms, this can be done using the property of Contentthe element or methods Add()and Remove().

Example:


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),
      ),
    );
  }
}

Question:


How to animate a widget?

Answer:


Using the Animation and AnimationController classes .

Differences:


Xamarin.Forms uses ViewExtensions and methods like FadeToor TranslateTo.

Additional Information:


Read more about animation here .

Example:


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();
        },
      ),
    );
  }
}

Question:


How to draw on the screen?

Answer:


Using the CustomPaint and CustomPainter classes .

Differences:


Xamarin.Forms uses a third-party SkiaSharp . In Flutter, Skia Canvas is used directly from the box.

Example:


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;
}

Question:


How to change transparency?

Answer:


Using the Opacity widget .

Differences:


Xamarin.Forms uses the Opacity of VisualElement . In Flutter, you just need to wrap the desired widget in Opacity .

Question:


How to create custom widgets?

Answer:


Compose them inside one (instead of inheritance).

Differences:


In Xamarin.Forms, you can inherit from the VisualElement that interests us and add your own logic. In Flutter, a widget is always inherited from StatelessWidget and StatefulWidget . Those. you need to create a new widget and use the set of necessary widgets in it as parameters or fields.

Example:


class CustomButton extends StatelessWidget {
  final String label;

  CustomButton(this.label);

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

Navigation


Question:


How to navigate between screens?

Answer:


To navigate between screens, the Navigator and Route classes are used .

Differences:


Xamarin.Forms uses the NavigationPage .

Flutter has two navigation methods that are similar to NavigationPage :

  1. Map the names to describe Route ;
  2. Navigate directly to Route .

Navigator can do push () or pop () to the route you specify.

Example:


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');

Question:


How to navigate to a third-party application?

Answer:


Using native implementations via MethodChannel or url_launcher plugin .

Async ui


Question:


What is the equivalent of Device.BeginInvokeOnMainThread () ? How to execute code asynchronously?

Answer:


Dart implements a single-threaded execution model that runs on Isolates . For asynchronous execution, use async / await, which you are familiar with from C #.

Example:


Fulfilling the request and returning the result for updating the UI:
loadData() async {
  String dataURL = "https://jsonplaceholder.typicode.com/posts";
  http.Response response = await http.get(dataURL);
  setState(() {
    widgets = json.decode(response.body);
  });
}

When the response to the request is received, you need to call the setState () method to redraw the widget tree with the new data.

An example of loading and updating data in a 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);
    });
  }
}

Question:


How to make network requests?

Answer:


Using the http plugin .

Example:


Connect dependency via pubspec.yaml:
dependencies:
  ...
  http: ^0.11.3+16

Inquiry:
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);
    });
  }
}

Question:


How to display the progress of long operations?

Answer:


Using ProgressIndicator .

Differences:


In Xamarin.Forms, this can be done directly by placing a progress indicator in XAML.

Example:


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);
    });
  }
}

Project Structure and Resources


Question:


Where to store resources of different resolutions?

Answer:


In assets.

Differences:


Xamarin.Forms does not have a unified storage for platform resources, so you have to store them in platform folders separately. There is a Flutter assets. The folder assetscan be located anywhere in the project, most importantly, write the path to it in the file pubspec.yaml.

Additional Information:


Comparison of the sizes of graphic resources in Android and Flutter.
Android density qualifierFlutter pixel ratio
ldpi0.75x
mdpi1.0x
hdpi1.5x
xhdpi2.0x
xxhdpi3.0x
xxxhdpi4.0x
Resource layout example:
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

An example of a path in a pubspec.yamlfile:
assets:
 - images/my_icon.jpeg

An example of using AssetImage :
return AssetImage("images/a_dot_burr.jpeg");

Direct usage example asset:
@override
Widget build(BuildContext context) {
  return Image.asset("images/my_image.png");
}

Question:


Where to store strings? How to localize them?

Answer:


Flutter has no specific place to store strings at the moment. They are proposed to be stored as static fields in a separate class. Plugins are used for localization, for example flutter_localizations or l10n .

Differences:


Xamarin.Forms uses a file resx.

Example:


Storage:
class Strings {
  static String welcomeMessage = "Welcome To Flutter";
}

Using:
new Text(Strings.welcomeMessage)

Localization:
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
  ],
  // ...
)

Question:


Where is the project file?

Answer:


Flutter does not have a project file to open this project in the development environment. The closest similar file - pubspec.yaml- contains dependencies on plugins and project details.

Application life cycle


Question:


How to handle life cycle events?

Answer:


Using the WidgetsBinding and didChangeAppLifecycleState () method .

Additional Information:


Flutter uses FlutterActivity in Android code and FlutterAppDelegate in iOS; due to this, the Flutter engine makes processing state changes as inconspicuous as possible. But if you still need to do some work depending on the state, then the life cycle is slightly different:
  • inactive - this method is only in iOS, in Android there is no analogue;
  • paused - similar to onPause () in Android;
  • resumed - similar to onPostResume () in Android;
  • suspending - similar to onStop in Android, in iOS there is no analogue.

See the AppLifecycleStatus documentation for more details .

Example:


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()));
}

Layouts


Question:


What is the analogue of StackLayout ?

Answer:


The analogue of StackLayout with vertical orientation is Column , and with horizontal - Row .

Example:


Column:
@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'),
    ],
  );
}

Row:
@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'),
    ],
  );
}

Question:


What is the analog of the Grid ?

Answer:


The GridView .

Example:


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,
      ),
    );
  }),
);

Question:


What is the analogue of ScrollView ?

Answer:


The closest analogue is SingleChildScrollView . But Flutter most often uses ListView to build content that is crawling .

Example:


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

ListView:
@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'),
    ],
  );
}

Gesture handling


Question:


How to handle clicks?

Answer:


If the widget supports the method onPressed, then you can handle the click using it. Otherwise, this can be done through the GestureDetector .

Example:


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

GestureDetector:
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");
        },
      ),
    ));
  }
}

Question:


How to handle gestures?

Answer:


Using the GestureDetector . They can handle the following actions:

Tap



Double tap



Long press



Vertical drag



Horizontal drag



Example:


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 and Adapters


Question:


What is the analog of ListView ?

Answer:


The ListView .

Differences:


In Xamarin.Forms, you need to create a ViewCell and (most often) a DataTemplateSelector and pass them to the ListView . In Flutter, you just need to pass a list of widgets to display.

Example:


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;
  }
}

Question:


How to determine which element was clicked on?

Answer:


In Flutter, an element widget must handle its click itself.

Differences:


Xamarin.Forms most commonly uses ItemTapped .

Example:


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;
  }
}

Question:


How to dynamically update a ListView ?

Answer:


Refresh the data list and call setState().

Differences:


Xamarin.Forms uses an ItemsSource for this . In Flutter, after the setState()widget will be redrawn again.

Example:


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');
        });
      },
    );
  }
}

Additional Information:


To create a list, it is recommended to use ListView.Builder .

Example:


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');
        });
      },
    );
  }
}

Text


Question:


How to use custom fonts?

Answer:


The font file you just need to put in a folder (think of a name for yourself) and indicate the path to it pubspec.yaml.

Example:


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'),
      ),
    ),
  );
}

Question:


How to style text widgets?

Answer:


Using parameters:

  • color;
  • decoration;
  • decorationColor;
  • decorationStyle;
  • fontFamily;
  • fontSize;
  • fontStyle;
  • fontWeight;
  • hashCode;
  • height;
  • inherit;
  • letterSpacing;
  • textBaseline;
  • wordSpacing.

Question:


What is the equivalent of Placeholder ?

Answer:


The hintText property of InputDecoration .

Example:


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

Question:


How to show validation errors?

Answer:


All the same with InputDecoration and its state.

Example:


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 Plugins


Question:


How to access GPS?

Answer:


Using the geolocator plugin .

Question:


How to access the camera?

Answer:


Using the image_picker plugin .

Question:


How to log in via Facebook?

Answer:


Using the flutter_facebook_login plugin .

Question:


How to use firebase?

Answer:


Firebase supports Flutter first party plugins :

Platform-specific code


Question:


How to determine which platform the code is running on?

Answer:


Using the field class platformin Theme or the Platform class .

Example:


Field 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 ';
}

Platform Class:
if (Platform.isIOS) {
  return 'iOS';
} else if (Platform.isAndroid) {
  return 'android';
} else if (Platform.isFuchsia) {
  return 'fuchsia';
} else {
  return 'not recognised ';
}

Question:


How to call native platform code?

Answer:


Via MethodChannel .

Additional Information:


More details here .

Debugging


Question:


What are the tools for debugging the application?

Answer:


DevTools .

Question:


How to do hot reload?

Answer:


If the application was launched from the IntelliJ IDE, Android Studio or VSCode, then by combining ⌘s/ctrl-sor clicking on the icon hot reload. If started from the terminal, then by entering a letter r.

Question:


How to access the developer menu in the application?

Answer:


If the launch was from the IDE, then using the IDE tools. If from the console, then use h.

Additional Information:


Full list of commands:

ActTeam in terminalFunctions and Fields
Widget hierarchywdebugDumpApp ()
Render treetdebugDumpRenderTree ()
LayersLdebugDumpLayerTree ()
AccessibilityS (traversal order) or U (inverse hit test order)debugDumpSemantics ()
Widget inspectoriWidgetsApp.showWidgetInspectorOverride
Display construction linespdebugPaintSizeEnabled
Simulation of different OSodefaultTargetPlatform
PerformancePWidgetsApp. showPerformanceOverlay
Screenshot flutter.pngs
Application closeq

Local storage


Question:


How to store key-valuedata in the application?

Answer:


Using the shared_preferences plugin .

Differences:


In Xamarin.Forms is used Xam.Plugins.Settings.

Example:


Connection dependency:
dependencies:
  flutter:
    sdk: flutter
  shared_preferences: ^0.4.3

Using:
SharedPreferences prefs = await SharedPreferences.getInstance();
_counter = prefs.getInt('counter');
prefs.setInt('counter', ++_counter);
setState(() {
  _counter = _counter;
});

Question:


How to store complex data?

Answer:


Using database plugins like sqflite or hive .

Here are perhaps the answers to the basic questions. This concludes the series of interpretations. I hope they were useful to all developers interested in this framework. Perhaps you even started writing on Flutter and recruited you into a friendly community of Flutter developers. And I’ll go think about new articles in order to develop the community and make the application world a better place. May your Forms not break Xamarin!

All Articles