flutter 入门
前提
- 有一定的前端编程基础,不会 dart 语言无所谓的。
- 使用 vscode 开发; 相关插件(Flutter, Awesome Flutter Snippets, flutter-stylizer, Dart, Dart-import)。
- 安装 flutter 安装连接
- 我的 Demo Demo
相关命令
- flutter run; 运行启动 flutter 工程,也可以直接点击 vscode 的调试按钮。
- r/R; 代码更新后输入,更新当前界面。
- flutter pub global activate encrypt 拉取三方库信息
➜ flutter pub global activate encrypt
Resolving dependencies...
+ args 1.5.2
+ asn1lib 0.5.15 (0.6.0 available)
+ charcode 1.1.2
+ clock 1.0.1
+ collection 1.14.12
+ convert 2.1.1
+ crypto 2.1.4
+ encrypt 4.0.0
+ meta 1.1.8
+ pointycastle 1.0.2
+ typed_data 1.1.6
- pubspec.yaml 中填写配置信息
dependencies:
flutter:
sdk: flutter
encrypt: ^4.0.0
- 拉去资源
flutter pub get
基本组件
- Container {类比 div}
- ListView
- GridView
- RowWidget - Row(children:
[]) {Expanded: 灵活布局} - ColumnWidget
- StackWidget - Positioned - Stack {positioned: 类比脱离文档流布局}
- PositionWidget
- CardWidget - Divider {Divider: 分割线组件}
一下是第一个 demo
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
Widget build(BuildContext context) {
return MaterialApp(
title: 'TestWidget',
theme: ThemeData(
primarySwatch: Colors.green,
backgroundColor: Colors.red
),
home: Scaffold(
appBar: AppBar(title: Text("TITLE"),),
body: Center(
child: Container(
child: Image.network(
'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1577960070587&di=d071099dff8fd7fc860a1189b8381470&imgtype=0&src=http%3A%2F%2Fb-ssl.duitang.com%2Fuploads%2Fitem%2F201205%2F01%2F20120501105612_LNEzM.jpeg',
// scale: 2,
color: Colors.lightBlue,
colorBlendMode: BlendMode.lighten,
fit: BoxFit.contain,
repeat: ImageRepeat.repeat,
),
// child: Text(
// "hello my labelddd",
// style: TextStyle(
// fontSize: 40,
// ),
// ),
// alignment: Alignment.center, // 这个属性打开后影响 image fit 属性
width: 800,
height: 200,
// color: Colors.red,
// padding: EdgeInsets.all(30),
// margin: EdgeInsets.fromLTRB(10, 10, 2, 10),
decoration: BoxDecoration(
// color: Colors.green,
gradient: LinearGradient(
colors: [Colors.red, Colors.green, Colors.purple],
),
border: Border.all(width:5, color: Colors.black)
)
),
),
)
);
}
}
ListView
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
title: "myapp",
home: Scaffold(
appBar: AppBar(
title: Text('my title')
),
body: Center(
child: Container(
height: 200.0,
// width: 400.0,
child: ListView(
scrollDirection: Axis.horizontal,
children: <Widget>[
Container(
width: 300,
child: Image.network(
'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1577960070587&di=d071099dff8fd7fc860a1189b8381470&imgtype=0&src=http%3A%2F%2Fb-ssl.duitang.com%2Fuploads%2Fitem%2F201205%2F01%2F20120501105612_LNEzM.jpeg'
),
),
Image.network(
'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1577960070587&di=d071099dff8fd7fc860a1189b8381470&imgtype=0&src=http%3A%2F%2Fb-ssl.duitang.com%2Fuploads%2Fitem%2F201205%2F01%2F20120501105612_LNEzM.jpeg'
),
Image.network(
'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1577960070587&di=d071099dff8fd7fc860a1189b8381470&imgtype=0&src=http%3A%2F%2Fb-ssl.duitang.com%2Fuploads%2Fitem%2F201205%2F01%2F20120501105612_LNEzM.jpeg'
),
Image.network(
'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1577960070587&di=d071099dff8fd7fc860a1189b8381470&imgtype=0&src=http%3A%2F%2Fb-ssl.duitang.com%2Fuploads%2Fitem%2F201205%2F01%2F20120501105612_LNEzM.jpeg'
),
],
),
),
)
),
);
}
}
ListView 分开
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
title: 'home',
home: Scaffold(
appBar: AppBar(title: Text('my title'),),
body: MyList()
)
);
}
}
class MyList extends StatelessWidget {
Widget build(BuildContext context) {
return ListView(
scrollDirection: Axis.horizontal,
children: <Widget>[
Container(
child: Text('kkkkkk'),
),
Container(
child: Text('jjjjjj'),
)
],
);
}
}
ListView 根据数据生成
import 'package:flutter/material.dart';
void main() => runApp(MyApp(
items: List<String>.generate(100, (i) => "Item $i")
));
class MyApp extends StatelessWidget {
final List<String> items;
MyApp({Key key, this.items}):super(key: key);
Widget build(BuildContext context) {
return MaterialApp(
title: 'home',
home: Scaffold(
appBar: AppBar(title: Text('my title'),),
body: MyList(items: items,)
)
);
}
}
class MyList extends StatelessWidget {
final List<String> items;
MyList({Key key, this.items}):super(key: key);
Widget build(BuildContext context) {
return ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return Text('${items[index]}');
},
);
}
}
GridView 两种方式
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
title: 'home',
home: Scaffold(
appBar: AppBar(title: Text('my title'),),
body: MyGrideView0()
)
);
}
}
// the old style to write code of GrideView
class MyGrideView0 extends StatelessWidget {
Widget build(BuildContext context) {
return GridView(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
mainAxisSpacing: 3,
crossAxisSpacing: 3,
childAspectRatio: 0.7, // 宽高比
),
children: <Widget>[
Container(
child: Text('im not strong enough',),
color: Colors.black,
),
Container(
child: Text('i like kungfu',),
color: Colors.black,
),
Container(
child: Text('you are my girlfriend', style: TextStyle(
color: Colors.red
)),
color: Colors.black,
),
Container(
child: Text('everything is not important',),
color: Colors.black,
),
],
);
}
}
class MyGrideView1 extends StatelessWidget {
Widget build(BuildContext context) {
return GridView.count(
padding: EdgeInsets.all(10.0),
crossAxisSpacing: 40,
crossAxisCount: 3, // 几列
children: <Widget>[
Text('im not strong enough'),
Text('i like kungfu'),
Text('i like watch movie'),
Text('i like take vlog'),
Text('i like write blog'),
],
);
}
}
Row
class MyRow extends StatelessWidget {
_change() {
print("this is red button");
}
Widget build(BuildContext context) {
return Row(
children: <Widget>[
Expanded( // Expanded 灵活布局, 平均分配撑满空间
child: Container(
width: 99,
child: Text('data', textAlign: TextAlign.center,),
color: Colors.green,
),
),
Container(
width: 99,
child: Text('data'),
color: Colors.green,
margin: EdgeInsets.only(left: 10),
),
Container(
// width: 99,
child: RaisedButton(
color: Colors.redAccent,
onPressed: () => {
_change()
},
child: Text('red button'),
),
color: Colors.green,
margin: EdgeInsets.only(left: 10),
)
],
);
}
}
Column
class MyColumn extends StatelessWidget {
Widget build(BuildContext context) {
return Container(
color: Colors.green,
width: 200,
child: Column(
children: <Widget>[
Expanded(
child: Container(
color: Colors.red,
child: Text('this is column Widget0this is column Widget0this is column Widget0'),
),
),
Container(
child: Text('this is my footer'),
),
],
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.center,
// acrossAxisAlignment:CrossAxisAlignment.center
),
);
}
}
Stack
class MyStack1 extends StatelessWidget {
var stack = Stack(
alignment: FractionalOffset(0.5, 0.9), // x,y 偏移
children: <Widget>[
CircleAvatar(
backgroundImage: NetworkImage('https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1577960070587&di=d071099dff8fd7fc860a1189b8381470&imgtype=0&src=http%3A%2F%2Fb-ssl.duitang.com%2Fuploads%2Fitem%2F201205%2F01%2F20120501105612_LNEzM.jpeg'),
radius: 100.0,
),
// 类比 web 脱离文档流布局
Positioned(
// top: 10,
bottom: 10,
left: 10,
child: Text('THIS IS MY BOOK'),
)
],
);
Widget build(BuildContext context) {
return Center(
child: stack,
);
}
}
class MyStack0 extends StatelessWidget {
var stack = Stack(
alignment: FractionalOffset(0.5, 0.9), // x,y 偏移
children: <Widget>[
CircleAvatar(
backgroundImage: NetworkImage('https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1577960070587&di=d071099dff8fd7fc860a1189b8381470&imgtype=0&src=http%3A%2F%2Fb-ssl.duitang.com%2Fuploads%2Fitem%2F201205%2F01%2F20120501105612_LNEzM.jpeg'),
radius: 100.0,
),
Container(
decoration: BoxDecoration(
color: Colors.lightBlueAccent
),
padding: EdgeInsets.all(5.0),
child: Text('title', style: TextStyle(color: Colors.black),),
)
],
);
Widget build(BuildContext context) {
return Center(
child: stack,
);
}
}
CardWidget
class MyCard extends StatelessWidget {
var card = Card(
child: Column(
children: <Widget>[
ListTile(
title: Text('AN HUI PROVENCE LUAN CITY', style: TextStyle(
fontWeight: FontWeight.w500
),
),
subtitle: Text('AN HUI PROVENCE LUAN CITY', style: TextStyle(
fontWeight: FontWeight.w200
),
),
leading: Image.network('https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1577960070587&di=d071099dff8fd7fc860a1189b8381470&imgtype=0&src=http%3A%2F%2Fb-ssl.duitang.com%2Fuploads%2Fitem%2F201205%2F01%2F20120501105612_LNEzM.jpeg'),
),
Divider(), // 分割线组件
ListTile(
title: Text('AN HUI IS A PLACE OF MY BORN', style: TextStyle(
fontWeight: FontWeight.w500
),
),
subtitle: Text('AN HUI PROVENCE LUAN CITY', style: TextStyle(
fontWeight: FontWeight.w200
),
),
leading: Image.network('https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1577960070587&di=d071099dff8fd7fc860a1189b8381470&imgtype=0&src=http%3A%2F%2Fb-ssl.duitang.com%2Fuploads%2Fitem%2F201205%2F01%2F20120501105612_LNEzM.jpeg'),
),
ListTile(
title: Text('AN HUI PROVENCE LUAN CITY', style: TextStyle(
fontWeight: FontWeight.w500
),
),
subtitle: Text('AN HUI PROVENCE LUAN CITY', style: TextStyle(
fontWeight: FontWeight.w200
),
),
leading: Image.network('https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1577960070587&di=d071099dff8fd7fc860a1189b8381470&imgtype=0&src=http%3A%2F%2Fb-ssl.duitang.com%2Fuploads%2Fitem%2F201205%2F01%2F20120501105612_LNEzM.jpeg'),
)
],
),
);
Widget build(BuildContext context) {
return card;
}
}
导航
- 跳转和返回
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home: MyApp() ,
),
);
}
class MyApp extends StatelessWidget {
BuildContext _context;
Widget build(BuildContext context) {
return MaterialApp(
title: 'home',
home: Scaffold(
appBar: AppBar(title: Text('FIRST PAGE'),),
body: ListView(
children: <Widget>[
Builder( // 注意:跳转要用 builder 包装一下,通过 context 才可以跳转
builder: (context) => RaisedButton(
onPressed: () => {
// print("object$context")
Navigator.of(context).pushNamed('/settings')
// Navigator.push(context, new MaterialPageRoute(
// builder: (context) => new MyApp1()
// ))
},
child: Text('CLICK ME TO OPEN OTHER PAGE 1'),
),
),
RaisedButton(
onPressed: () => {
Navigator.of(_context).pushNamed('/otherpage')
},
child: Text('CLICK ME TO OPEN OTHER PAGE 2'),
),
],
)
),
routes: <String, WidgetBuilder>{
'/otherpage': (BuildContext context) => new MyApp1(),
},
);
}
}
class MyApp1 extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
title: 'home',
home:Scaffold(
appBar: AppBar(title: Text('Second PAGE'),),
body: Center(
child: ListView(
children: <Widget>[
Text('this is my second page'),
RaisedButton(
child: Text('GO BACK'),
onPressed: () => {
// print('go back!!')
Navigator.pop(context)
// Navigator.of(context).pop()
},
)
],
),
)));
}
}
跳转传参,返回传参
- 正向传参: 直接在初始化的过程中复制
- 反向传值: 可以通过将本地的 function 当参数传递的方式,进行数据回调。
- 反向传值(async, await): 通过返回界面直接返回数据
- State: 状态机,返回修改界面中的数据;(这个状态机居然也要把 界面写进去,个人感觉还是 React 的逻辑比较好
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home: MyApp() ,
),
);
}
class Productj {
final String title;
final String description;
Productj(this.title, this.description);
}
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
title: 'home',
home: MyApp0(),
/// 可以使用 路由提前定义跳转
routes: <String, WidgetBuilder>{
'/otherpage': (BuildContext context) => MyApp1(params: Productj('title', 'description')),
},
);
}
}
class _MyApp0State extends State<MyApp0> with TickerProviderStateMixin {
String callback = '';
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('FIRST PAGE'),),
body: ListView(
children: <Widget>[
Text('${callback}'),
Builder( // 注意:跳转要用 builder 包装一下,通过 context 才可以跳转
builder: (context) => RaisedButton(
onPressed: () => {
// this._naviagtionTo(context)
this._navigationToj(context)
},
child: Text('CLICK ME TO OPEN OTHER PAGE 1'),
),
),
],
)
);
}
_navigationToj(BuildContext context) async{
final result = await Navigator.push(context, new MaterialPageRoute(
builder: (context) => MyApp1(params: Productj('title', 'description'), f: this._test)
));
Scaffold.of(context).showSnackBar(SnackBar(content: Text("${result} 哈哈哈", textAlign: TextAlign.center,),));
if (this.callback.length > 0) {
this.callback = '';
} else {
this.callback = result;
}
}
_naviagtionTo(BuildContext context) async{
final result = await Navigator.of(context).pushNamed('/otherpage');
Scaffold.of(context).showSnackBar(SnackBar(content: Text("$result", textAlign: TextAlign.center,),));
if (this.callback.length > 0) {
this.callback = '';
// setState(() {
// callback
// });
} else {
this.callback = result;
}
}
_test (String s) {
print('object' + s);
// this.callback = s;
}
}
class MyApp0 extends StatefulWidget {
_MyApp0State createState() => _MyApp0State();
}
class MyApp1 extends StatelessWidget {
final Productj params;
final Function(String s) f; // function 可以当参数传递
_t (BuildContext context) {
this.f('kkk');
Navigator.pop(context, '给你一个小姐姐');
}
MyApp1({Key key, this.params, this.f}):super(key: key);
Widget build(BuildContext context) {
return MaterialApp(
title: 'home',
home:Scaffold(
appBar: AppBar(title: Text('Second PAGE'),),
body: Center(
child: ListView(
children: <Widget>[
Text('this is my second page' + this.params.description),
RaisedButton(
child: Text('GO BACK'),
onPressed: () => {
this._t(context)
// print('go back!!')
// Navigator.pop(context)
// Navigator.of(context).pop()
},
)
],
),
)));
}
}
本地图片加载
- pubspec.yaml 文件配置自己的图片
assets:
- images/a.png
- 代码写法
class MyImageApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
title: 'home',
home: Scaffold(
appBar: AppBar(title: Text('LOCAL IMAGE PAGE'),),
body: Center(
child: Image.asset('images/a.png'),
)
),
);
}
}