[Pelas docas] Flutter. Parte 5. Para desenvolvedores do Xamarin.Forms

Esta é a parte final de uma interpretação concisa da documentação do Flutter que será útil para os desenvolvedores do Xamarin.Forms. Dada a situação atual, agora é a hora de aprender algo novo! De acordo com o corte, você pode encontrar informações suficientes para avaliar se vale a pena mudar de uma estrutura de plataforma cruzada para outra e quanto tempo levará.



Se essas informações não forem suficientes ou você tiver experiência em desenvolvimento nativo para uma plataforma específica, recomendo procurar em outras partes:

Flutter. Parte 1. Para desenvolvedores do Android
Flutter. Parte 2. Para desenvolvedores do iOS
Flutter. Parte 3. Para reagir a desenvolvedores Native
Flutter. Parte 4. Para desenvolvedores da web
Flutter. Parte 5. Para desenvolvedores do Xamarin.Forms

Conteúdo:


  1. Projeto

  2. Views



  3. Async UI





  4. Layouts



  5. ListView

  6. Texto

  7. Flutter Plugins

  8. Código específico da plataforma

  9. Depuração

  10. Armazenamento local



Projeto


Questão:


Onde fica o ponto de entrada?

Responda:


Função main().

Diferenças:


No Xamarin.Forms, é isso LoadApplication(new App());.

Exemplo:


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

Questão:


Como criar uma página ou elemento ?

Responda:


O Flutter não tem conceito de página e elemento como tal. Todos os componentes são widgets. O Flutter possui 2 tipos de widgets: StatelessWidget e StatefulWidget . Eles funcionam da mesma maneira, a única diferença está no estado de renderização.

Diferenças:


StatelessWidget tem um estado imutável. Adequado para a exibição de texto, logotipo etc. Essa. se o elemento na tela não mudar durante todo o tempo de exibição, ele combina com você. Também pode ser usado como um contêiner para widgets com estado.

StatefulWidget possui a classe State , que armazena informações sobre o estado atual. Se você deseja alterar um elemento na tela ao executar alguma ação (uma resposta veio do servidor, o usuário clicou em um botão etc.) - esta é sua opção.

Exemplo:


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

Visualizações


Questão:


Como organizar widgets? Qual é o equivalente a um XAMLarquivo?

Responda:


No Flutter, o layout é feito diretamente no código usando a árvore de widgets.

Diferença:


No Xamarin.Forms, o layout geralmente é feito em um XAMLarquivo. Flutter não tem equivalente.

Informação adicional:


A lista de widgets pode ser vista aqui .

Exemplo:


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

Questão:


Como adicionar ou remover um widget através do código?

Responda:


Atualizando o estado do widget pai e reconstruindo a árvore do widget.

Diferenças:


No Xamarin.Forms, isso pode ser feito usando a propriedade do Contentelemento ou métodos Add()e Remove().

Exemplo:


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

Questão:


Como animar um widget?

Responda:


Usando os Animação e AnimationController aulas .

Diferenças:


Xamarin.Forms usa ViewExtensions e métodos como FadeToou TranslateTo.

Informação adicional:


Leia mais sobre animação aqui .

Exemplo:


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

Questão:


Como desenhar na tela?

Responda:


Usando os CustomPaint e aulas CustomPainter .

Diferenças:


O Xamarin.Forms usa um SkiaSharp de terceiros . No Flutter, o Skia Canvas é usado diretamente da caixa.

Exemplo:


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

Questão:


Como mudar a transparência?

Responda:


Usando o widget Opacity .

Diferenças:


Xamarin.Forms usa a opacidade do VisualElement . No Flutter, você só precisa agrupar o widget desejado no Opacity .

Questão:


Como criar widgets personalizados?

Responda:


Componha-os dentro de um (em vez de herança).

Diferenças:


No Xamarin.Forms, você pode herdar do VisualElement que nos interessa e adicionar sua própria lógica. No Flutter, um widget é sempre herdado de StatelessWidget e StatefulWidget . Essa. você precisa criar um novo widget e usar o conjunto de widgets necessários nele como parâmetros ou campos.

Exemplo:


class CustomButton extends StatelessWidget {
  final String label;

  CustomButton(this.label);

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

Navegação


Questão:


Como navegar entre telas?

Responda:


Para navegar entre telas, as classes Navegador e Rota são usadas .

Diferenças:


Xamarin.Forms usa o NavigationPage .

O Flutter possui dois métodos de navegação semelhantes ao NavigationPage :

