Flutter从零到∞学习笔记

  • 有状态widget:StatefulWidget和无状态widget:StatelessWidget 前者不需要实现Widget build(BuildContext context)。

    具体的选择取决于widget是否需要管理一些状态

  • 在Dart语言中使用下划线前缀标识符,会强制其变成私有的。

  • Icons.favorite Icons类里面有很多默认图标

  • isOdd 是否奇数 2.isOdd -> false 1.isOdd -> true

  • pushSaved “”开头的自动转成私有(方法和变量)

  • 导航栏添加按钮和事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@override
 
Widget build(BuildContext context) {
 
  return new Scaffold(
 
    appBar: new AppBar(
 
      title: new Text('Startup Name Generator'),
 
      actions: <Widget>[
 
        // AppBar 添加一个按钮 样式为list 事件是_pushSaved
 
        new IconButton(icon: new Icon(Icons.list), onPressed: _pushSaved)
 
      ],
 
    ),
 
    body: _buildSuggestions(),
 
  );
 
}
 
// tooltip 长时间按下的提示文字
 
IconButton(icon: new Icon(Icons.search), tooltip: 'Search', onPressed: null)

  

 

  1. 界面跳转方法
1
2
3
4
5
6
7
8
9
10
11
Navigator.of(context).push(
 
  new MaterialPageRoute(
 
      builder: (context) {
 
      },
 
  ),
 
);

  

 

  1. 一行函数写法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 多行
 
void main() {
 
  runApp(
 
      new Center(
 
        child: new Text(
 
          'Hello, world!',
 
          textDirection: TextDirection.ltr,
 
        ),
 
      )
 
  )
 
}
 
// 一行
 
void main() => runApp(new MyApp());

  

  1. // Material 是UI呈现的“一张纸”

  2. 请确保在pubspec.yaml文件中,将flutter的值设置为:uses-material-design: true。这允许我们可以使用一组预定义Material icons。

  3. Row(横向排列)和Column(纵向排列)

1
2
3
4
5
6
7
8
9
10
11
12
13
child: new Row(
 
  children: <Widget>[
 
    new ...,
 
    new ...,
 
    new ...,
 
  ],
 
)

  

1
2
3
4
5
6
7
8
9
10
11
12
13
child: new Column(
 
  children: <Widget>[
 
    new ...,
 
    new ...,
 
    new ...,
 
  ],
 
),

  

  1. cached_network_image 图片占位和淡入淡出

  2. push

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Navigator.push(
 
  context,
 
  new MaterialPageRoute(builder: (context) => new 新界面),
 
);
 
// 如果需要传值:
 
新界面({Key key, @required this.接收字段的名字}) : super(key: key);
 
pop
 
Navigator.pop(context);

  

  1. dio网络请求 https://github.com/flutterchina/dio

  2. import 'dart:convert'; // package将响应内容转化为一个json Map

  3. // 使用fromJson工厂函数,将json Map 转化为一个Post对象

1
new Post.fromJson(json);

  

  1. future参数是一个异步的网络请求

  2. import 'dart:io'; // 添加请求的headers

  3. // 长连接

1
2
3
import 'package:web_socket_channel/io.dart';
 
import 'package:multi_server_socket/multi_server_socket.dart';

  

  1. // 网络请求
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
Future<Post> fetchPost() async {
 
  final response = await http.get('[http://jsonplaceholder.typicode.com/posts/1](http://jsonplaceholder.typicode.com/posts/1)');
 
  final responseJson = json.decode(response.body);
 
  return new Post.fromJson(responseJson);
 
}
 
// 请求添加headers
 
/*
 
Future<Post> fetchPost() async {
 
  final response = await http.get(
 
    '[https://jsonplaceholder.typicode.com/posts/1](https://jsonplaceholder.typicode.com/posts/1)',
 
    headers: {HttpHeaders.AUTHORIZATION: "Basic your_api_token_here"},
 
  );
 
  final json = jsonDecode(response.body);
 
  return new Post.fromJson(json);
 
}
 
*/
 
new FutureBuilder<Post>(
 
  future: fetchPost(),
 
  builder: (context, snapshot) {
 
    return new CircularProgressIndicator();
 
  }
 
)

  

 

  1. 长连接
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 连接长连接
 
