[Pelas docas] Flutter. Parte 1. Para desenvolvedores do Android

Flutter já escreveu muitos artigos. Todo mês está se tornando mais popular. Por isso, decidi interpretar a documentação oficial do Flutter em um formato conciso de perguntas e respostas. Acho que muitos, como eu, não têm tempo livre suficiente para estudar em detalhes a documentação da estrutura com a qual eles ainda não funcionam.

Se você quiser entender para que serve essa estrutura e avaliar quanto esforço você precisará fazer para usá-la, seja bem-vindo ao gato.



Conteúdo:


  1. Visualizações

  2. Intenções

  3. Interface do usuário assíncrona

  4. Estrutura e Recursos do Projeto

  5. Atividades e Fragmentos

  6. Layouts

  7. Gestos e manipulação de eventos por toque.

  8. Listviews e adaptadores

  9. Trabalhar com texto

  10. Formulário de entrada

  11. Flutter Plugins

  12. Temas

  13. Bancos de dados e armazenamento local

  14. Notificações


Visualizações


Pergunta:


Qual é o equivalente de View in Flutter?

A resposta é:


Widget

Diferenças:


Ver - de fato, o que estará na tela. Invalidate () é chamado para exibir as alterações.

Widget - uma descrição do que estará na tela. Pois a mudança é criada novamente.

Informações adicionais:


Quando lançado no próprio Android, o View está sob o capô do Widget. Flutter inclui a biblioteca de componentes de material . Ele contém widgets que implementam as diretrizes de design de material .

Pergunta:


Como atualizar a exibição de widgets?

A resposta é:


Usando StatefulWidget e seu estado . 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. I.e. 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 o estado 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.

Um exemplo:


1) StatelessWidget - Texto

Text( 'I like Flutter!', style: TextStyle(fontWeight: FontWeight.bold), ); 

