iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >Flutter瀑布流仿写原生的复用机制有什么用
  • 413
分享到

Flutter瀑布流仿写原生的复用机制有什么用

2023-06-20 18:06:59 413人浏览 独家记忆
摘要

这篇文章主要介绍了Flutter瀑布流仿写原生的复用机制有什么用,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。废话开篇:iOS与Android在实现列表界面的时候是有重用机制

这篇文章主要介绍了Flutter瀑布流仿写原生的复用机制有什么用,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。

废话开篇:

iOSAndroid在实现列表界面的时候是有重用机制的,目的就是减少内存开销,用时间换空间。个人感觉flutter并没有特别强调复用,关于listView.builder 的“复用”个人感觉应该是销毁跟重建的过程,所以这里用flutter实现了简单的复用机制。代码拙劣,大神勿喷,共同进步

先看复用效果

Flutter瀑布流仿写原生的复用机制有什么用

复用状态打印

Flutter瀑布流仿写原生的复用机制有什么用

右侧是简单实现瀑布流界面,里面显示的是一共有39个Widget。左侧是控制台打印一共创建的12个Widget,所以这里就简单的实现了Widget复用。

问题一、实现思路是什么?

这里先简单的说一下实现思路。

  • 在渲染界面前,通过计算得出全部的Widget的位置坐标。

  • 首次渲染创建一屏可视瀑布流Widget.

  • 监听滑动,判断当前页面滚动方向展示的瀑布流Widget,先去缓存池里拿,如果没有就直接创建,添加到组件中进行渲染。如果缓存池里有,修改Widget的相对布局位置。

问题二、UI布局代码分析。

Flutter瀑布流仿写原生的复用机制有什么用

tip: WaterfallFlow.dart 瀑布流主页面;WaterfallFlowItem.dart 瀑布流单元item

效果展示:

Flutter瀑布流仿写原生的复用机制有什么用

WaterfallFlowItem.dart 瀑布流item文件