  1. Mapeie os nomes para descrever a rota ;
  2. Navegue diretamente para Rota .

O Navegador pode pressionar () ou pop () para a rota especificada.

Exemplo:


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

Questão:


Como navegar para um aplicativo de terceiros?

Responda:


Usando implementações nativas via MethodChannel ou plugin url_launcher .

Interface do usuário assíncrona


Questão:


Qual é o equivalente de Device.BeginInvokeOnMainThread () ? Como executar código de forma assíncrona?

Responda:


O Dart implementa um modelo de execução de thread único que é executado no Isolates . Para execução assíncrona, use async / waitit, que você está familiarizado com C #.

Exemplo:


Atendendo à solicitação e retornando o resultado para atualizar a interface do usuário:
loadData() async {
  String dataURL = "https://jsonplaceholder.typicode.com/posts";
  http.Response response = await http.get(dataURL);
  setState(() {
    widgets = json.decode(response.body);
  });
}

Quando a resposta à solicitação é recebida, você precisa chamar o método setState () para redesenhar a árvore do widget com os novos dados.

Um exemplo de carregamento e atualização de dados em um 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);
    });
  }
}

Questão:


Como fazer solicitações de rede?

Responda:


Usando o plugin http .

Exemplo:


Conectar dependência via pubspec.yaml:
dependencies:
  ...
  http: ^0.11.3+16

Inquérito:
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);
    });
  }
}

Questão:


Como exibir o progresso de operações longas?

Responda:


Usando ProgressIndicator .

Diferenças:


No Xamarin.Forms, isso pode ser feito diretamente, colocando um indicador de progresso em XAML.

Exemplo:


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

Estrutura e Recursos do Projeto


Questão:


Onde armazenar recursos de diferentes resoluções?

Responda:


In assets.

Diferenças:


O Xamarin.Forms não possui um armazenamento unificado para recursos da plataforma, portanto, você deve armazená-los em pastas da plataforma separadamente. Há uma vibração assets. A pasta assetspode estar localizada em qualquer lugar do projeto, e mais importante, escreva o caminho para ela no arquivo pubspec.yaml.

Informação adicional:


Comparação dos tamanhos de recursos gráficos no Android e Flutter.
Qualificador de densidade do AndroidProporção de pixel oscilante
ldpi0,75x
mdpi1.0x
hdpi1,5x
xhdpi2.0x
xxhdpi3.0x
xxxhdpi4.0x
Exemplo de layout de recurso:
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

Um exemplo de caminho em um pubspec.yamlarquivo:
assets:
 - images/my_icon.jpeg

Um exemplo de uso do AssetImage :
return AssetImage("images/a_dot_burr.jpeg");

Exemplo de uso direto asset:
@override
Widget build(BuildContext context) {
  return Image.asset("images/my_image.png");
}

Questão:


Onde armazenar cordas? Como localizá-los?

Responda:


O Flutter não tem um local específico para armazenar seqüências de caracteres no momento. Eles são propostos para serem armazenados como campos estáticos em uma classe separada. Os plug-ins são usados ​​para localização, por exemplo, flutter_localizations ou l10n .

Diferenças:


Xamarin.Forms usa um arquivo resx.

Exemplo:


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

Usando:
new Text(Strings.welcomeMessage)

Localização:
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
  ],
  // ...
)

Questão:


Onde está o arquivo do projeto?

Responda:


O Flutter não possui um arquivo de projeto para abrir esse projeto no ambiente de desenvolvimento. O arquivo semelhante mais próximo - pubspec.yaml- contém dependências de plugins e detalhes do projeto.

Ciclo de vida do aplicativo


Questão:


Como lidar com eventos do ciclo de vida?

Responda:


Usando o método WidgetsBinding e didChangeAppLifecycleState () .

Informação adicional:


O Flutter usa FlutterActivity no código Android e FlutterAppDelegate no iOS; por esse motivo , o mecanismo Flutter torna as alterações de estado de processamento o mais discretas possível. Mas se você ainda precisa fazer algum trabalho, dependendo do estado, o ciclo de vida é um pouco diferente:
  • inativo - esse método é apenas no iOS, no Android não há analógico;
  • pausado - semelhante ao onPause () no Android;
  • retomado - semelhante ao onPostResume () no Android;
  • suspensão - semelhante ao onStop no Android, no iOS não há analógico.

Consulte a documentação do AppLifecycleStatus para obter mais detalhes .

Exemplo:


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


Questão:


Qual é o análogo do StackLayout ?

Responda:


O análogo do StackLayout com orientação vertical é Column e com horizontal - Row .

Exemplo:


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

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

Questão:


Qual é o análogo da grade ?

Responda:


O GridView .

Exemplo:


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

Questão:


Qual é o análogo do ScrollView ?

Responda:


O analógico mais próximo é o SingleChildScrollView . Mas o Flutter costuma usar o ListView para criar conteúdo que está rastreando .

Exemplo:


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

Exibição de lista:
@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'),
    ],
  );
}

Manuseio de gestos


Questão:


Como lidar com cliques?

Responda:


Se o widget suportar o método onPressed, você poderá manipular o clique usando-o. Caso contrário, isso pode ser feito através do GestureDetector .

Exemplo:


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

Questão:


Como lidar com gestos?

Responda:


Usando o GestureDetector . Eles podem lidar com as seguintes ações:

Toque



Toque duplo