2) StatefulWidget - quando você clica no botão (FloatingActionButton), o texto no widget Texto muda de "Eu gosto de vibração" para "Flutter é impressionante!".

 import 'package:flutter/material.dart'; 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> { //   String textToShow = "  Flutter"; void _updateText() { setState(() { //   textToShow = "Flutter !"; }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Sample App"), ), body: Center(child: Text(textToShow)), floatingActionButton: FloatingActionButton( onPressed: _updateText, tooltip: ' ', child: Icon(Icons.update), ), ); } } 

Pergunta:


Como fazer o layout de uma tela com widgets? Onde está o arquivo de layout XML?

A resposta é:


O Flutter não possui layout XML para telas. Tudo digitado na árvore de widgets diretamente no código.

Um exemplo:


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

Todos os widgets padrão no Flutter podem ser visualizados no catálogo de widgets .

Pergunta:


Como adicionar ou remover um componente no layout enquanto o aplicativo está em execução?

A resposta é:


Através de uma função que retornará o widget desejado, dependendo do estado.

Diferenças:


No Android, você pode addView () ou removeView () em um ViewGroup. No Flutter não é possível, porque os widgets permanecem inalterados. Somente sua condição pode mudar.

Um exemplo:


Como alterar o texto para o botão, clicando em FloatingActionButton.

 import 'package:flutter/material.dart'; 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> { //     bool toggle = true; void _toggle() { setState(() { toggle = !toggle; }); } _getToggleChild() { if (toggle) { return Text('Toggle One'); } else { return MaterialButton(onPressed: () {}, child: Text('Toggle Two')); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Sample App"), ), body: Center( child: _getToggleChild(), ), floatingActionButton: FloatingActionButton( onPressed: _toggle, tooltip: 'Update Text', child: Icon(Icons.update), ), ); } } 

Pergunta:


Como animar widgets?

A resposta é:


Usando a classe AnimationController , que é o descendente da classe abstrata Animation <T> . Além de iniciar a animação, ele pode pausar, retroceder, parar e reproduzir na direção oposta. Funciona com o Ticker , que relata um redesenho da tela.

Diferenças:


No Android, você pode criar animações em XML ou animar o View usando animate (). No Flutter, a animação deve ser escrita em código usando o AnimationController.

Informações adicionais:


Você pode aprender mais nos widgets Animação e movimento , tutorial Animações e visão geral de Animações .

Um exemplo:


Desvanece a animação do logotipo Flutter.

 import 'package:flutter/material.dart'; void main() { runApp(FadeAppTest()); } class FadeAppTest extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'Fade Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: MyFadeTest(title: 'Fade Demo'), ); } } class MyFadeTest extends StatefulWidget { MyFadeTest({Key key, this.title}) : super(key: key); final String title; @override _MyFadeTest createState() => _MyFadeTest(); } class _MyFadeTest extends State<MyFadeTest> with TickerProviderStateMixin { AnimationController controller; CurvedAnimation curve; @override void initState() { super.initState(); controller = AnimationController(duration: const Duration(milliseconds: 2000), vsync: this); curve = CurvedAnimation(parent: controller, curve: Curves.easeIn); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Center( child: Container( child: FadeTransition( opacity: curve, child: FlutterLogo( size: 100.0, )))), floatingActionButton: FloatingActionButton( tooltip: 'Fade', child: Icon(Icons.brush), onPressed: () { controller.forward(); }, ), ); } } 

Pergunta:


Como usar o Canvas ?

A resposta é:


Android e Flutter têm a mesma API para Canvas, pois eles usam o mesmo motor Skia de baixo nível.

Diferenças:


Não.

Informações adicionais:


O Flutter possui duas classes para desenhar no Canvas - CustomPaint e CustomPainter . O segundo implementa seu algoritmo de renderização.

Leia mais aqui: StackOverflow

Um exemplo:


 import 'package:flutter/material.dart'; void main() => runApp(MaterialApp(home: DemoApp())); class DemoApp extends StatelessWidget { Widget build(BuildContext context) => Scaffold(body: Signature()); } class Signature extends StatefulWidget { SignatureState createState() => SignatureState(); } class SignatureState extends State<Signature> { List<Offset> _points = <Offset>[]; Widget build(BuildContext context) { return GestureDetector( onPanUpdate: (DragUpdateDetails details) { setState(() { RenderBox referenceBox = context.findRenderObject(); Offset localPosition = referenceBox.globalToLocal(details.globalPosition); _points = List.from(_points)..add(localPosition); }); }, onPanEnd: (DragEndDetails details) => _points.add(null), child: CustomPaint(painter: SignaturePainter(_points), size: Size.infinite), ); } } class SignaturePainter extends CustomPainter { SignaturePainter(this.points); final List<Offset> points; void paint(Canvas canvas, Size size) { var paint = Paint() ..color = Colors.black ..strokeCap = StrokeCap.round ..strokeWidth = 5.0; for (int i = 0; i < points.length - 1; i++) { if (points[i] != null && points[i + 1] != null) canvas.drawLine(points[i], points[i + 1], paint); } } bool shouldRepaint(SignaturePainter other) => other.points != points; } 

Pergunta:


Como criar widgets personalizados?

A resposta é:


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

Diferenças:


No Android, podemos herdar da Vista em que estamos interessados ​​e adicionar nossa própria lógica. No Flutter, isso é semelhante a um ViewGroup, apenas o widget é sempre herdado de StatelessWidget ou StatefulWidget. I.e. você precisa criar um novo widget e usá-lo como conjunto de parâmetros ou campos.

Um exemplo:


 class CustomButton extends StatelessWidget { final String label; CustomButton(this.label); @override Widget build(BuildContext context) { return RaisedButton(onPressed: () {}, child: Text(label)); } } @override Widget build(BuildContext context) { return Center( child: CustomButton("Hello"), ); } 

Intenções


Pergunta:


Qual é o análogo da Intent in Flutter?

A resposta é:


Ele não está lá. Para navegar entre as telas, as classes Navegador e Rota são usadas.

Para interagir com componentes externos (por exemplo, uma câmera ou seletor de arquivos), você pode usar plug - ins ou integração nativa em cada plataforma. Saiba mais sobre integração nativa: desenvolvendo pacotes e plugins .

Diferenças:


Flutter não possui Atividade e Fragmento. Existem Navegador (Navegador) e Rotas (rotas). O aplicativo Flutter é semelhante a um aplicativo de atividade única, em que telas diferentes representam fragmentos diferentes e o FragmentManager os controla. O Navegador é semelhante ao FragmentManager em princípio. Pode pressionar push () ou pop () para a rota que você especificar. A rota é um tipo de fragmento, mas no Flutter é comum comparar com uma tela ou página.

No Android, descrevemos todas as atividades entre as quais podemos navegar no AndroidManifest.xml.

O Flutter tem duas maneiras:

  • Descrever um mapa chamado Route (MaterialApp)
  • Navegue diretamente para o Route (WidgetApp).

Um exemplo:


 void main() { runApp(MaterialApp( 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'); 

Pergunta:


Como processar intenções provenientes de outros aplicativos?

A resposta é:


Interagindo com a camada Android do aplicativo por meio do MethodChannel .

Um exemplo:


Escrevemos filtro de intenção no AndroidManifest.xml:

 <activity android:name=".MainActivity" android:launchMode="singleTop" android:theme="@style/LaunchTheme" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection" android:hardwareAccelerated="true" android:windowSoftInputMode="adjustResize"> <!-- ... --> <intent-filter> <action android:name="android.intent.action.SEND" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="text/plain" /> </intent-filter> </activity> 

Processamos o Intent em MainActivity e chamamos o código do Flutter por meio do MethodChannel:

 package com.example.shared; import android.content.Intent; import android.os.Bundle; import java.nio.ByteBuffer; import io.flutter.app.FlutterActivity; import io.flutter.plugin.common.ActivityLifecycleListener; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; import io.flutter.plugins.GeneratedPluginRegistrant; public class MainActivity extends FlutterActivity { private String sharedText; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); GeneratedPluginRegistrant.registerWith(this); Intent intent = getIntent(); String action = intent.getAction(); String type = intent.getType(); if (Intent.ACTION_SEND.equals(action) && type != null) { if ("text/plain".equals(type)) { handleSendText(intent); // Handle text being sent } } new MethodChannel(getFlutterView(), "app.channel.shared.data").setMethodCallHandler( new MethodCallHandler() { @Override public void onMethodCall(MethodCall call, MethodChannel.Result result) { if (call.method.contentEquals("getSharedText")) { result.success(sharedText); sharedText = null; } } }); } void handleSendText(Intent intent) { sharedText = intent.getStringExtra(Intent.EXTRA_TEXT); } } 

Solicitamos dados quando o widget começa a ser desenhado:

 import 'package:flutter/material.dart'; import 'package:flutter/services.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 Shared App Handler', 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> { static const platform = const MethodChannel('app.channel.shared.data'); String dataShared = "No data"; @override void initState() { super.initState(); getSharedText(); } @override Widget build(BuildContext context) { return Scaffold(body: Center(child: Text(dataShared))); } getSharedText() async { var sharedData = await platform.invokeMethod("getSharedText"); if (sharedData != null) { setState(() { dataShared = sharedData; }); } } } 

Pergunta:


Qual é o análogo de startActivityForResult () ?

A resposta é:


A palavra-chave wait e o resultado de uma classe Future .

Diferenças:


Depois de chamar startActivityForResult () no Android, precisamos implementar o processamento em onActivityResult (). O Flutter não precisa implementar nada, porque O método navigator push () retorna um objeto Future.

Um exemplo:


 Map coordinates = await Navigator.of(context).pushNamed('/location'); 

E quando tivermos as coordenadas na tela '/ location', pop ():

 Navigator.of(context).pop({"lat":43.821757,"long":-79.226392}); 

Interface do usuário assíncrona


Pergunta:


Qual é o análogo de runOnUiThread () no Flutter?

A resposta é:


O Dart implementa um modelo de execução de thread único que é executado no Isolates . A execução assíncrona usa async / waitit, que você pode estar familiarizado com as rotinas C #, JavaScript ou Kotlin.

Um 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:


Carregando e atualizando 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); }); } } 

Pergunta:


Como executar código em um thread em segundo plano?

A resposta é:


Como mencionado acima - usando assíncrono / espera e isolamento (Isolar).

Diferenças:


Pronto para uso no Android, você pode usar o AsyncTask. Você precisa implementar onPreExecute () , doInBackground () , onPostExecute () nele . No Flutter "pronto para uso", você só precisa usar assíncrono / aguardar, o Dart cuidará do resto.

Um exemplo:


Aqui o método dataLoader () é isolado. Isoladamente, você pode executar operações pesadas, como analisar JSONs grandes, criptografia, processamento de imagem etc.

 loadData() async { ReceivePort receivePort = ReceivePort(); await Isolate.spawn(dataLoader, receivePort.sendPort); // The 'echo' isolate sends its SendPort as the first message SendPort sendPort = await receivePort.first; List msg = await sendReceive(sendPort, "https://jsonplaceholder.typicode.com/posts"); setState(() { widgets = msg; }); } // The entry point for the isolate static dataLoader(SendPort sendPort) async { // Open the ReceivePort for incoming messages. ReceivePort port = ReceivePort(); // Notify any other isolates what port this isolate listens to. sendPort.send(port.sendPort); await for (var msg in port) { String data = msg[0]; SendPort replyTo = msg[1]; String dataURL = data; http.Response response = await http.get(dataURL); // Lots of JSON to parse replyTo.send(json.decode(response.body)); } } Future sendReceive(SendPort port, msg) { ReceivePort response = ReceivePort(); port.send([msg, response.sendPort]); return response.first; }   : import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; import 'dart:async'; import 'dart:isolate'; void main() { runApp(SampleApp()); } class SampleApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Sample App', theme: ThemeData( primarySwatch: Colors.blue, ), home: SampleAppPage(), ); } } class SampleAppPage extends StatefulWidget { SampleAppPage({Key key}) : super(key: key); @override _SampleAppPageState createState() => _SampleAppPageState(); } class _SampleAppPageState extends State<SampleAppPage> { List widgets = []; @override void initState() { super.initState(); loadData(); } showLoadingDialog() { if (widgets.length == 0) { return true; } return false; } getBody() { if (showLoadingDialog()) { return getProgressDialog(); } else { return getListView(); } } getProgressDialog() { return Center(child: CircularProgressIndicator()); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Sample App"), ), body: getBody()); } ListView getListView() => ListView.builder( itemCount: widgets.length, itemBuilder: (BuildContext context, int position) { return getRow(position); }); Widget getRow(int i) { return Padding(padding: EdgeInsets.all(10.0), child: Text("Row ${widgets[i]["title"]}")); } loadData() async { ReceivePort receivePort = ReceivePort(); await Isolate.spawn(dataLoader, receivePort.sendPort); // The 'echo' isolate sends its SendPort as the first message SendPort sendPort = await receivePort.first; List msg = await sendReceive(sendPort, "https://jsonplaceholder.typicode.com/posts"); setState(() { widgets = msg; }); } // the entry point for the isolate static dataLoader(SendPort sendPort) async { // Open the ReceivePort for incoming messages. ReceivePort port = ReceivePort(); // Notify any other isolates what port this isolate listens to. sendPort.send(port.sendPort); await for (var msg in port) { String data = msg[0]; SendPort replyTo = msg[1]; String dataURL = data; http.Response response = await http.get(dataURL); // Lots of JSON to parse replyTo.send(json.decode(response.body)); } } Future sendReceive(SendPort port, msg) { ReceivePort response = ReceivePort(); port.send([msg, response.sendPort]); return response.first; } } 

Pergunta:


O que é equivalente ao Flutter do OkHttp ?

A resposta é:


O Flutter possui seu próprio pacote HTTP .

Informações adicionais:


Até o momento, nem todos os recursos do OkHttp foram implementados no pacote HTTP; portanto, muitos dos recursos ausentes são abstraídos e você pode implementá-los, conforme necessário.

Um exemplo:


Para usar o pacote HTTP, adicione-o como uma dependência no pubspec.yaml:

 dependencies: ... http: ^0.11.3+16 

Para executar a solicitação, aguarde a chamada na função assíncrona http.get ():

 import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; [...] loadData() async { String dataURL = "https://jsonplaceholder.typicode.com/posts"; http.Response response = await http.get(dataURL); setState(() { widgets = json.decode(response.body); }); } } 

Pergunta:


Como mostrar progresso?

A resposta é:


Usando o widget ProgressIndicator .

Um exemplo:


 import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; void main() { runApp(SampleApp()); } class SampleApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Sample App', theme: ThemeData( primarySwatch: Colors.blue, ), home: SampleAppPage(), ); } } class SampleAppPage extends StatefulWidget { SampleAppPage({Key key}) : super(key: key); @override _SampleAppPageState createState() => _SampleAppPageState(); } class _SampleAppPageState extends State<SampleAppPage> { List widgets = []; @override void initState() { super.initState(); loadData(); } showLoadingDialog() { return widgets.length == 0; } getBody() { if (showLoadingDialog()) { return getProgressDialog(); } else { return getListView(); } } getProgressDialog() { return Center(child: CircularProgressIndicator()); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Sample App"), ), body: getBody()); } ListView getListView() => ListView.builder( itemCount: widgets.length, itemBuilder: (BuildContext context, int position) { return getRow(position); }); Widget getRow(int i) { return Padding(padding: EdgeInsets.all(10.0), child: Text("Row ${widgets[i]["title"]}")); } loadData() async { String dataURL = "https://jsonplaceholder.typicode.com/posts"; http.Response response = await http.get(dataURL); setState(() { widgets = json.decode(response.body); }); } } 

Estrutura e Recursos do Projeto


Pergunta:


Onde armazenar recursos de diferentes resoluções?

A resposta é:


Em ativos.

Diferenças:


No Android, os recursos têm uma pasta res e ativos. Flutter tem apenas ativos. A pasta de ativos pode estar localizada em qualquer lugar do projeto, principalmente, escreva o caminho para ele no arquivo pubspec.yaml.

Informações adicionais:


Comparação dos tamanhos de recursos gráficos no Android e no Flutter.
Qualificador de densidade do AndroidProporção de pixel oscilante
ldpi0,75x
mdpi1.0x
hdpi1,5x
xhdpi2,0x
xxhdpi3.0x
xxxhdpi4.0x
O Flutter usa o AssetManager ou classes especializadas começando com o Asset para usar os recursos no código.

Um exemplo:


AssetManager:

 val flutterAssetStream = assetManager.open("flutter_assets/assets/my_flutter_asset.png") 

Local do 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 

Caminho no arquivo pubspec.yaml:

 assets: - images/my_icon.jpeg 

Usando AssetImage :

 return AssetImage("images/a_dot_burr.jpeg"); 

Usando o ativo diretamente:

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

Pergunta:


Onde armazenar cordas? Como localizá-los?

A resposta é:


Armazenar em campos estáticos. Localize usando o pacote intl .

Um exemplo:


 class Strings { static String welcomeMessage = "Welcome To Flutter"; } Text(Strings.welcomeMessage) 

Pergunta:


Qual é o análogo do arquivo gradle? Como adicionar dependências?

A resposta é:


pubspec.yaml.

Informações adicionais:


O Flutter delega a montagem aos construtores nativos do Android e iOS. Veja uma lista de todas as bibliotecas populares de Flutter no Pub .

Atividades e Fragmentos


Pergunta:


Qual é o equivalente de Atividade e Fragmento em Flutter?

A resposta é:


Tudo no Flutter é widgets. O papel da atividade e dos fragmentos para trabalhar com a interface do usuário é desempenhado por widgets. E o papel da navegação, conforme mencionado no parágrafo sobre navegação, é Navegador e Rota.

Informações adicionais:


Flutter Para desenvolvedores do Android: como criar uma UI de atividade no Flutter .

Pergunta:


Como lidar com eventos do ciclo de vida?

A resposta é:


Usando o método WidgetsBinding e didChangeAppLifecycleState () .

Informações adicionais:


Flutter usa FlutterActivity no código nativo, e 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.

Isso é descrito em mais detalhes na documentação do AppLifecycleStatus .

Um 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


Pergunta:


Qual é o análogo do LinearLayout ?

A resposta é:


Linha para horizontal, coluna para vertical.

Informações adicionais:


Flutter Para desenvolvedores do Android: como criar o LinearLayout no Flutter?

Um exemplo:


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

Pergunta:


Qual é o equivalente a RelativeLayout ?

A resposta é:


Pilha de Widget.

Mais detalhes:

Stackoverflow

Pergunta:


Qual é o análogo do ScrollView ?

A resposta é:


ListView com widgets.

Um exemplo:


 @override Widget build(BuildContext context) { return ListView( children: <Widget>[ Text('Row One'), Text('Row Two'), Text('Row Three'), Text('Row Four'), ], ); } 

Pergunta:


Como lidar com transições entre retrato e paisagem?

A resposta é:


FlutterView manipula inversões se AndroidManifest.xml contiver
android: configChanges = "orientação | tamanho da tela"

Gestos e manipulação de eventos por toque


Pergunta:


Como adicionar um ouvinte onClick para widget no Flutter?

A resposta é:


Se o widget suportar cliques, em onPressed (). Caso contrário, em onTap ().

Um exemplo:


Em onPressed ():

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

Em onTap ():

 class SampleApp extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( body: Center( child: GestureDetector( child: FlutterLogo( size: 200.0, ), onTap: () { print("tap"); }, ), )); } } 