IOWebSocketChannel.connect('[ws://echo](ws://echo/).[websocket.org](http://websocket.org/)’)
 
// 接收消息
 
new StreamBuilder(
 
    stream: widget.channel.stream,
 
    builder: (context, snapshot) {
 
      return new Padding(
 
        child: new Text(snapshot.hasData ? '${snapshot.data}' : ''),
 
          padding: const EdgeInsets.symmetric(vertical: 20.0)
 
      );
 
    }
 
)
 
// 发送消息
 
widget.channel.sink.add(_textController.text);
 
// 关闭长连接
 
widget.channel.sink.close();

  

 

  1. 在Flutter中添加资源和图片

https://flutterchina.club/assets-and-images/

  1. 标准widget:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Container
 
添加 padding, margins, borders, background color, 或将其他装饰添加到widget.
 
GridView
 
将 widgets 排列为可滚动的网格.
 
ListView
 
将widget排列为可滚动列表
 
Stack
 
将widget重叠在另一个widget之上.
 
Material Components:
 
Card
 
将相关内容放到带圆角和投影的盒子中。
 
ListTile
 
将最多3行文字,以及可选的行前和和行尾的图标排成一行

  

  1. pubspec.yaml中添加字体 注意缩进对齐 注意缩进对齐 注意缩进对齐
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
-asset 路径是与pubspec.yaml平级的文件路径
 
flutter:
 
  # Include the Material Design fonts.
 
  uses-material-design: true
 
  fonts:
 
    - family: Rock Salt
 
      fonts:
 
        # [https://fonts.google.com/specimen/Rock+Salt](https://fonts.google.com/specimen/Rock+Salt)
 
      - asset: fonts/Arial-Unicode.ttf
 
    - family: VT323
 
      fonts:
 
        # [https://fonts.google.com/specimen/VT323](https://fonts.google.com/specimen/VT323)
 
        - asset: fonts/Arial-Unicode.ttf
 
    - family: Ewert
 
      fonts:
 
        # [https://fonts.google.com/specimen/Ewert](https://fonts.google.com/specimen/Ewert)
 
        - asset: fonts/Ewert-Regular.ttf

  

  1. 比如一个关闭按钮在
1
2
3
4
5
6
7
new Row(mainAxisAlignment: MainAxisAlignment.end, children: <Widget>[
 
  new FlatButton(onPressed: () {
 
  }, child: Icon(Icons.close))
 
],);

  

  1. 分割线
new Divider(color: Colors.lightBlue,) 


  1. 自定义Icon
new Image.asset(“图片路径", width: 20.0, height: 20.0,)


  1. 按钮宽高
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
001
 
new Padding(padding: new EdgeInsets.fromLTRB(48.0, 20.0, 48.0, 20.0),
 
  child: new Row(
 
    children: <Widget>[
 
      new Expanded(child:
 
        new RaisedButton(onPressed: (){
 
        },
 
          //设置控件的高度
 
          child: new Padding(padding: new EdgeInsets.fromLTRB(0.0, 10.0, 0.0, 10.0),
 
            child: new Text("登录",
 
              style: TextStyle(color: Colors.white)
 
            ),
 
          ),
 
          color: Colors.brown,
 
        ),
 
      ),
 
    ],
 
  ),
 
),
 
002
 
new Container(
 
  width: MediaQuery.of(context).size.width - 48 * 2 ,
 
  padding: new EdgeInsets.only(top: 40.0),
 
  child: new RaisedButton(onPressed: (){
 
  },
 
    //设置控件的高度
 
    child: new Padding(padding: new EdgeInsets.fromLTRB(0.0, 10.0, 0.0, 10.0),
 
      child: new Text("登录",
 
          style: TextStyle(color: Colors.white)
 
      ),
 
    ),
 
    color: Colors.brown,
 
  ),
 
),
 
003
 
Widget _bigButton(String text, double lSpace, double rSpace) {
 
  return new Container(
 
    width: MediaQuery.of(context).size.width - lSpace - rSpace,
 
    height: 48.0,
 
    margin: new EdgeInsets.only(left: lSpace, right: rSpace),
 
    color: Colors.white54,
 
    padding: new EdgeInsets.only(top: 0.0),
 
    child: new RaisedButton(onPressed: (){
 
      print(text);
 
    },
 
      child: new Padding(padding: new EdgeInsets.fromLTRB(0.0, 0.0, 0.0, 0.0),
 
        child: new Text(text,
 
            style: TextStyle(color: Colors.white)
 
        ),
 
      ),
 
      color: Colors.brown,
 
    ),
 
  );
 
}

  

 

  1. 设备尺寸
1
MediaQuery.of(context).size.width

  

  1. 设备像素密度
1
MediaQuery.of(context).devicePixelRatio

  

  1. 状态栏高度
1
MediaQuery.of(context).padding.top

  

  1. 担心键盘挡住控件,可以使用 SingleChildScrollView,将SingleChildScrollView当做容器。

  2. 一个超级简单界面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import 'package:flutter/material.dart';
 
class RegisterPage extends StatelessWidget {
 
  @override
 
  Widget build(BuildContext context) {
 
    return new Scaffold(
 
      backgroundColor: Colors.black,
 
      body: new RegisterWidget(),
 
    );
 
  }
 
}
 
class RegisterWidget extends StatefulWidget {
 
  RegisterWidgetState createState() => RegisterWidgetState();
 
}
 
class RegisterWidgetState extends State<RegisterWidget> {
 
  @override
 
  Widget build(BuildContext context) {
 
    return new Text("RegisterPage", style: TextStyle(color: Colors.white),);
 
  }
 
}

  

  1. Flutter 按钮总结
1
2
3
4
5
6
7
· InkWell   // 纯文字按钮
 
· OutLineButton   // 边框按钮
 
· IconButton  // icon按钮
 
·

  

  1. import 'package:flutter/services.dart';
1
2
3
4
5
6
7
TextField
 
inputFormatters: <TextInputFormatter> [
 
  WhitelistingTextInputFormatter.digitsOnly,
 
],

  

 37 . 验证码按钮

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
new Positioned(
 
    child: new Container(
 
      width: 80.0,
 
      height: 27.0,
 
      alignment: Alignment.center,
 
      decoration: new BoxDecoration(
 
        border: new Border.all(
 
          color: Colors.white,
 
          width: 1.0,
 
        ),
 
        borderRadius: new BorderRadius.circular(4.0),
 
      ),
 
      child: InkWell(
 
        child: _mText(_verifyStr, 12.0),
 
        onTap: () {
 
        },
 
      ),
 
    )
 
),

  

  1. 倒计时方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
@override
 
void dispose() {
 
  super.dispose();
 
  _cancelTimer();
 
}
 
_startTimer() {
 
  if (_verifyStr == '重新发送' || _verifyStr == '获取验证码') {
 
    _seconds = 5;
 
    _timer = new Timer.periodic(new Duration(seconds: 1), (timer) {
 
      if (_seconds == 0) {
 
        _cancelTimer();
 
        return;
 
      }
 
      _seconds--;
 
      _verifyStr = '$_seconds(s)';
 
      setState(() {});
 
      if (_seconds == 0) {
 
        _verifyStr = '重新发送';
 
      }
 
    });
 
  }
 
}
 
_cancelTimer() {
 
  _timer?.cancel();
 
}

  

 

  1. 富文本拼接: 协议
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
Widget _protocolWidget() {
 
  return new Container(
 
    child: new Row(
 
      children: <Widget>[
 
        new GestureDetector(
 
          onTap: () {
 
            print("选择");
 
          },
 
          child: Icon(Icons.add_alert, color: Colors.white),
 
        ),
 
        new Text.rich(
 
            new TextSpan(
 
                text: '我已阅读并同意',
 
                style: new TextStyle(
 
                  fontSize: 12.0,
 
                  color: Colors.grey[500],
 
                  fontWeight: FontWeight.w400,
 
                ),
 
                children: [
 
                  new TextSpan(
 
                    recognizer: new TapGestureRecognizer()
 
                      ..onTap = () {
 
                        print("《燎原用户服务协议》");
 
                      },
 
                    text: "《燎原用户服务协议》",
 
                    style: new TextStyle(
 
                      fontSize: 14.0,
 
                      color: Color(0XFFB57A36),
 
                      fontWeight: FontWeight.w400,
 
                    ),
 
                  )
 
                ]
 
            )
 
        ),
 
      ],
 
    )
 
  );
 
}

  

  1. 阴影、圆角
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
new Card(
 
  elevation: 4.0,
 
  shape: new RoundedRectangleBorder(
 
    borderRadius: BorderRadius.only(
 
      topLeft: Radius.circular(16.0),
 
      topRight: Radius.circular(16.0),
 
      bottomLeft: Radius.circular(12.0),
 
      bottomRight: Radius.circular(2.0),
 
    )
 
  ),
 
  child: new IconButton(icon: Icon(Icons.add), onPressed: () {
 
  }),
 
)

  

  1. YYTabbarWidget
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
import 'package:flutter/material.dart';
 
// with AutomaticKeepAliveClientMixin
 
class YYTabbarWidget extends StatefulWidget {
 
  List<Widget> tabItems = [];
 
  Widget title;
 
  List<Widget> tabViews = [];
 
  PageController pageController;
 
  final ValueChanged<int> onPageChanged;
 
  final Widget drawer;
 
  YYTabbarWidget({Key key,
 
    this.drawer,
 
    this.tabItems,
 
    this.title,
 
    this.tabViews,
 
    this.pageController,
 
    this.onPageChanged,
 
  }) : super(key: key);
 
  _YYTabbarWidgetState createState() => _YYTabbarWidgetState(drawer, title, tabItems, tabViews, pageController, onPageChanged);
 
}
 
class _YYTabbarWidgetState extends State<YYTabbarWidget> with SingleTickerProviderStateMixin {
 
  final Widget _title;
 
  final List<Widget> _tabViews;
 
  final List<Widget> _tabItems;
 
  final ValueChanged<int> _onPageChanged;
 
  final Widget _drawer;
 
  _YYTabbarWidgetState(
 
      this._drawer,
 
      this._title,
 
      this._tabItems,
 
      this._tabViews,
 
      this._pageController,
 
      this._onPageChanged,
 
      ) : super();
 
  TabController _tabController;
 
  PageController _pageController;
 
  @override
 
  void initState() {
 
    super.initState();
 
    _tabController = new TabController(length: _tabItems.length, vsync: this);
 
  }
 
  @override
 
  void dispose() {
 
    _tabController.dispose();
 
    super.dispose();
 
  }
 
  _renderTab() {
 
    print(_tabItems);
 
    List<Widget> list = new List();
 
    for (int i = 0; i < _tabItems.length; i++) {
 
      list.add(new FlatButton(onPressed: () {
 
        print(i);
 
        _pageController.jumpTo(MediaQuery
 
            .of(context)
 
            .size
 
            .width * i);
 
      }, child: _tabItems[I],
 
      )
 
      );
 
    }
 
    return list;
 
  }
 
  @override
 
  Widget build(BuildContext context) {
 
    return new Scaffold(
 
      drawer: _drawer,
 
      appBar: new AppBar(
 
        title: _title,
 
      ),
 
      body: new PageView(
 
        controller: _pageController,
 
        children: _tabViews,
 
        onPageChanged: (index) {
 
          _tabController.animateTo(index);
 
          _onPageChanged?.call(index);
 
        },
 
    ),
 
      bottomNavigationBar: new Material(
 
        color: Colors.white,
 
        child: new TabBar(
 
          indicatorPadding: new EdgeInsets.only(top: 0.0),
 
          controller: _tabController,
 
          tabs: _renderTab(),
 
          indicatorColor: Colors.red,
 
        ),
 
      ),
 
    );
 
  }
 
}

  

 

  1. ListView 添加刷新,当数量少的时候不能滚动
1
physics: new AlwaysScrollableScrollPhysics(), // 让ListView一直可以滚动

  

  1. tabView切换 子界面都会调用initState
1
2
3
4
5
6
7
8
9
解决:AutomaticKeepAliveClientMixin
 
class HomePageState extends State<HomePage> with AutomaticKeepAliveClientMixin {
 
    @override
 
    bool get wantKeepAlive => true;
 
}

  

 

  1. 路有跳转
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
///不带参数的路由表跳转
 
Navigator.pushNamed(context,routeName);
 
///跳转新页面并且替换,比如登录页跳转主页
 
Navigator.pushReplacementNamed(context,routeName);
 
///跳转到新的路由,并且关闭给定路由的之前的所有页面
 
Navigator.pushNamedAndRemoveUntil(context,'/calendar',ModalRoute.withName('/'));
 
///带参数的路由跳转,并且监听返回
 
Navigator.push(context,newMaterialPageRoute(builder:(context)=>newNotifyPage())).then((res){
 
      ///获取返回处理
 
    });

  

 

  1. flutter lib
1
2
3
4
5
cupertino_icons: ^0.1.2  #icon
 
flutter_spinkit: "^2.1.0"  # load more loading  import 'package:flutter_spinkit/flutter_spinkit.dart';
 
dio: x.x.x  #无网络请求  import 'package:dio/dio.dart';

  

 

  1. dio网络请求示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
_dioRequest() async {
 
  Dio dio = new Dio();
 
  Response response;
 
  try {
 
    String url;
 
    var params; // 请求参数
 
    Options options; // 配置:超时,请求头,请求类型等
 
    response = await dio.request(url, data: params, options: options);
 
  } on DioError catch(e) {
 
    // 请求出错时,返回一个DioError对象
 
  }
 
}

  

 

  1. build_runner的使用
1
2
3
4
5
6
7
8
9
1、在根目录运行
 
2、一次性创建.g.dart文件 使用build 此时目录内不能有.g.dart文件
 
3、watch是监听 有model类的文件创建 自动创建.g.dart文件
 
flutter packages pub run build_runner build
 
flutter packages pub run build_runner watch

  



 

posted @   CrossPython  阅读(546)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示