Flutter For Dummies Cheat Sheet
Tài liệu ngắn gọn về framework Flutter
A “Hello World” Dart Program
main() => print('Hello World');
A “Hello World” Flutter Program
import 'package:flutter/material.dart';
main() => runApp(HelloApp());
class HelloApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
home: Material(
child: Text("Hello world!"),
),
);
}
}
A Stateless Widget
import 'package:flutter/material.dart';
class Greeter extends StatelessWidget {
Greeter({Key key @required this.name}) : super(key: key);
final String name;
@override
Widget build(BuildContext context) {
return Container(
child: Text('Hello, $name'),
);
}
}
A Stateful Widget
import 'package:flutter/material.dart';
class WidgetWithState extends StatefulWidget {
@override
_WidgetWithStateState createState() => _WidgetWithStateState();
}
class _WidgetWithStateState extends State<WidgetWithState> {
int counter = 0;
increment() {
setState(() {
counter++;
});
}
decrement() {
setState(() {
counter--;
});
}
@override
Widget build(BuildContext context) {
return Row(
children: <Widget>[
FlatButton(onPressed: increment, child: Text('Increment')),
FlatButton(onPressed: decrement, child: Text('Decrement')),
Text(counter.toString()),
],
);
}
}
A Simple Scaffold
Scaffold(
appBar: AppBar(
title: Text("I'm aan AppBar."),
),
body: Center(
child: Text("I'm a Text widget."),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.ac_unit),
),
drawer: Drawer(
child: Center(child: Text("I'm a drawer.")),
),
)
A Cupertino App
import 'package:flutter/cupertino.dart';
void main() => runApp(CupterinoApp());
class CupterinoApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return CupertinoApp(
home: CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
backgroundColor: Color.fromRGBO(66, 165, 245, 1.0),
middle: Text("I'm a navigation bar"),
),
child: Center(
child: Text('Hello from Cupertino, Californa!'),
),
),
);
}
}
A Column
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text("I'm on top."),
Text("I'm in the middle."),
Text("I'm the bottom."),
],
)
Responding to a Button Press
import 'package:flutter/material.dart';
void main() => runApp(ButtonDemo());
class ButtonDemo extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State {
String _whatToDisplay;
void initState() {
_whatToDisplay = 'Click Me';
}
void _doSomething() {
setState(() {
_whatToDisplay = 'Thank you for clicking';
});
}
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: RaisedButton(
child: Text(_whatToDisplay),
onPressed: _doSomething,
),
),
);
}
}
Some Useful Layout Widgets
Material(
child: SafeArea(
child: Column(
children: [
Expanded(
child: Container(
height: 50.0,
color: Colors.blue,
),
),
SizedBox(
height: 50.0,
),
Container(
alignment: Alignment.bottomRight,
height: 100.0,
color: Colors.blue,
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Text(
'Hello',
style: TextStyle(backgroundColor: Colors.red),
),
),
),
],
),
),
)
A Text Field
class _MyHomePageState extends State {
final _myController = TextEditingController();
@override
void dispose() {
_myController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Material(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextField(
decoration: InputDecoration(labelText: "Type something:"),
controller: _myController,
),
RaisedButton(
child: Text("UPPERCASE"),
onPressed: () =>
_myController.text = _myController.text.toUpperCase(),
),
],
),
),
);
}
}
A Slider
class _MyHomePageState extends State {
double _sliderValue = 1.0;
void _refreshSlider(double newValue) {
setState(() {
_sliderValue = newValue;
});
}
@override
Widget build(BuildContext context) {
return Material(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(_sliderValue.toStringAsFixed(2)),
Slider(
value: _sliderValue,
onChanged: _refreshSlider,
min: 1.0,
max: 10.0,
)
],
),
),
);
}
}
Radio Buttons
class _MyHomePageState extends State {
int _radioValue;
void _refreshRadio(int newValue) {
setState(() {
_radioValue = newValue;
});
}
@override
Widget build(BuildContext context) {
return Material(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(_radioValue?.toString() ?? 'Select One'),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('0'),
Radio(
value: 0,
groupValue: _radioValue,
onChanged: _refreshRadio),
Text('1'),
Radio(
value: 1,
groupValue: _radioValue,
onChanged: _refreshRadio),
Text('2'),
Radio(
value: 2,
groupValue: _radioValue,
onChanged: _refreshRadio,
)
],
),
],
),
),
);
}
}
Basic Navigation
class FirstPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Material(
child: Center(
child: RaisedButton(
child: Text('Go to second page'),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SecondPage(),
),
);
},
),
),
);
}
}
class SecondPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Material(
child: Center(
child: RaisedButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('Go back!'),
),
),
);
}
}
A List
List movieName = [
"Casablanca",
"Citizen Kane",
"Lawrence of Arabia",
];
ListView.builder(
itemCount: movieName.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(movieName[index]),
onTap: () => _goToDetailPage(movieName[index]));
},
)
Animation
class MyHomePageState extends State
with SingleTickerProviderStateMixin {
Animation animation;
AnimationController controller;
@override
void initState() {
super.initState();
controller =
AnimationController(duration: const Duration(seconds: 3), vsync: this);
animation = Tween(begin: 100.0, end: 500.0).animate(controller)
..addListener(() {
setState(() {});
});
controller.forward();
}
@override
Widget build(BuildContext context) {
return Material(
child: Stack(
children: [
Positioned(
left: 150.0,
top: animation.value,
child: Icon(
Icons.music_note,
size: 70.0,
),
),
],
),
);
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
}
Trick and Tips
Lock Orientation
import 'package:flutter/services.dart';
void main() async {
await SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
]);
runApp(App());
}
Hide Status Bar
import 'package:flutter/services.dart';
void main() {
SystemChrome.setEnabledSystemUIOverlays([]);
}
Check Platform
import 'dart:io' show Platform;
if (Platform.isIOS) {
doSmthIOSSpecific();
}
if (Platform.isAndroid) {
doSmthAndroidSpecific();
}
Data Types
List/Array
final length = items.length;
final newItems = items..addAll(otherItems);
final allEven = items.every((item) => item % 2 == 0);
final filled = List<int>.filled(3, 42);
final even = items.where((n) => n % 2 == 0).toList();
final found = items.firstWhere((item) => item.id == 42);
final index = items.indexWhere((item) => item.id == 42);
final flat = items.expand((_) => _).toList();
final mapped = items.expand((item) => [item + 1]).toList();
items.forEach((item) => print(item));
items.asMap().forEach((index, item) => print('$item, $index'));
final includes = items.contains(42);
final indexOf = items.indexOf(42);
final joined = items.join(',');
final newItems = items.map((item) => item + 1).toList();
final item = items.removeLast();
items.add(42);
final reduced = items.fold({}, (acc, item) {
acc[item.id] = item;
return acc;
});
final reversed = items.reversed;
items.removeAt(0);
final slice = items.sublist(15, 42);
final hasOdd = items.any((item) => item % 2 == 0);
items.sort((a, b) => a - b);
items.replaceRange(15, 42, [1, 2, 3]);
items.insert(0, 42);
Class
Singleton
class Singleton {
static Singleton _instance;
final int prop;
factory Singleton() =>
_instance ??= new Singleton._internal();
Singleton._internal()
: prop = 42;
}
Json
import 'dart:convert' show json;
json.decode(someString);
json.encode(encodableObject);
json.decode
returns a dynamic
type, which is probably not very useful
You should describe each entity as a Dart class with fromJson
and toJson
methods
class User {
String displayName;
String photoUrl;
User({this.displayName, this.photoUrl});
User.fromJson(Map<String, dynamic> json)
: displayName = json['displayName'],
photoUrl = json['photoUrl'];
Map<String, dynamic> toJson() {
return {
'displayName': displayName,
'photoUrl': photoUrl,
};
}
}
final user = User.fromJson(json.decode(jsonString));
json.encode(user.toJson());
However this approach is error-prone (e.g. you can forget to update map key after class field was renamed), so you can use json_serializable
as an alternative
Add json_annotation
, build_runner
and json_serializable
to dependencies
dependencies:
json_annotation: ^2.0.0
dev_dependencies:
build_runner: ^1.0.0
json_serializable: ^2.0.0
Update your code
import 'package:json_annotation/json_annotation.dart';
part 'user.g.dart';
@JsonSerializable()
class User {
String displayName;
String photoUrl;
User({this.displayName this.photoUrl});
// _$UserFromJson is generated and available in user.g.dart
factory User.fromJson(Map<String, dynamic> json) {
return _$UserFromJson(json);
}
// _$UserToJson is generated and available in user.g.dart
Map<String, dynamic> toJson() => _$UserToJson(this);
}
final user = User.fromJson(json.decode(jsonString));
json.encode(user); // toJson is called by encode
Run flutter packages pub run build_runner build
to generate serialization/deserialization code
To watch for changes run flutter packages pub run build_runner watch
Để thảo luận về các vấn đề trong bài viết này, mời các bạn tham gia nhóm facebook https://fb.com/groups/divindev/