android studio一个页面等待3秒跳转_Flutter 对 iOS、Android(双端开发者)的快速理解(二)...

原文链接 http://tryenough.com/flutter09

更多教程 https://tryenough.com/type-flutter


Flutter怎么在不同页面之间跳转?

  • 在 iOS 中,你可以使用管理了 view controller 栈的 UINavigationController 来在不同的 view controller 之间跳转。
  • 在Android中,Intents主要有两种使用场景:在Activity之间切换,以及调用外部组件。
  • 在Flutter中切换屏幕,您可以访问路由以绘制新的Widget。 管理多个屏幕有两个核心概念和类:Route 和 Navigator。Route是应用程序的“屏幕”或“页面”的抽象(可以认为是Android中的Activity或iOS中的UIViewController), Navigator是管理Route的Widget。Navigator可以通过push和pop 路由以实现页面切换。

在Flutter中,您可以将具有指定Route的Map传递到顶层MaterialApp进行声明:

void main() { runApp(new MaterialApp( home: new MyAppHome(), // becomes the route named '/' routes:  { '/a': (BuildContext context) => new MyPage(title: 'page A'), '/b': (BuildContext context) => new MyPage(title: 'page B'), '/c': (BuildContext context) => new MyPage(title: 'page C'), }, ));}

然后,您可以通过Navigator来切换到命名路由的页面。

Navigator.of(context).pushNamed('/b');

通过Navigator获取跳转到的页面的返回值:

例如跳转到location页面,使用关键字await等待结果:

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

在 location 页面中,一旦用户选择了地点,携带结果一起 pop() 出栈,上面的coordinates就能拿到结果:

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

Flutter怎么编写异步的代码?

Dart 的单线程模型并不意味着你写的代码一定是阻塞操作,从而卡住 UI。相反,使用 Dart 语言提供的异步工具,例如 async / await ,来实现异步操作。

loadData() async { String dataURL = "https://jsonplaceholder.typicode.com/posts"; http.Response response = await http.get(dataURL); setState(() { widgets = json.decode(response.body); });}

一旦 await 到网络请求完成,通过调用 setState() 来更新 UI,这会触发 widget 子树的重建,并更新相关数据。

下面的例子展示了异步加载数据,并用 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 { 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包,要使用 http 包,在 pubspec.yaml 中把它添加为依赖:

dependencies: ... http: ^0.11.3+16

运行效果如下:

666053a5f0ce1efe5d5a5d162237797f.png

这就是对诸如网络请求或数据库访问等 I/O 操作的典型做法。

然而,有时候你需要处理大量的数据,这会导致你的 UI 挂起。在 Flutter 中,使用 Isolate 来发挥多核心 CPU 的优势来处理那些长期运行或是计算密集型的任务。

Isolates 是分离的运行线程,并且不和主线程的内存堆共享内存。这意味着你不能访问主线程中的变量,或者使用 setState() 来更新 UI。正如它们的名字一样,Isolates 不能共享内存。

下面的例子展示了一个简单的 isolate,是如何把数据返回给主线程来更新 UI 的:

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

“dataLoader”是在它自己的独立执行线程中运行的隔离区,您可以在其中执行CPU密集型任务,例如解析大于1万的JSON或执行计算密集型数学计算。

你可以运行下面的完整例子:

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

效果如下:

3baa86127caae060bcb844a9e4b403eb.gif

Flutter中显示进度指示器loading

在 Flutter 中,使用一个 ProgressIndicator widget。通过一个布尔 flag 来控制是否展示进度。在任务开始时,告诉 Flutter 更新状态,并在结束后隐去。

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

效果同上面的gif。

Flutter工程结构、本地化、依赖和资源如何引入?

图片等资源在 Flutter 中被放到了 assets 文件夹中。assets 可以是任意类型的文件,而不仅仅是图片。例如,你可以把 json 文件放置到 my-assets 文件夹中my-assets/data.json。

在 pubspec.yaml 文件中声明 assets:

assets: - my-assets/data.json

然后在代码中使用 AssetBundle 来访问它:

import 'dart:async' show Future;import 'package:flutter/services.dart' show rootBundle;Future loadAsset() async { return await rootBundle.loadString('my-assets/data.json');}

图片资源:Flutter遵循像iOS这样简单的3种分辨率格式: 1x, 2x, and 3x。

举个例子,要把一个叫 my_icon.png 的图片放到 Flutter 工程中,你可能想要把存储它的文件夹叫做 images。把基础图片(1.0x)放置到 images 文件夹中,并把其他变体放置在子文件夹中,并接上合适的比例系数:

images/my_icon.png // Base: 1.0x imageimages/2.0x/my_icon.png // 2.0x imageimages/3.0x/my_icon.png // 3.0x image

接着,在 pubspec.yaml 文件夹中声明这些图片:

assets: - images/my_icon.jpeg

你可以用 AssetImage 来访问这些图片:

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

或者在 Image widget 中直接使用:

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

Flutter中的字符串资源

目前,最好的做法是创建一个名为Strings的类:

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

然后在你的代码中,你可以像访问你的字符串一样:

new Text(Strings.welcomeMessage)

鼓励Flutter开发者使用intl package 进行国际化和本地化

由于篇幅过长,文章将分为多部分,请继续关注本文其他部分。

原文链接 http://tryenough.com/flutter09

更多教程 https://tryenough.com/type-flutter

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值