常用

Posted by アライさん on 2021年10月08日

滚动屏幕自动隐藏软键盘

1
keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,

斜纹背景

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Container(
width: width,
height: height,
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment(-0.5, -0.5),
stops: [0.0, 0.5, 0.5, 1],
colors: [
Colors.grey,
Colors.grey,
Colors.black45,
Colors.black45,
],
tileMode: TileMode.repeated,
),
),
)

baseline


中文会使用TextBaseline.alphabetic对齐,就算设置ideographic,但也无法起效。

防止软键盘把floatingActionButton顶上去

1
2
3
4
5
6
7
8
9
10
11
 @override
Widget build(BuildContext context) {
bool keyboardIsOpened = MediaQuery.of(context).viewInsets.bottom != 0.0;
return Scaffold(
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
floatingActionButton: Visibility(
visible: !keyboardIsOpened,
child: _floatingActionButton(),
),
);
}

自动构建

1
flutter packages pub run build_runner build

单个页面修改状态栏文字图标颜色

1
2
3
AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle.light,
child: ),

Animation<Color>

1
AlwaysStoppedAnimation<Color>(Colors.white)

延迟执行

1
2
3
await Future.delayed(const Duration(seconds: time), () {

});

软键盘覆盖在界面上

1
2
Scaffold(
resizeToAvoidBottomInset: false,)

TextField无法顶部对齐

1
2
3
4
Row(
crossAxisAlignment: CrossAxisAlignment.start,
textBaseline: TextBaseline.alphabetic,
)

TextFeild

设置文字后保持光标在文字之后:

1
2
3
_controller.text =
'${Provider.of<PersonState>(context, listen: false).nickName}';
_controller.selection = TextSelection.fromPosition(TextPosition(offset: _controller.text.length));

MaterialApp

清除右上角debug角标

1
2
MaterialApp(
debugShowCheckedModeBanner: false,)

list转化为children widget

1
2
3
Column(
children: ['','',''].map((e) => Container()).toList(),
),

list转化为children widget,保留index

1
2
3
Column(
children: ['','',''].asMap().map((index,data) => MapEntry(index,Container())).values.toList(),
),

List<List>转换成List

1
List<List<T>>.expand((element)=>element).toList();

在滚动视图中滚动到指定widget

1
2
3
4
final _myKey = new GlobalKey(); 
Scrollable.ensureVisible(_myKey.currentContext,
duration: Duration(seconds: 1));

弧度和角度换算

1
2
3
4
//角度转弧度
num degToRad(num deg) => deg * (pi / 180.0);
//弧度转角度
num radToDeg(num rad) => rad * (180.0 / pi);

对比实例是否相等

可以引入equatable实现

1
2
import 'package:equatable/equatable.dart';
class Post extends Equatable{}

immutable、final、StatefulWidget

在Flutter中,StatefulWidget只是持有一些immutable(不可变)的数据以及创建它的状态,所有成员变量都应该是final,动态部分全部放到了State中。
当状态改变时,通知视图重新绘制,就是setState。

@immutable 注解

不可修改,只能重新创建。由于const必须在编译时创建,所以有时候需要用immutable来完成不可变。
类一旦创建,成员变量就不可改变。

1
2
3
4
5
6
7
import 'package:meta/meta.dart';
// 因为当前类使用@immutable注解,所以变量必须是final的
@immutable
class User {
final String name;
User(this.name)
}

命令行新建项目

1
flutter create -i swift -a kotlin 工程名

显示布局线

1
2
3
4
5
import 'package:flutter/rendering.dart' show debugPaintSizeEnabled;
void main(){
debugPaintSizeEnabled = true;
runApp(new MyApp());
}

vsync

当创建一个AnimationController时,需要传递一个vsync参数,存在vsync时会防止屏幕外动画(译者语:动画的UI不在当前屏幕时)消耗不必要的资源。 通过将SingleTickerProviderStateMixin添加到类定义中,可以将stateful对象作为vsync的值。

1
with SingleTickerProviderStateMixin
1
AnimationController(duration: const Duration(milliseconds: 600), vsync: this);

compute

compute是Flutter对dart的lsolate用法的封装。

lsolate类似线程,但相互之间不共享内存。