Pressão longa



Arrasto vertical



Arrasto horizontal



Exemplo:


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 e adaptadores


Questão:


Qual é o análogo do ListView ?

Responda:


O ListView .

Diferenças:


No Xamarin.Forms, você precisa criar um ViewCell e (na maioria das vezes) um DataTemplateSelector e passá-los para o ListView . No Flutter, você só precisa passar uma lista de widgets para exibir.

Exemplo:


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

Questão:


Como determinar em qual elemento foi clicado?

Responda:


No Flutter, um widget de elemento deve manipular seu próprio clique.

Diferenças:


O Xamarin.Forms costuma usar o ItemTapped .

Exemplo:


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

Questão:


Como atualizar dinamicamente um ListView ?

Responda:


Atualize a lista de dados e ligue setState().

Diferenças:


Xamarin.Forms usa um ItemsSource para isso . No Flutter, após o setState()widget ser redesenhado novamente.

Exemplo:


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

Informação adicional:


Para criar uma lista, é recomendável usar o ListView.Builder .

Exemplo:


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

Texto


Questão:


Como usar fontes personalizadas?

Responda:


O arquivo de fonte que você só precisa colocar em uma pasta (pense em um nome para si mesmo) e indique o caminho para ele pubspec.yaml.

Exemplo:


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

Questão:


Como estilizar widgets de texto?

Responda:


Usando parâmetros:

  • cor;
  • decoração;
  • decorationColor;
  • decorationStyle;
  • família de fontes;
  • tamanho da fonte;
  • estilo de fonte;
  • espessura da fonte;
  • hashCode;
  • altura;
  • herdar;
  • letterSpacing;
  • textBaseline;
  • wordSpacing.

Questão:


Qual é o equivalente a Placeholder ?

Responda:


O hintText propriedade de InputDecoration .

Exemplo:


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

Questão:


Como mostrar erros de validação?

Responda:


Tudo o mesmo com InputDecoration e seu estado.

Exemplo:


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


Questão:


Como acessar o GPS?

Responda:


Usando o GeoLocator plug-in .

Questão:


Como acessar a câmera?

Responda:


Usando o plugin image_picker .

Questão:


Como fazer login via Facebook?

Responda:


Usando o plugin flutter_facebook_login .

Questão:


Como usar o firebase?

Responda:


O Firebase suporta plugins Flutter :

Código específico da plataforma


Questão:


Como determinar em qual plataforma o código está sendo executado?

Responda:


Usando a classe de campo platformem Theme ou a classe Platform .

Exemplo:


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

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

Questão:


Como chamar código de plataforma nativa?

Responda:


Via MethodChannel .

Informação adicional:


Mais detalhes aqui .

Depuração


Questão:


Quais são as ferramentas para depurar o aplicativo?

Responda:


DevTools .

Questão:


Como fazer hot reload?

Responda:


Se o aplicativo foi iniciado a partir do IntelliJ IDE, Android Studio ou VSCode, combine ⌘s/ctrl-sou clique no ícone hot reload. Se iniciado a partir do terminal, digite uma letra r.

Questão:


Como acessar o menu do desenvolvedor no aplicativo?

Responda:


Se o lançamento foi do IDE, use as ferramentas do IDE. Se no console, use h.

Informação adicional:


Lista completa de comandos:

AjaEquipe no terminalFunções e Campos
Hierarquia do widgetWdebugDumpApp ()
Renderizar árvoretdebugDumpRenderTree ()
CamadaseudebugDumpLayerTree ()
AcessibilidadeS (ordem de travessia) ou U (ordem de teste de golpe inverso)debugDumpSemantics ()
Inspetor de widgetEuWidgetsApp.showWidgetInspectorOverride
Exibir linhas de construçãopdebugPaintSizeEnabled
Simulação de diferentes sistemas operacionaisodefaultTargetPlatform
atuaçãoPWidgetsApp. showPerformanceOverlay
Captura de tela flutter.pngs
Aplicação fecharq

Armazenamento local


Questão:


Como armazenar key-valuedados no aplicativo?

Responda:


Usando o plug-in shared_preferences .

Diferenças:


No Xamarin.Forms é usado Xam.Plugins.Settings.

Exemplo:


Dependência de conexão:
dependencies:
  flutter:
    sdk: flutter
  shared_preferences: ^0.4.3

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

Questão:


Como armazenar dados complexos?

Responda:


Usando plugins de banco de dados como sqflite ou hive .

Aqui estão, talvez, as respostas para as perguntas básicas. Isso conclui a série de interpretações. Espero que tenham sido úteis para todos os desenvolvedores interessados ​​neste framework. Talvez você tenha começado a escrever sobre o Flutter e o recrutado para uma comunidade amigável de desenvolvedores do Flutter. E irei pensar em novos artigos para desenvolver a comunidade e tornar o mundo dos aplicativos um lugar melhor. Que seus formulários não quebrem o Xamarin!

All Articles