1、前言
高仿某东商城flutter版本是个人学习flutter的练手项目,开源以来收到几位同学的反馈,存在性能问题。
本人用的21款M1 Pro的MacBook Pro
,一直使用ios模拟器开发,很流畅,收到反馈后,找了几个Android设备跑了下的确比较卡 😓
,于是抽时间进行了优化,先看下优化后的效果,再分享下优化的点
可以看到优化后的UI线程
和Raster线程
均为绿色
2、优化
2.1 使用LazyLoadIndexedStack
替代IndexedStack实现首页、分类、购物车、我的4个tab页面懒加载
LazyLoadIndexedStack源码
import 'package:flutter/widgets.dart';
class LazyLoadIndexedStack extends StatefulWidget {
late final Widget unloadWidget;
final AlignmentGeometry alignment;
final StackFit sizing;
final TextDirection? textDirection;
final int index;
final List<Widget> children;
LazyLoadIndexedStack({
Key? key,
Widget? unloadWidget,
this.alignment = AlignmentDirectional.topStart,
this.sizing = StackFit.loose,
this.textDirection,
required this.index,
required this.children,
}) : super(key: key) {
this.unloadWidget = unloadWidget ?? Container();
}
@override
LazyLoadIndexedStackState createState() => LazyLoadIndexedStackState();
}
class LazyLoadIndexedStackState extends State<LazyLoadIndexedStack> {
late List<Widget> _children;
final _stackKey = GlobalKey();
@override
void initState() {
super.initState();
_children = _initialChildren();
}
@override
void didUpdateWidget(final LazyLoadIndexedStack oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.children.length != oldWidget.children.length) {
_children = _initialChildren();
}
_children[widget.index] = widget.children[widget.index];
}
@override
Widget build(final BuildContext context) {
return IndexedStack(
key: _stackKey,
index: widget.index,
alignment: widget.alignment,
textDirection: widget.textDirection,
sizing: widget.sizing,
children: _children,
);
}
List<Widget> _initialChildren() {
return widget.children.asMap().entries.map((entry) {
final index = entry.key;
final childWidget = entry.value;
return index == widget.index ? childWidget : widget.unloadWidget;
}).toList();
}
}
2.2 使用MasonryGridView.builder替代MasonryGridView.count
2.3 使用flutter_redux有大坑
,不能用来记录滚动条的位置,因为滚动会一直触发build,这是导致卡顿的重要原因,感觉后面有项目会选择其他状态管理库,比如 get、provider
为什么会选择flutter_redux。一直从事前端开发,对redux比较熟练,恰巧看到了flutter_redux就用了,刚刚学习flutter,前期也不知道get、prvider等库。前端的redux只有用到这个变量才会build,这里flutter_redux明明这个widget没有用到store里的某个属性,这个属性变了,widget还刷新,这里不知道是我用的不对,还是就是不支持,有清楚的同学可以告知下
使用
ValueListenableBuilder
改造,频繁变更的状态剥离flutter_reudx。
inal ValueNotifier<double> _pageScrollY = ValueNotifier<double>(0);
return NotificationListener<ScrollNotification>(
onNotification: (ScrollNotification notification) {
int depth = notification.depth;
double distance = notification.metrics.pixels;
if (depth == 0) {
_pageScrollY.value = distance;
}
return false;
}
...
ValueListenableBuilder<double>(
builder: (BuildContext context, double value, Widget? child) {
return Positioned(
top: calc2Top(value),
child: Container(
height: 34,
width: getScreenWidth(context) - calcWidth(value),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: Colors.white,
),
child: child,
),
);
},
valueListenable: pageScrollY,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
SizedBox(
width: 40,
height: 34,
child: UnconstrainedBox(
child: assetImage('images/ic_search.png', 20, 20),
),
),
Expanded(
flex: 1,
child: Container(
height: 34.0,
alignment: Alignment.centerLeft,
child: Text(
S.of(context).homeSearchTip,
style: TextStyle(
fontSize: 14,
color: CommonStyle.placeholderColor,
),
),
),
),
SizedBox(
width: 40,
height: 34,
child: UnconstrainedBox(
child: assetImage('images/ic_camera.png', 20, 20),
),
)
],
),
)
3、结尾
感谢以上两位的反馈,优化的分享到此结束,希望大家都可以写出高性能的代码,最后再次贴出源码 github.com/GuoguoDad/j…