顶层方法:

1
2
3
4
5
6
7
8
//必须是顶层方法或类的静态方法
Future<int> testFunction(String str) async {
int result = 0;
for (int i = 0; i < 10000000000; i++) {
result += i;
}
return result;
}

调用:

1
2
3
4
import 'package:flutter/foundation.dart';
int result = await compute(testFunction,'hello');
//不使用compute将会导致UI被阻塞,比如:
//testFunction('hello');

Row和Column的mainAxisAlignment

  • center:将children放置在主轴的中心;
  • end:将children放置在主轴的末尾;
  • spaceAround:将主轴方向上的空白区域均分,使得children之间的空白区域相等,但是首尾child的空白区域为1/2;
  • spaceBetween:将主轴方向上的空白区域均分,使得children之间的空白区域相等,首尾child都靠近首尾,没有间隙;
  • spaceEvenly:将主轴方向上的空白区域均分,使得children之间的空白区域相等,包括首尾child;
  • start:将children放置在主轴的起点;

BoxFit

  • BoxFit.none:原始大小。超过就截取中间,不足就两边留空。
  • BoxFit.fill:拉伸占满。
  • BoxFit.contain:等比缩放。
  • BoxFit.cover:截取中间
  • BoxFit.fitWidth:宽度占满。上下可能留空也可能截取。
  • BoxFit.fitHeight:高度占满。左右可能留空也可能截取。
  • BoxFit.scaleDown:大于父控件,则采用与contain一致的缩放模式,否则采用none缩放模式。

圆角框

1
2
3
4
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(6.0)),
),

Slivers家族

  • SliverAppBar:可折叠的AppBar。
  • SliverList:list列表。
  • SliverFixedExtentList:每项高度固定的list列表。
  • SliverToBoxAdapter:有明确尺寸的child。
  • SliverPadding:包含其他sliver并提供padding。
  • SliverGrid:GridView。

保留2位小数

1
double.toStringAsFixed(2)

TextField控制字符数但去掉右下角记数

1
decoration: InputDecoration(counterText: '',),

Timer定时执行,非阻塞

1
2
3
4
import 'dart:async';
new Timer(new Duration(milliseconds: 2000), () {
//延迟2000毫秒执行
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Timer _timer;
@override
void dispose() {
_timer.cancel();
super.dispose();
}
//倒计时60秒。60秒后退出timer
void _startTimer() {
timerNumber = 60;
const oneSec = const Duration(seconds: 1);
_timer = new Timer.periodic(oneSec, (Timer timer) {
setState(() {
if (timerNumber < 1) {
timer.cancel();
timerNumber = 60;
} else {
timerNumber = timerNumber - 1;
}
});
});
}

Future.delayed,延时执行

阻塞,可以用在Future方法中

1
2
3
4
Future< Null > getData() async {
await Future.delayed(Duration(milliseconds: 3000),(){
});
}

某个页面或某个控件使用自己的主题

1
2
3
4
Theme(
data: ThemeData(
dialogBackgroundColor: Colors.white54,
),),

连续点击2次才能退出应用

使用WillPopScope包裹,拦截返回按键

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
DateTime _lastPressedAt;
return WillPopScope(
onWillPop: () async {
if (_lastPressedAt == null ||
DateTime.now().difference(_lastPressedAt) > Duration(seconds: 1)) {
Fluttertoast.showToast(
fontSize: 14.0,
msg: "再按一次退出程序",
toastLength: Toast.LENGTH_SHORT,
timeInSecForIos: 1,
textColor: Colors.white,
gravity: ToastGravity.BOTTOM,
);
//两次点击间隔超过1秒则重新计时
_lastPressedAt = DateTime.now();
return false;
}
return true;
},
child:...
);

widget根据判断返回null或widget

1
2
3
4
bool notNull(Object o) => o != null;
children: <Widget>[
null,
].where(notNull).toList(),

初始化UI后执行

1
2
3
4
5
6
7
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_){
//do some things
});
}

OutlineInputBorder边框颜色

1
2
3
4
OutlineInputBorder(
borderSide: BorderSide(color: Theme.of(context).primaryColor ),
borderRadius: BorderRadius.circular(8.0),
),