这是Flutter文档的简要解释的最后一部分,这将对Xamarin.Forms开发人员很有用。鉴于当前的情况,现在该学习一些新知识了!通过削减,您可以为自己找到足够的信息,以评估从一个跨平台框架迁移到另一个框架是否值得,以及花费多长时间。
如果这些信息还不够,或者您有特定平台的本机开发经验,那么我建议您查看其他部分:Flutter。第1部分。适用于Android开发人员Flutter。第2部分。面向iOS开发人员Flutter。第3部分。面向React NativeFlutter 开发人员。第4部分。针对Flutter Web开发人员。第5部分。对于Xamarin.Forms开发人员内容:
- 项目
- Views
- Async UI
- Layouts
- ListView
- 文本
- Flutter插件
- 平台特定的代码
- 调试
- 本地存储
项目
题:
入口在哪里?回答:
功能main()
。差异:
在Xamarin.Forms中是LoadApplication(new App());
。例:
void main() {
runApp(new MyApp());
}
题:
如何创建页面或元素?回答:
Flutter本身没有Page和Element的概念。所有组件都是小部件。Flutter有2种小部件:StatelessWidget和StatefulWidget。它们以相同的方式工作,唯一的区别在于渲染状态。差异:
StatelessWidget具有不可变状态。适用于显示文本,徽标等。那些。如果屏幕上的元素在整个显示时间内均不应更改,则适合您。它也可以用作有状态窗口小部件的容器。StatefulWidget具有State类,该类存储有关当前状态的信息。如果要在执行某些操作时更改屏幕上的元素(来自服务器的响应,用户单击按钮等),这是您的选择。例:
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),
),
);
}
}
观看次数
题:
如何安排小部件?相当于什么XAML
文件?回答:
在Flutter中,布局是使用小部件树直接在代码中完成的。区别:
在Xamarin.Forms中,最常见的布局是在XAML
.file中完成。Flutter没有等效的功能。附加信息:
小部件列表可以在此处查看。例:
@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),
),
),
);
}
题:
如何通过代码添加或删除小部件?回答:
通过更新父窗口小部件的状态,然后重建窗口小部件树。差异:
在Xamarin.Forms中,可以使用Content
元素或方法Add()
和的属性来完成此操作Remove()
。例:
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),
),
);
}
}
题:
如何为小部件制作动画?回答:
使用Animation和AnimationController类。差异:
Xamarin.Forms使用ViewExtensions和类似FadeTo
或的方法TranslateTo
。附加信息:
在此处
阅读有关动画的更多信息。例:
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();
},
),
);
}
}
题:
如何在屏幕上绘制?回答:
使用CustomPaint和CustomPainter类。差异:
Xamarin.Forms使用第三方SkiaSharp。在Flutter中,直接从包装盒中使用Skia画布。例:
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;
}
题:
如何改变透明度?回答:
使用不透明度小部件。差异:
Xamarin.Forms用途不透明的VisualElement。在Flutter中,您只需要在Opacity中包装所需的小部件。题:
如何创建自定义窗口小部件?回答:
将它们组成一个(而不是继承)。差异:
在Xamarin.Forms中,您可以从我们感兴趣的VisualElement继承并添加自己的逻辑。在Flutter中,小部件始终从StatelessWidget和StatefulWidget继承。那些。您需要创建一个新的小部件,并将其中的必要小部件集用作参数或字段。例:
class CustomButton extends StatelessWidget {
final String label;
CustomButton(this.label);
@override
Widget build(BuildContext context) {
return new RaisedButton(onPressed: () {}, child: new Text(label));
}
}
导航
题:
如何在屏幕之间导航?回答:
要在屏幕之间导航,请使用Navigator和Route类。差异:
Xamarin.Forms使用NavigationPage。Flutter有两种类似于NavigationPage的导航方法:- 映射名称以描述Route ;
- 直接导航到Route。
导航器可以将()或pop()推送到您指定的路线。例:
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');
题:
如何导航到第三方应用程序?回答:
通过MethodChannel或url_launcher插件使用本机实现。异步用户界面
题:
相当于Device.BeginInvokeOnMainThread()?如何异步执行代码?回答:
Dart实现了一个在Isolates上运行的单线程执行模型。对于异步执行,请使用C#熟悉的async / await。例:
完成请求并返回结果以更新UI:loadData() async {
String dataURL = "https://jsonplaceholder.typicode.com/posts";
http.Response response = await http.get(dataURL);
setState(() {
widgets = json.decode(response.body);
});
}
收到对请求的响应后,您需要调用setState()方法以使用新数据重绘窗口小部件树。在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);
});
}
}
题:
如何发出网络请求?回答:
使用http插件。例:
通过pubspec.yaml
以下方式连接依赖项:dependencies:
...
http: ^0.11.3+16
查询: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);
});
}
}
题:
如何显示长时间作业的进度?回答:
使用ProgressIndicator。差异:
在Xamarin.Forms中,可以通过在中放置进度指示器直接完成此操作XAML
。例:
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);
});
}
}
项目结构与资源
题:
哪里存储不同分辨率的资源?回答:
在中assets
。差异:
Xamarin.Forms没有用于平台资源的统一存储,因此您必须将它们分别存储在平台文件夹中。有颤动assets
。该文件夹assets
可以位于项目中的任何位置,最重要的是,在文件中写入该文件夹的路径pubspec.yaml
。附加信息:
比较Android和Flutter中图形资源的大小。资源布局示例: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
pubspec.yaml
文件中
路径的示例:assets:
- images/my_icon.jpeg
使用AssetImage的示例:return AssetImage("images/a_dot_burr.jpeg");
直接用法示例asset
:@override
Widget build(BuildContext context) {
return Image.asset("images/my_image.png");
}
题:
在哪里存储字符串?如何定位它们?回答:
Flutter目前没有特定的位置来存储字符串。建议将它们作为静态字段存储在单独的类中。插件用于本地化,例如flutter_localizations或l10n。差异:
Xamarin.Forms使用一个文件resx
。例:
存储:class Strings {
static String welcomeMessage = "Welcome To Flutter";
}
使用:new Text(Strings.welcomeMessage)
本土化: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'),
],
)
题:
项目文件在哪里?回答:
Flutter没有在开发环境中打开该项目的项目文件。最接近的类似文件-- pubspec.yaml
包含对插件和项目详细信息的依赖关系。应用程序生命周期
题:
如何处理生命周期事件?回答:
使用WidgetsBinding和didChangeAppLifecycleState()方法。附加信息:
扑使用FlutterActivity Android中代码和FlutterAppDelegate在IOS;由于这一点,扑引擎使得处理状态改变不惹人可能的。但是,如果您仍然需要根据状态进行一些工作,则生命周期会略有不同:- 无效-此方法仅在iOS中有效,在Android中没有类似功能;
- 已暂停-与Android中的onPause()类似;
- 恢复-类似于Android中的onPostResume();
- 暂停-与Android中的onStop相似,在iOS中没有类似物。
有关更多详细信息,请参见AppLifecycleStatus文档。例:
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()));
}
版面
题:
什么是StackLayout的类似物?回答:
垂直方向
的StackLayout类似为Column,水平方向为Row。例:
柱:@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'),
],
);
}
行:@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'),
],
);
}
题:
网格
的模拟是什么?回答:
GridView。例:
GridView.count(
crossAxisCount: 2,
children: List.generate(100, (index) {
return Center(
child: Text(
'Item $index',
style: Theme.of(context).textTheme.headline,
),
);
}),
);
题:
ScrollView
的类似物是什么?回答:
最接近的类似物是SingleChildScrollView。但是Flutter最经常使用ListView来构建正在爬网的内容。例:
SingleChildScrollView:@override
Widget build(BuildContext context) {
return new SingleChildScrollView(
child: new Text('Long Content'),
);
}
列表显示:@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'),
],
);
}
手势处理
题:
如何处理点击?回答:
如果窗口小部件支持方法onPressed
,则可以使用它来处理单击。否则,这可以通过GestureDetector完成。例:
onPressed:@override
Widget build(BuildContext context) {
return new RaisedButton(
onPressed: () {
print("click");
},
child: new Text("Button"));
}
手势检测器: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");
},
),
));
}
}
题:
如何处理手势?回答:
使用GestureDetector。他们可以执行以下操作:点按
双击
长按
垂直拖曳
水平拖曳
例:
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和适配器
题:
什么是ListView的类似物?回答:
ListView。差异:
在Xamarin.Forms中,您需要创建一个ViewCell和(通常是)一个DataTemplateSelector并将它们传递给ListView。在Flutter中,您只需要传递要显示的小部件列表即可。例:
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;
}
}
题:
如何确定单击了哪个元素?回答:
在Flutter中,元素小部件必须自己处理其单击。差异:
Xamarin.Forms最常使用ItemTapped。例:
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;
}
}
题:
如何动态更新ListView?回答:
刷新数据列表并调用setState()
。差异:
Xamarin.Forms为此使用了ItemsSource。在Flutter中,setState()
小部件将再次重绘。例:
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');
});
},
);
}
}
附加信息:
要创建列表,建议使用ListView.Builder。例:
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');
});
},
);
}
}
文本
题:
如何使用自定义字体?回答:
您只需要将字体文件放在一个文件夹中(以自己的名字命名)并指出其路径pubspec.yaml
。例:
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'),
),
),
);
}
题:
如何设置文字小部件的样式?回答:
使用参数:- 颜色;
- 装饰;
- 装饰颜色;
- 装饰风格;
- 字体系列;
- 字体大小;
- 字体样式;
- fontWeight;
- hashCode;
- 高度;
- 继承;
- 字母间距;
- textBaseline;
- wordSpacing。
题:
占位符
等于多少?回答:
该hintText财产的InputDecoration。例:
body: new Center(
child: new TextField(
decoration: new InputDecoration(hintText: "This is a hint"),
)
)
题:
如何显示验证错误?回答:
与InputDecoration及其状态相同。例:
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插件
题:
如何访问GPS?回答:
使用geolocator插件。题:
如何使用相机?回答:
使用image_picker插件。题:
如何通过Facebook登录?回答:
使用flutter_facebook_login插件。题:
如何使用firebase?回答:
Firebase支持Flutter第一方插件:平台特定的代码
题:
如何确定代码在哪个平台上运行?回答:
platform
在Theme或Platform类中
使用字段类。例:
领域 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 ';
}
平台类别:if (Platform.isIOS) {
return 'iOS';
} else if (Platform.isAndroid) {
return 'android';
} else if (Platform.isFuchsia) {
return 'fuchsia';
} else {
return 'not recognised ';
}
题:
如何调用本机平台代码?回答:
通过MethodChannel。附加信息:
更多细节在这里。调试
题:
有哪些调试应用程序的工具?回答:
开发工具。题:
怎么办hot reload
?回答:
如果应用程序是从IntelliJ IDE,Android Studio或VSCode启动的,则可以通过组合⌘s/ctrl-s
或单击图标来启动hot reload
。如果从终端启动,则输入字母r
。题:
如何访问应用程序中的开发人员菜单?回答:
如果是从IDE启动的,则使用IDE工具。如果从控制台,则使用h。附加信息:
命令完整列表:本地存储
题:
如何key-value
在应用程序中存储数据?回答:
使用shared_preferences插件。差异:
在Xamarin.Forms中使用Xam.Plugins.Settings
。例:
连接依赖性:dependencies:
flutter:
sdk: flutter
shared_preferences: ^0.4.3
使用:SharedPreferences prefs = await SharedPreferences.getInstance();
_counter = prefs.getInt('counter');
prefs.setInt('counter', ++_counter);
setState(() {
_counter = _counter;
});
题:
如何存储复杂数据?回答:
使用sqflite或hive等数据库插件。这也许是基本问题的答案。这结束了一系列的解释。我希望它们对所有对此框架感兴趣的开发人员都有用。也许您甚至开始写Flutter,并将您招募到Flutter开发人员的友好社区中。我将考虑使用新文章来发展社区,并使应用程序世界变得更美好。希望您的表格不会破坏Xamarin!