class WaterfallFlowItem extends StatefulWidget{  Frame? _frame;  WaterfallFlowItemState? _waterfallFlowItemState;  WaterfallFlowItem({required Frame frame}){    _frame = frame;  }  Frame getFrame(){    return _frame!;  }  void setFrame({required Frame frame}) {    _frame = frame;    _waterfallFlowItemState!.setFrame(frame: frame);  }  @override  State<StatefulWidget> createState() {    _waterfallFlowItemState = new WaterfallFlowItemState(frame: _frame!);    return _waterfallFlowItemState!;  }}class WaterfallFlowItemState extends State<WaterfallFlowItem> with AutomaticKeepAliveClientMixin {  Frame? _frame;  WaterfallFlowItemState({required Frame frame}){    _frame = frame;  }  void setFrame({required Frame frame}) {    setState(() {      _frame = frame;    });  }  @override  Widget build(BuildContext context) {    return new Positioned(        top: _frame!.top,        left: _frame!.left,        child: GestureDetector(          child: new Container(            color: _frame!.index == 12 ? Colors.red : Color.fromARGB(255, 220, 220, 220),            width: _frame!.width,            height: _frame!.heigth,            child: new Text(_frame!.index.toString()),          ),          onTap: (){          },        )    );  }  @override  // TODO: implement wanTKEepAlive  bool get wantKeepAlive => true;}

WaterfallFlow.dart 主界面文件

builder 实现

@overrideWidget build(BuildContext context) {  return new Container(    //去掉scrollView顶部空白间隙    child: MediaQuery.removePadding(        context: context,        removeTop: true,        child: Scrollbar(          //isAlwaysshown: true,          //showTrackOnHover: true,          //scrollView          child: new SingleChildScrollView(            controller: _scrollController,            child: new Container(              width: MediaQuery.of(context).size.width,              //最大高度              height: _maxHeight,              color: Colors.white,              child: new Stack(                //帧布局下的瀑布流单元格item集合                children: _listWidget,              ),            ),          ),        )  ),  );}

声明的属性

//瀑布流间隔double sep = 5;//瀑布流宽度double? _width;//最大高度double _maxHeight = 0;//左侧最大高度double leftHeight = 0;//右侧最大高度double rightHeight = 0;//主界面高度double _mineContentHeight = 0;//瀑布流item缓存池List<WaterfallFlowItem> _bufferPoolWidget = [];//当前显示的瀑布流itemList<WaterfallFlowItem> _listWidget = [];//当前组渲染frame对象保存List<Frame> _fList = [];//总frame集合List<Frame> _frameList = [];//数据源这里只保存高度List<double> _list = [  100,150,45,11,140,89,212,21,434,545,100,150,45,11,140,89,212,21,434,545,  100,150,45,11,140,89,212,21,434,545,100,150,45,11,140,89,212,21,434,545];//滑动监听ScrollController _scrollController = new ScrollController();//滑动偏移量double _scrollOff = 0;

计算主窗口scrollView 高度

//获取最大高度,并计算出全部的瀑布流位置void getMaxHeight(){  List<Frame> fList = [];  double width = (_width! - sep * 3) / 2.0;  double maxHeight = _maxHeight;  for(int i = _frameList.length;i < _list.length;i++){    double height = _list[i];    bool isLeft = (leftHeight <= rightHeight);    double left = isLeft ? sep : (width + sep * 2);    maxHeight = isLeft ? leftHeight : rightHeight;    Frame frame = Frame(leftP: left, topP: maxHeight, widthP: width, heigthP: height,indexP: i);    if(isLeft == true) {      leftHeight += (height + sep);    } else {      rightHeight += (height + sep);    }    fList.add(frame);  }  _maxHeight = max(leftHeight, rightHeight);  _frameList.addAll(fList);  //刷新  setState(() {});}

Frame 位置信息类

class Frame{  double left = 0;//左  double top = 0;//右  double width = 0;//宽度  double heigth = 0;//高度  int index = 0;//索引  Frame({required leftP  ,required topP,    required widthP,    required heigthP,    required indexP}){    left = leftP * 1.0;    top = topP * 1.0;    width = widthP * 1.0;    heigth = heigthP * 1.0;    index = indexP;  }}

生成瀑布流Widget单元item

//重用池里生成item_takeReuseFlowItem(Frame f,dynamic block){  WaterfallFlowItem? waterfallFlowItem;  //是否重用,是,直接修改frame;否,重新渲染。  bool isReUse = false;  //有,从缓存池里取(缓存中的已在结构树里,可以修改帧布局位置)  if(_bufferPoolWidget.length > 0){    waterfallFlowItem = _bufferPoolWidget.last;    waterfallFlowItem.setFrame(frame: f);    _bufferPoolWidget.removeLast();    isReUse = true;  }    //没有,直接创建(不缓存中的,需要调用setState方法渲染)  if(waterfallFlowItem == null) {    waterfallFlowItem = new WaterfallFlowItem(frame: f,);    isReUse = false;  }  block(waterfallFlowItem,isReUse);}

创建首屏全部可视瀑布流Widget单元组件

//渲染瀑布流itemcreateWaterfallFlow(int index){  getMaxHeight();  //这里加点延迟,保证获取最大高度完成(不太严谨,大神有好方法请赐教[抱拳])  Future.delayed(Duration(milliseconds: 100),(){    _mineContentHeight = context.size!.height;    for(var i = 0;i < _frameList.length;i++){      Frame f = _frameList[i];      //判断可视化逻辑      if(f.top <= _mineContentHeight + _scrollOff) {        _takeReuseFlowItem(f,(WaterfallFlowItem waterfallFlowItem,bool isReuse){          _listWidget.add(waterfallFlowItem);        });      }    }    setState(() {    });  });}

滑动过程中进行重用渲染

//获取上滑状态当前显示的下一个item位置Frame? _getUpNeedShowFrame(){  Frame? f;  WaterfallFlowItem? lastWaterfallFlowItem = _listWidget.last;  if(lastWaterfallFlowItem.getFrame().index + 1 < _frameList.length) {    f = _frameList[lastWaterfallFlowItem.getFrame().index + 1];  }  return f;}//获取下滑状态当前显示的上一个item位置Frame? _getDownNeedShowFrame(){  Frame? f;  WaterfallFlowItem? lastWaterfallFlowItem = _listWidget[0];  if(lastWaterfallFlowItem.getFrame().index - 1 >= 0) {    f = _frameList[lastWaterfallFlowItem.getFrame().index - 1];  }  return f;}//超出界面可视范围的瀑布流加入缓存池void addFlowItemAddToBufferPool(){  List<WaterfallFlowItem> list = [];  for(int i = 0; i < _listWidget.length;i++){    WaterfallFlowItem? waterfallFlowItem = _listWidget[i];    Frame? frame = waterfallFlowItem.getFrame();    if((frame.top + frame.heigth) <  _scrollOff || frame.top > _mineContentHeight + _scrollOff) {      _bufferPoolWidget.add(waterfallFlowItem);      list.add(waterfallFlowItem);    }  }  if(list.length != 0) {    for(int i= 0;i < list.length;i++){      WaterfallFlowItem? waterfallFlowItem = list[i];      if(_listWidget.contains(waterfallFlowItem)){        _listWidget.remove(waterfallFlowItem);      }    }  }  //从缓存池里获取item  //上滑状态  Frame? upNextFrame = _getUpNeedShowFrame();  if(upNextFrame != null) {    //debugPrint('我是在复用 ${upNextFrame.index} ,${upNextFrame.top},${_mineContentHeight + _scrollOff}');    if(upNextFrame.top <= _mineContentHeight + _scrollOff) {      debugPrint('我在上滑重置第${upNextFrame.index}个frame');      _takeReuseFlowItem(upNextFrame,(WaterfallFlowItem waterfallFlowItem,bool isReuse){        _listWidget.add(waterfallFlowItem);        if(!isReuse){          debugPrint('我不是复用');          setState(() {});        } else {          debugPrint('我是复用');          waterfallFlowItem.setFrame(frame: upNextFrame);        }      });    }  }  //下滑状态  Frame? downNextFrame = _getDownNeedShowFrame();  if(downNextFrame != null) {    //debugPrint('我是在复用 ${downNextFrame.index} ,${downNextFrame.top},${_mineContentHeight + _scrollOff}');    if(downNextFrame.top + downNextFrame.heigth > _scrollOff && downNextFrame.top + downNextFrame.heigth < _mineContentHeight + _scrollOff) {      debugPrint('我在下滑重置第${downNextFrame.index}个frame');      _takeReuseFlowItem(downNextFrame,(WaterfallFlowItem waterfallFlowItem,bool isReuse){        _listWidget.insert(0, waterfallFlowItem);        if(!isReuse){          debugPrint('我不是复用');          setState(() {});        } else {          debugPrint('我是复用');          waterfallFlowItem.setFrame(frame: downNextFrame);        }      });    }  }}

滚动监听

_scrollController.addListener(() {  _scrollOff = _scrollController.offset;  //加入缓存池,并进行复用  addFlowItemAddToBufferPool();  debugPrint('总共:${_listWidget.length + _bufferPoolWidget.length} 个');});

基本上flutter的瀑布流复用逻辑就完成了,代码拙劣,里面有些地方需要优化,比如:快速滑动防护,item的内容渲染。flutter对于界面渲染已经很极致了,重写复用有点倒退的赶脚。

感谢你能够认真阅读完这篇文章,希望小编分享的“Flutter瀑布流仿写原生的复用机制有什么用”这篇文章对大家有帮助,同时也希望大家多多支持编程网,关注编程网精选频道,更多相关知识等着你来学习!

--结束END--

本文标题: Flutter瀑布流仿写原生的复用机制有什么用

本文链接: https://www.lsjlt.com/news/299292.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Flutter瀑布流仿写原生的复用机制有什么用
    这篇文章主要介绍了Flutter瀑布流仿写原生的复用机制有什么用,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。废话开篇:iOS与android在实现列表界面的时候是有重用机制...
    99+
    2023-06-20
  • Flutter瀑布流仿写原生的复用机制详解
    目录废话开篇:先看复用效果复用状态打印问题一、实现思路是什么?问题二、UI布局代码分析。总结废话开篇: iOS与android在实现列表界面的时候是有重用机制的,目的就是减少内存开销...
    99+
    2024-04-02
  • MySQL复制的原理和作用是什么
    本篇内容主要讲解“MySQL复制的原理和作用是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“MySQL复制的原理和作用是什么”吧!目录一、MySQL复制相关概念二、简单的一主一从架构实现新数...
    99+
    2023-06-20
  • dubbo的spi机制有什么用途
    Dubbo的SPI(Service Provider Interface)机制可以实现插件化的扩展和灵活的配置,让用户可以在不修改源...
    99+
    2024-04-03
    dubbo
  • DM7数据复制中数据库级复制的原理及用法是什么
    DM7数据复制中数据库级复制的原理及用法是什么,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。DM 的数据复制可以在表级,模式级和库级进行配置,...
    99+
    2024-04-02
  • go的垃圾回收机制有什么用
    Go语言的垃圾回收机制主要用于自动管理内存的分配和释放,以帮助开发者更方便地编写高效且安全的代码。具体来说,Go语言的垃圾回收机制有...
    99+
    2023-10-20
    go
  • 有什么免费的云服务器可以用手机控制
    如果您是在使用 Amazon Alexa 语音助手,那么您可以使用 Microsoft Azure 云服务器来提供远程控制功能。下面是一个用手机控制 Microsoft Azure 云服务器的简单步骤: 打开您的设备。 登录您的 Mic...
    99+
    2023-10-26
    有什么 可以用 服务器
  • Java不能使用字符流读取非文本二进制文件的原因是什么
    这篇文章主要介绍“Java不能使用字符流读取非文本二进制文件的原因是什么”,在日常操作中,相信很多人在Java不能使用字符流读取非文本二进制文件的原因是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Jav...
    99+
    2023-07-06
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作