flutter 一些技巧
[toc]
局部设置明暗主题
多设备启动
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
|
{
// 使用 IntelliSense 了解相关属性。
// 悬停以查看现有属性的描述。
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Current Device", // 设备名
"request": "launch", // 操作
"type": "dart", // 语言类型
"program": "lib/main_dev.dart" // 入口
},
{
"name": "Android",
"request": "launch",
"type": "dart",
"deviceId": "android",
"program": "lib/main_dev.dart" // 入口
},
{
"name": "iPhone",
"request": "launch",
"type": "dart",
"deviceId": "iPhone"
}
],
"compounds": [
{
"name": "All Devices",
"configurations": ["Android", "iPhone"]
}
]
}
|
ListView 嵌套 ListView
1
2
|
shrinkWrap: true, //解决无限高度问题
physics: new NeverScrollableScrollPhysics(), //禁用滑动事件
|
刷新效果 , 即转圈动画
背景透明的路由
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
Navigator.of(context).push(
PageRouteBuilder(
opaque:false,
pageBuilder: (context, animation, secondaryAnimation) {
return Scaffold(
backgroundColor: Colors.transparent,
body: SafeArea(
child: Stack(
children: <Widget>[
//...
],
),
)
);
}
));
|
屏幕适配
参考 https://github.com/jiang111/flutter_code/blob/master/lib/ui_4/home_page.dart
全局坐标转换局部坐标
1
2
|
RenderBox box = context.findRenderObject();
_tapPos = box.globalToLocal(details.globalPosition);
|
强制竖屏
1
2
3
|
// 强制竖屏
// SystemChrome.setPreferredOrientations(
// [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]);
|
网络请求处理
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
|
return Center(
child: FutureBuilder<dynamic>(
future: CommentApi.getCommentList(
elem["id"], 10, 0), // a previously-obtained Future<String> or null
builder: (BuildContext context, AsyncSnapshot snapshot) {
switch (snapshot.connectionState) {
// 未执行
case ConnectionState.none:
// 连接到异步操作
return Text('Press button to start.');
case ConnectionState.active:
// 请求中
case ConnectionState.waiting:
// // 请求未结束,显示loading
return Text("");
// return CircularProgressIndicator();
case ConnectionState.done:
// 请求完成
if (snapshot.hasError) return Text('Error: ${snapshot.error}');
List list = snapshot.data as List;
return Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: comment(context, list),
);
}
return null; // unreachable
},
));
|
时间格式化
1
2
3
4
5
|
import 'package:intl/intl.dart'
var _formatter = new DateFormat('yyyy-MM-dd');
var _createTime = _formatter.format(DateTime.parse(elem["create_time"]));
|
渐变色
1
2
3
4
5
6
7
8
|
Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Color(0xFFfbab66), Color(0xFFf7418c)],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
)),
);
|
圆形头像
1
2
3
4
|
CircleAvatar(
maxRadius: 15,
backgroundImage: NetworkImage(_icon),
),
|
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
|
LikeButton(
onTap: (bool flag) {
return onLikeButtonTap(flag, _id);
},
isLiked: _likes,
size: 18,
likeCount: _count,
countPostion: CountPostion.left,
likeCountPadding: EdgeInsets.only(right: 5),
likeBuilder: (bool flag) {
return Image(
image: AssetImage("images/like.png"),
height: 18,
color: flag
? Colors.redAccent
: Colors.grey[600],
);
},
),
Future<bool> onLikeButtonTap(bool isLiked, String id) {
if (isLiked != true) {
// send your request here
CommentApi.putLike(id).then((value) {
if (value.statusCode != 200) {
message("网络异常,请稍后再试");
isLiked = isLiked;
} else {
isLiked = true;
}
});
}
final Completer<bool> completer = new Completer<bool>();
Timer(const Duration(milliseconds: 200), () {
// if your request is failed,return null,
completer.complete(isLiked);
});
return completer.future;
}
|
图片上传
https://www.jianshu.com/p/b582daddd737
http://47.105.149.100/web/flutter-cai-kang-ri-ji-chi-xu-geng-xin-
点击可修改的属性
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
|
Container(
height: 25,
width: 100,
alignment: Alignment.centerLeft,
child: TextField(
onTap: () {
if (authorController.text ==
UserApi.model.getUserInfo["nick_name"]) {
authorController.text = '';
} // 默认值则自动置空
},
maxLines: 1,
maxLength: 7, // 限制最长字符
controller: authorController,
decoration: InputDecoration(
counterText: "", // 不显示字符串数量
disabledBorder: InputBorder.none,// 无边框
enabledBorder: InputBorder.none,
focusedBorder: InputBorder.none,
border: InputBorder.none,
// contentPadding: EdgeInsets.all(10.0),
),
autofocus: false,
textAlign: TextAlign.left,
style: Theme.of(context).textTheme.bodyText2,
)),
],
),
|
组件位置
1
2
3
4
5
|
GlobalKey anchorKey = GlobalKey();
RenderBox renderBox =
anchorKey.currentContext.findRenderObject();
var offset = renderBox.localToGlobal(Offset(0.0, 0.0));
|
延迟执行
1
2
3
4
5
|
// 延时1s执行返回
Future.delayed(Duration(seconds: 1), (){
Navigator.of(context).pop();
print('延时1s执行');
});
|
wifi 真机调试
https://juejin.im/post/5c9848cae51d450d91120278
定时器 循环执行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
import 'dart:async'; // 引入定时去所需要的包
Timer _timer; // 定义一个变量,在页面销毁时需要用到,如果在定时器内部已经销毁了,可以不需要
int _count = 0; // 一切为了演示。定义的变量
...
myTimer() { // 定义一个函数,将定时器包裹起来
_timer = Timer.periodic(Duration(milliseconds: 1000), (t) {
_count++;
if (_count==5) {
t.cancel(); // 定时器内部触发销毁
}
});
}
...
@override
void dispose(() {
if (_timer != null) { // 页面销毁时触发定时器销毁
if (_timer.isActive) { // 判断定时器是否是激活状态
_timer.cancel();
}
}
super.dispose();
});
|
https://juejin.im/post/5cada409e51d456e5b66ad1b
https://juejin.im/post/5d81cf6d518825485e227b8c
仅仅执行一次, 在构造中写逻辑
1
2
3
4
5
|
MineView() {
WidgetsBinding.instance.addPostFrameCallback((callback) {
HttpUtils.userModel.controller.callRefresh();
});
}
|
自定义高度 appbar
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
appBar: AppBar(
brightness: Brightness.dark,
leading: navigatPop(context, color: Colors.white),
backgroundColor: Colors.blue[300],
bottom: PreferredSize(
child: Column(
children: [
Container(
padding: EdgeInsets.only(left: 20, bottom: 30),
alignment: Alignment.centerLeft,
child: Text(
title,
style: Theme.of(context)
.textTheme
.headline6
.copyWith(color: Colors.white),
),
),
],
),
preferredSize: Size(double.infinity, 70)),
),
|
滑动删除
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
|
Slidable(
key: Key(index.toString()),
actionPane: SlidableScrollActionPane(), //滑出选项的面板 动画
actionExtentRatio: 0.25,
dismissal: SlidableDismissal(
child: SlidableDrawerDismissal(),
onWillDismiss: (actionType) {
return action(index, e.id);
},
onDismissed: (actionType) {
print(actionType);
},
),
secondaryActions: <Widget>[
Padding(
padding: EdgeInsetsDirectional.only(top: 20, bottom: 15),
child: IconSlideAction(
caption: 'Delete',
color: Colors.red,
icon: Icons.delete,
closeOnTap: false,
onTap: () {
showIosDialog(context, title: title, desc: desc)
.then((value) {
if (value) {
action(index, e.id);
}
});
})),
],
|
Flutter TextField设置只读不可编辑
1
2
3
4
|
TextField(
enableInteractiveSelection: false,
onTap: () { FocusScope.of(context).requestFocus(new FocusNode()); },
)
|
参考 : [http://www.appblog.cn/2019/01/22/Flutter%20TextField%E8%AE%BE%E7%BD%AE%E5%8F%AA%E8%AF%BB%E4%B8%8D%E5%8F%AF%E7%BC%96%E8%BE%91/](http://www.appblog.cn/2019/01/22/Flutter TextField设置只读不可编辑/)
可选的 text selectabletext