The original link
More tutorials
How does a Flutter jump between pages?
- In iOS, you can jump between view Controllers using the UINavigationController that manages the View Controller stack.
- In Android, Intents are used in two main ways: switching between activities and calling external components.
- Switching screens in Flutter allows you to access routes to draw new widgets. There are two core concepts and classes for managing multiple screens: Route and Navigator. Route is an abstraction of the application’s “screen” or “page” (think of it as an Activity in Android or a UIViewController in iOS), and Navigator is the Widget that manages Route. Navigator can use push and POP routing to switch pages.
In Flutter, you can declare a Map with a specified Route to the top-level MaterialApp:
void main() {
runApp(new MaterialApp(
home: new MyAppHome(), // becomes the route named '/'
routes: <String, WidgetBuilder> {
'/a': (BuildContext context) => new MyPage(title: 'page A'),
'/b': (BuildContext context) => new MyPage(title: 'page B'),
'/c': (BuildContext context) => new MyPage(title: 'page C'),})); }Copy the code
You can then switch to a page with named routes through the Navigator.
Navigator.of(context).pushNamed('/b');
Copy the code
Use Navigator to get the return value of the page to jump to:
For example, jump to the Location page and await the result with the keyword await:
Map coordinates = await Navigator.of(context).pushNamed('/location');
Copy the code
On the Location page, once the user has selected the location, coordinates above it pop() off the stack with the result:
Navigator.of(context).pop({"lat":43.821757."long":79.226392});
Copy the code
How does Flutter code asynchronously?
Dart’s single-threaded model doesn’t mean that you write code that blocks operations and thus jams the UI. Instead, use the asynchronous tools provided by the Dart language, such as async/await, to implement asynchronous operations.
loadData() async {
String dataURL = "https://jsonplaceholder.typicode.com/posts";
http.Response response = await http.get(dataURL);
setState(() {
widgets = json.decode(response.body);
});
}
Copy the code
Once the await to the network request is complete, update the UI by calling setState(), which triggers a rebuild of the widget subtree and updates the associated data.
The following example shows asynchronously loading data and displaying it with a 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); }); }}Copy the code
This example uses the HTTP package. To use the HTTP package, add it as a dependency in pubspec.yaml:
dependencies:
...
http: ^0.113.+16
Copy the code
The running effect is as follows:
This is typical for I/O operations such as network requests or database access.
However, sometimes you need to process a lot of data, which can cause your UI to hang. In Flutter, the Isolate is used to take advantage of multi-core cpus to handle long running or computationally intensive tasks. Computer extensions are separate running threads that do not share memory with the memory heap of the main thread. This means you can’t access variables in the main thread, or use setState() to update the UI. As their name suggests, Computers cannot share memory.
The following example shows a simple ISOLATE that returns data to the main thread to update the 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 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;
}
Copy the code
The “dataLoader” is a quarantine area that runs in its own separate thread of execution where you can perform CPU-intensive tasks, such as parsing JSON larger than 10,000 or performing computationally intensive mathematical calculations.
You can run the full example below:
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]);
returnresponse.first; }}Copy the code
The effect is as follows:
A progress indicator loading is displayed in a Flutter
In Flutter, use a ProgressIndicator widget. A Boolean flag controls whether progress is displayed. Tells Flutter to update its status at the start of the task and disappears at the end.
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: newSampleAppPage(), ); }}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() {
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); }); }}Copy the code
Same effect as GIF above.
How are Flutter engineering structures, localization, dependencies, and resources introduced?
Assets such as images are placed in the assets folder in Flutter. Assets can be any type of document, not just an image. For example, you can put json files in my-Assets /data.json.
Declare assets in the pubspec.yaml file:
assets:
- my-assets/data.json
Copy the code
Then use the AssetBundle in your code to access it:
import 'dart:async' show Future;
import 'package:flutter/services.dart' show rootBundle;
Future<String> loadAsset() async {
return await rootBundle.loadString('my-assets/data.json');
}
Copy the code
Flutter follows three resolution formats as simple as iOS: 1x, 2X, and 3X.
For example, to put an image called my_icon. PNG into the Flutter project, you might want to call the folder in which it is stored images. Place the base image (1.0x) in the images folder and the other variations in the subfolder with appropriate scaling factors:
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 imageCopy the code
Next, declare these images in the pubspec.yaml folder:
assets:
- images/my_icon.jpeg
Copy the code
You can access these images with AssetImage:
return AssetImage("images/a_dot_burr.jpeg");
Copy the code
Or use it directly in the Image widget:
@override
Widget build(BuildContext context) {
return Image.asset("images/my_image.png");
}
Copy the code
String resources in a Flutter
For now, the best thing to do is create a class called Strings:
class Strings{
static String welcomeMessage = "Welcome To Flutter";
}
Copy the code
Then in your code, you can access it as if it were your string:
new Text(Strings.welcomeMessage)
Copy the code
Encourage Flutter developers to internationalize and localize using INTL Package
Please stay tuned for the rest of this article because it is too long and will be divided into several parts.