1 引导页
普通的页面加一个倒计时
var duration = const Duration(seconds: 3);
Future.delayed(duration, newHomePage);
2 首部尾部导航
Scaffold
appBar 首部
bottomNavigationBar 底部
3 路由
显式声明路由
MaterialApp(
routes: {
"/client": (context) => const Client(),
},
home: const Splash(),
引导页跳转
Navigator.pushReplacementNamed(context, '/client');
跳转传参
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ChooseLinePage(
nodeList: nodeList,
curNodeIndex: curNodeIndex,
))).then((value) => callback(value));
返回代参
Navigator.pop(context, _selIndex);
4 网络
dio:案例
5 uuid
uuid:案例
6 aes 加解密
encrypt:案例
7 弹窗
flutter_smart_dialog:案例
8 网络图片
cached_network_image:案例
9 json动画
lottie:案例
10 webView与 html
webview_flutter: ^2.0.4
flutter_html: ^2.2.1
这2个一起用有版本限制,不是最新的最好。。
webview_flutter通过url拉起web页面
flutter_html 可以显示一些用html写的富文本
11 dart
-
由于dart不能动态获取类的字段,所以json 与class转换需要借助android studio的插件生成class
- ()=>{} 与(){}
2个都是闭包,但是=>后面只能跟一句话,如果想说的有很多,建议写成方法 - 单例
3.1 饿汉式
class Simple{
static final Simple _instance = Simple._internal();
factory Simple() {
return _instance;
}
Simple._internal() {
//todo
}
}
3.2 饱汉式
class Simple {
static Simple? _instance;
factory Simple() {
if (_instance == Null) {
_instance = Simple._internal();
}
return _instance!;
}
Simple._internal() {
//todo
}
}
12 页面布局
填充内容可以用 Container ,column, rows 快速填充。
适配类Expanded(),被该类包裹的child大小会自适应
GestureDetector(),被该类包裹可以添加一个额外opTap点击时间
13 数据持久化 shared_preferences
shared_preferences:案例
14 照片选择器 image_picker
15 上传文件到s3 amplify
16 保存文件到本地 image_gallery_saver
17 分享文件 share_plus
18 视频播放器 video_player
19 页面局部刷新与不刷新
首先 当我们写一个方法返回 widget时,是可以封装为一个组件的,此处拿appbar举例子:
我们每个tarbar都需要相同的顶部 appbar
static AppBar commonAppBar(String title) {
return AppBar(
shadowColor: const Color.fromRGBO(0, 0, 0, 0),
leadingWidth: 280,
leading: Padding(
padding: const EdgeInsets.fromLTRB(16, 10, 0, 0),
child: Text(title,
style: const TextStyle(
fontFamily: 'Impact', color: Colors.black, fontSize: 30)),
),
);
}
每当页面执行 setState(() {});时 appbar也会刷新
如何让appbar不刷新呢?,封装为一个静态组件
//PreferredSizeWidget 使用自定义的appbar必须实现该接口
class CommonAppBar extends StatelessWidget implements PreferredSizeWidget {
final String title;
const CommonAppBar({super.key, required this.title});
@override
Widget build(BuildContext context) {
return AppBar(
shadowColor: const Color.fromRGBO(0, 0, 0, 0),
leadingWidth: 280,
leading: Padding(
padding: const EdgeInsets.fromLTRB(16, 10, 0, 0),
child: Text(title,
style: const TextStyle(
fontFamily: 'Impact', color: Colors.black, fontSize: 30)),
),
);
}
static final _appBar = AppBar();
@override
Size get preferredSize => _appBar.preferredSize;
}
如果因为需求变更我们需要让appbar刷新又该怎么办?使用StatelessWidget
class CommonAppBar extends StatefulWidget implements PreferredSizeWidget {
final String title;
const CommonAppBar({super.key, required this.title});
static final _appBar = AppBar();
@override
Size get preferredSize => _appBar.preferredSize;
@override
State createState() => CommonAppBarStatus();
}
class CommonAppBarStatus extends State {
late String title;
@override
void initState() {
super.initState();
title = widget.title;
}
@override
Widget build(BuildContext context) {
return AppBar(
shadowColor: const Color.fromRGBO(0, 0, 0, 0),
leadingWidth: 280,
leading: Padding(
padding: const EdgeInsets.fromLTRB(16, 10, 0, 0),
child: Text(title,
style: const TextStyle(
fontFamily: 'Impact', color: Colors.black, fontSize: 30)),
),
);
}
//StatelessWidget的特点是可以使用setState(() {});
void flushUI(String title) {
setState(() {
_title = title;
});
}
}
只是这么写外部组件setState(() {});时封装的CommonAppBar还是不会刷新,下面写2种常用的刷新方法:
A.UniqueKey()不做缓存,每次setState(() {});都刷新
Scaffold(
appBar: CommonAppBar (
key: UniqueKey()
title: "test",
),
}
B.GlobalKey存储key,只在想刷新时刷新
final GlobalKey _key= GlobalKey();
Scaffold(
appBar: CommonAppBar (
key: _key
title: "test",
),
}
//在需要刷新的地方调用
_key.currentState?.flushUI("hello");
20 tabbar封装多个页面
参考 pageview和bottomNavigationBar
21 当图片fit类型为BoxFit.contain时,图片的圆角失效(Center 关键点)
SizedBox(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.width - 20,
//关键点:如果+Center有圆角,如果不加Center圆角就会消息
child: Center(
child: ClipRRect(
borderRadius: BorderRadius.circular(20),
child: Image.memory(
imgBytes,
fit: BoxFit.contain,
),
),
),
),
22 某些页面顶部撑不满 使用该组件包子组件即可
SafeArea(
top: false,
child: MediaQuery.removePadding(
removeTop: true,
context: context,
child:
}
23 富文本
RichText(
text: TextSpan(text: title, style: const TextStyle(fontSize: 18, color: Colors.white), children: [
TextSpan(
text: pending,
style: const TextStyle(fontSize: 18, color: Color(0xFF17E8E2)),
)
])),
24 颜色使用hex
拓展color
extension HexColor on Color {
/// String is in the format "aabbcc" or "ffaabbcc" with an optional leading "#".
static Color fromHex(String hexString) {
final buffer = StringBuffer();
if (hexString.length == 6 || hexString.length == 7) buffer.write('ff');
buffer.write(hexString.replaceFirst('#', ''));
return Color(int.parse(buffer.toString(), radix: 16));
}
/// Prefixes a hash sign if [leadingHashSign] is set to `true` (default is `true`).
String toHex({bool leadingHashSign = true}) => '${leadingHashSign ? '#' : ''}'
'${alpha.toRadixString(16).padLeft(2, '0')}'
'${red.toRadixString(16).padLeft(2, '0')}'
'${green.toRadixString(16).padLeft(2, '0')}'
'${blue.toRadixString(16).padLeft(2, '0')}';
}
example
HexColor.fromHex("#222222")
25 小组件
a.可点击小组件
InkWell(
onTap: () {
callBack();
},
child:
)
b.控制显示和隐藏 (备注:只是隐藏和显示,组件还是会被加载,如果child内异常会报错的)
Visibility(
visible: bool,
child:
)