Pergunta:


Como lidar com outros gestos em widgets?

A resposta é:


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

Toque



Toque duas vezes



Pressão longa



Arrasto vertical



Arrasto horizontal



Um exemplo:


Processando onDoubleTap:

 AnimationController controller; CurvedAnimation curve; @override void initState() { controller = AnimationController(duration: const Duration(milliseconds: 2000), vsync: this); curve = CurvedAnimation(parent: controller, curve: Curves.easeIn); } class SampleApp extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( body: Center( child: GestureDetector( child: RotationTransition( turns: curve, child: FlutterLogo( size: 200.0, )), onDoubleTap: () { if (controller.isCompleted) { controller.reverse(); } else { controller.forward(); } }, ), )); } } 

Listviews e adaptadores


Pergunta:


Qual é o análogo do ListView no Flutter?

A resposta é:


ListView

Diferenças:


O Flutter não precisa pensar em limpar e reutilizar itens (que é o que o ListView / RecyclerView faz no Android, usando o padrão ViewHolder).

Um 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> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Sample App"), ), body: ListView(children: _getListData()), ); } _getListData() { List<Widget> widgets = []; for (int i = 0; i < 100; i++) { widgets.add(Padding(padding: EdgeInsets.all(10.0), child: Text("Row $i"))); } return widgets; } } 

