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 AndroidFlutter. Parte 2. Para desenvolvedores do iOSFlutter. Parte 3. Para reagir a desenvolvedores NativeFlutter. Parte 4. Para desenvolvedores da webFlutter. Parte 5. Para desenvolvedores do Xamarin.FormsConteúdo:
- Projeto
- Views
- Async UI
- Layouts
- ListView
- Texto
- Flutter Plugins
- Código específico da plataforma
- Depuração
- 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 {
@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(
title: new Text(widget.title),
),
body: new Center(
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 XAML
arquivo?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 XAML
arquivo. 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 Content
elemento ou métodos Add()
e Remove()
.Exemplo:
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> {
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 FadeTo
ou 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 {
@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 :- Mapeie os nomes para descrever a rota ;
- Navegue diretamente para Rota .
O Navegador pode pressionar () ou pop () para a rota especificada.Exemplo:
void main() {
runApp(CupertinoApp(
home: MyAppHome(),
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 assets
pode 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.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.yaml
arquivo: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: [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
supportedLocales: [
const Locale('en', 'US'),
const Locale('he', 'IL'),
],
)
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(
crossAxisCount: 2,
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 {
@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 {
@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 {
@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 {
@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 {
@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 platform
em 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-s
ou 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:Armazenamento local
Questão:
Como armazenar key-value
dados 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!