Após um longo intervalo, continuarei a falar sobre a estrutura popular do Flutter em um formato de perguntas e respostas. Você pode encontrar o primeiro artigo para desenvolvedores do Android
aqui , e hoje haverá material útil para desenvolvedores para iOS.
Se você tiver pouco tempo para um estudo independente e aprofundado da documentação, mas deseja entender o que o Flutter é bom e como usá-lo, consulte o gato.
Flutter. Parte 1. Para desenvolvedores do AndroidFlutter. Parte 2. Para desenvolvedores do iOSFlutter. Parte 3. Para reagir a desenvolvedores nativosFlutter. Parte 4. Para desenvolvedores da webFlutter. Parte 5. Para desenvolvedores do Xamarin.Forms
Conteúdo:
- Visualizações
- Navegação
- Rosqueamento e assincronicidade
- Estrutura e Recursos do Projeto
- ViewControllers
- Layouts
- Gestos e manipulação de eventos por toque
- Estilo de aplicativo
- Formulário de entrada
- Flutter Plugins
- Bancos de dados e armazenamento local
- Notificações
Visualizações
Pergunta:
O que é o
analógico UIView no Flutter?
A resposta é:
WidgetDiferenças:
UIView é realmente o que estará na tela. SetNeedsDisplay () é chamado para exibir as alterações.
Widget - uma descrição do que estará na tela. Pois a mudança é criada novamente.
Informações adicionais:
O Flutter inclui a biblioteca
Cupertino Widgets . Ele contém widgets que implementam as
diretrizes de design da Apple .
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 flutter para
Flutter é impressionante! import 'package:flutter/material.dart'; void main() { runApp(SampleApp()); } class SampleApp extends StatelessWidget {
Pergunta:
Como fazer o layout de uma tela com widgets? Onde está o
storyboard ?
A resposta é:
Flutter não tem
Storyboard . 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: CupertinoButton( onPressed: () { setState(() { _pressedCount += 1; }); }, 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 iOS, você pode adicionar addview () ou remover fromSuperview (). No Flutter, você não pode os widgets permanecem inalterados. Somente sua condição pode mudar.
Um exemplo:
Mude o texto para o botão clicando em FloatingActionButton.
class SampleApp extends StatelessWidget {
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 iOS, você pode animar uma exibição usando animar (com Duração: animações :). 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.
class SampleApp extends StatelessWidget {
Pergunta:
Como usar o
CoreGraphics ?
A resposta é:
O Flutter usa a API do Canvas no
mecanismo de baixo nível do
Skia, em vez do CoreGraphics. O Android usa uma API Canvas semelhante.
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:
StackOverflowUm exemplo:
class SignaturePainter extends CustomPainter { SignaturePainter(this.points); final List<Offset> points; void paint(Canvas canvas, Size size) { var paint = Paint() ..color = Colors.black ..strokeCap = StrokeCap.round ..strokeWidth = 5.0; for (int i = 0; i < points.length - 1; i++) { if (points[i] != null && points[i + 1] != null) canvas.drawLine(points[i], points[i + 1], paint); } } bool shouldRepaint(SignaturePainter other) => other.points != points; } class Signature extends StatefulWidget { SignatureState createState() => SignatureState(); } class SignatureState extends State<Signature> { List<Offset> _points = <Offset>[]; Widget build(BuildContext context) { return GestureDetector( onPanUpdate: (DragUpdateDetails details) { setState(() { RenderBox referenceBox = context.findRenderObject(); Offset localPosition = referenceBox.globalToLocal(details.globalPosition); _points = List.from(_points)..add(localPosition); }); }, onPanEnd: (DragEndDetails details) => _points.add(null), child: CustomPaint(painter: SignaturePainter(_points), size: Size.infinite), ); } }
Pergunta:
Como mudar a transparência dos widgets?
A resposta é:
Quebra no widget
Opacidade .
Diferenças:
No iOS, todas as visualizações têm .opacity ou .alpha. No Flutter, essa opção substitui o widget do wrapper.
Pergunta:
Como criar widgets personalizados?
A resposta é:
Componha widgets dentro de um (em vez de herança).
Diferenças:
No iOS, você pode herdar da exibição que nos interessa e adicionar sua própria lógica. No Flutter, um 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"), ); }
Navegação
Pergunta:
Como implementar a navegação entre telas no Flutter?
A resposta é:
A navegação entre telas usa as classes
Navigator e
Route .
Diferenças:
O Flutter não possui conceitos como UIViewController e UINavigationController. Existem Navegador (Navegador) e Rotas (rotas). O Navegador é semelhante ao UINavigationController em princípio. Pode
pressionar push () ou
pop () para a rota que você especificar. Route é um tipo de UIViewController, mas no Flutter é comum comparar com uma tela ou página.
O Flutter possui dois métodos de navegação:
- Descrever um mapa com nomes de rotas
- Navegue diretamente para a rota.
Um exemplo:
void main() { runApp(CupertinoApp( home: MyAppHome(),
Pergunta:
Como navegar para um aplicativo de terceiros?
A resposta é:
Interagindo com a camada iOS do aplicativo por meio do
MethodChannel ou usando o plug-in do
iniciador de URL .
Pergunta:
Como voltar ao iOS no ViewController?
A resposta é:
Chamando SystemNavigator.pop ().
Informações adicionais:
SystemNavigator.pop () do código Dart chama o seguinte código no iOS:
UIViewController* viewController = [UIApplication sharedApplication].keyWindow.rootViewController; if ([viewController isKindOfClass:[UINavigationController class]]) { [((UINavigationController*)viewController) popViewControllerAnimated:NO]; }
Se não é isso que você precisa, você pode fazer sua implementação através do
MethodChannel .
Rosqueamento e assincronicidade
Pergunta:
Como escrever código assíncrono 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, com a qual 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 iOS, você pode usar o Operation com uma possível redefinição de métodos. 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);
Pergunta:
Como fazer solicitações de rede no Flutter?
A resposta é:
O Flutter possui seu próprio
pacote HTTP .
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 iOS, os recursos gráficos têm o Images.xcasset, localizado na pasta de ativos. Flutter tem apenas ativos. A pasta do recurso pode estar localizada em qualquer lugar do projeto, e o mais importante, escreva o caminho para ele no arquivo pubspec.yaml.
Informações adicionais:
Os tamanhos dos recursos gráficos no iOS e no Flutter são idênticos e seguem o formato baseado em densidade.
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.png
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 é a contrapartida do CocoaPods? Como adicionar dependências?
A resposta é:
pubspec.yaml.
Informações adicionais:
O Flutter delega a construção para construtores nativos do Android e iOS. Veja uma lista de todas as bibliotecas populares de Flutter no
Pub .
ViewControllers
Pergunta:
Qual é o equivalente do
ViewController no Flutter?
A resposta é:
Tudo no Flutter é widgets. O papel do ViewController 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.
Pergunta:
Como lidar com eventos do ciclo de vida?
A resposta é:
Usando o
método WidgetsBinding e
didChangeAppLifecycleState () .
Informações adicionais:
O Flutter usa FlutterAppDelegate no código nativo, e o mecanismo Flutter torna o tratamento das alterações de estado o mais discreto possível. Mas se você ainda precisa fazer algum trabalho, dependendo do estado, o ciclo de vida é um pouco diferente:
- inativo - o aplicativo está inativo e não recebe entrada do usuário. Este estado é apenas no iOS, no Android não há analógico;
- pausado - o aplicativo está atualmente invisível para o usuário, não responde à entrada do usuário, mas funciona em segundo plano;
- retomado - o aplicativo está visível e responde à entrada do usuário;
- suspensão - aplicação no processo de parada. Este estado é apenas 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 equivalente de
UITableView e
UICollectionView ?
A resposta é:
ListViewUm exemplo:
import 'package:flutter/material.dart'; void main() { runApp(SampleApp()); } class SampleApp extends StatelessWidget {
Pergunta:
Como sei em qual item da lista foi clicado?
A resposta é:
O widget, que é um elemento da lista, deve manipular o clique nele.
Diferenças:
No iOS, o método tableView: didSelectRowAtIndexPath: é o responsável por isso. No Flutter, o item da lista deve ser agrupado em um widget que lida com cliques, como o
GestureDetector .
Pergunta:
Como atualizar dinamicamente um
ListView ?
A resposta é:
Atualize a lista de dados e chame setState ().
Diferenças:
No iOS, você precisa atualizar os dados e chamar o método reloadData. No Flutter, após setState (), o widget será redesenhado novamente.
Um exemplo:
import 'package:flutter/material.dart'; void main() { runApp(SampleApp()); } class SampleApp extends StatelessWidget {
Informações adicionais:
É recomendável usar o
ListView.Builder para criar uma lista.
Um exemplo:
import 'package:flutter/material.dart'; void main() { runApp(SampleApp()); } class SampleApp extends StatelessWidget {
Pergunta:
Qual é o análogo do
UIScrollView ?
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'), ], ); }
Informações adicionais:
Mais detalhes
aqui .
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(); } }, ), ), ); } }
Estilo de aplicativo
Pergunta:
Como usar o tema (Tema) no aplicativo?
A resposta é:
Usando o widget MaterialApp ou WidgetApp como raiz no aplicativo.
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(), ); } }
Pergunta:
Como usar fontes personalizadas?
A resposta é:
Você só precisa colocar o arquivo de fonte na pasta (pense no nome você mesmo) e indicar o caminho para ele em 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'), ), ), ); }
Pergunta:
Como estilizar widgets de texto?
A resposta é:
Usando parâmetros:
- cor;
- decoração;
- decorationColor;
- decorationStyle;
- fontFamily;
- fontSize;
- fontStyle;
- fontWeight;
- hashCode;
- altura;
- herdar;
- letterSpacing;
- textBaseline;
- wordSpacing.
Formulário de entrada
Pergunta:
Como obter o resultado da entrada do usuário?
A resposta é:
Usando
TextEditingController .
Um exemplo:
class _MyFormState extends State<MyForm> {
:
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:
class SampleApp extends StatelessWidget {
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 .
:
UserDefault?
A resposta é:
Shared_Preferences plugin ( Shared Preferences Android ).
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); }
:
Core Data ?
A resposta é:
SQFlite .
:
push-?
A resposta é:
Firebase_Messaging .
Conclusão
. , , . « » . «-» . , ? 2016 Kotlin, - 2017. , , . , .
2016 Flutter Dart. , 2018 . . ! , , , . ( Google Fuchsia , , , Flutter ). — ! , — . . Apple Store!