:


?

A resposta é:


GestureDetector .

Um 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> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Sample App"), ), body: ListView(children: _getListData()), ); } _getListData() { List<Widget> widgets = []; for (int i = 0; i < 100; i++) { widgets.add(GestureDetector( child: Padding( padding: EdgeInsets.all(10.0), child: Text("Row $i")), onTap: () { print('row tapped'); }, )); } return widgets; } } 

:


ListView ?

A resposta é:


, setState() . , ListView.Builder , RecyclerView .

Um exemplo:


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 = <Widget>[]; @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 = <Widget>[]; @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'); }); }, ); } } 


:


?

A resposta é:


( ) pubspec.yaml.

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

:


?

A resposta é:


:

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


: Retrieve the value of a text field .

:


hint TextInput ?

A resposta é:


InputDecoration , .

Um exemplo:


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

:


?

A resposta é:


InputDecoration .

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

Flutter


:


GPS?

A resposta é:


geolocator .

:


?

A resposta é:


image_picker .

:


Facebook?

A resposta é:


flutter_facebook_login .

:


Firebase?

A resposta é:


Firebase Flutter first party plugins .


:


() ?

A resposta é:


Flutter EventBus . : developing packages and plugins .

:


NDK?

A resposta é:


NDK- Flutter. Flutter .

Themes


:


(Theme) ?

A resposta é:


MaterialApp WidgetApp .

Um exemplo:


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


:


Shared Preferences?

A resposta é:


Shared_Preferences plugin ( NSUserDefaults iOS ).

Um exemplo:


 import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; void main() { runApp( MaterialApp( home: Scaffold( body: Center( child: RaisedButton( onPressed: _incrementCounter, child: Text('Increment Counter'), ), ), ), ), ); } _incrementCounter() async { SharedPreferences prefs = await SharedPreferences.getInstance(); int counter = (prefs.getInt('counter') ?? 0) + 1; print('Pressed $counter times.'); prefs.setInt('counter', counter); } 

:


SQLite Flutter?

A resposta é:


SQFlite .


:


push-?

A resposta é:


Firebase_Messaging .

Conclusão


. , , . « » . «-» . , ? 2016 Kotlin, - 2017. , , . , .
2016 Flutter Dart. , 2018 . . ! , , , . ( Google Fuchsia , , , Flutter ). — ! , — . Isso é tudo para mim. Google Play!

Source: https://habr.com/ru/post/pt442432/


All Articles