国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - Flutter瀑布流仿寫原生的復用機制詳解

Flutter瀑布流仿寫原生的復用機制詳解

2021-11-01 10:51頭疼腦脹的代碼搬運工 Java教程

這篇文章主要給大家介紹了關于Flutter瀑布流仿寫原生的復用機制的相關資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用flutter具有一定的參考學習價值,需要的朋友可以參考下

廢話開篇:

iOS與android在實現列表界面的時候是有重用機制的,目的就是減少內存開銷,用時間換空間。個人感覺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 實現

@override
Widget 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 = [];
//當前顯示的瀑布流item
List<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單元組件

//渲染瀑布流item
createWaterfallFlow(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瀑布流仿寫原生的復用機制的文章就介紹到這了,更多相關Flutter仿寫復用機制內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!

原文鏈接:https://juejin.cn/post/6989900968842231838

延伸 · 閱讀

精彩推薦
  • Java教程Java BufferWriter寫文件寫不進去或缺失數據的解決

    Java BufferWriter寫文件寫不進去或缺失數據的解決

    這篇文章主要介紹了Java BufferWriter寫文件寫不進去或缺失數據的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望...

    spcoder14552021-10-18
  • Java教程Java8中Stream使用的一個注意事項

    Java8中Stream使用的一個注意事項

    最近在工作中發現了對于集合操作轉換的神器,java8新特性 stream,但在使用中遇到了一個非常重要的注意點,所以這篇文章主要給大家介紹了關于Java8中S...

    阿杜7482021-02-04
  • Java教程xml與Java對象的轉換詳解

    xml與Java對象的轉換詳解

    這篇文章主要介紹了xml與Java對象的轉換詳解的相關資料,需要的朋友可以參考下...

    Java教程網2942020-09-17
  • Java教程小米推送Java代碼

    小米推送Java代碼

    今天小編就為大家分享一篇關于小米推送Java代碼,小編覺得內容挺不錯的,現在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧...

    富貴穩中求8032021-07-12
  • Java教程20個非常實用的Java程序代碼片段

    20個非常實用的Java程序代碼片段

    這篇文章主要為大家分享了20個非常實用的Java程序片段,對java開發項目有所幫助,感興趣的小伙伴們可以參考一下 ...

    lijiao5352020-04-06
  • Java教程升級IDEA后Lombok不能使用的解決方法

    升級IDEA后Lombok不能使用的解決方法

    最近看到提示IDEA提示升級,尋思已經有好久沒有升過級了。升級完畢重啟之后,突然發現好多錯誤,本文就來介紹一下如何解決,感興趣的可以了解一下...

    程序猿DD9332021-10-08
  • Java教程Java使用SAX解析xml的示例

    Java使用SAX解析xml的示例

    這篇文章主要介紹了Java使用SAX解析xml的示例,幫助大家更好的理解和學習使用Java,感興趣的朋友可以了解下...

    大行者10067412021-08-30
  • Java教程Java實現搶紅包功能

    Java實現搶紅包功能

    這篇文章主要為大家詳細介紹了Java實現搶紅包功能,采用多線程模擬多人同時搶紅包,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙...

    littleschemer13532021-05-16
Weibo Article 1 Weibo Article 2 Weibo Article 3 Weibo Article 4 Weibo Article 5 Weibo Article 6 Weibo Article 7 Weibo Article 8 Weibo Article 9 Weibo Article 10 Weibo Article 11 Weibo Article 12 Weibo Article 13 Weibo Article 14 Weibo Article 15 Weibo Article 16 Weibo Article 17 Weibo Article 18 Weibo Article 19 Weibo Article 20 Weibo Article 21 Weibo Article 22 Weibo Article 23 Weibo Article 24 Weibo Article 25 Weibo Article 26 Weibo Article 27 Weibo Article 28 Weibo Article 29 Weibo Article 30 Weibo Article 31 Weibo Article 32 Weibo Article 33 Weibo Article 34 Weibo Article 35 Weibo Article 36 Weibo Article 37 Weibo Article 38 Weibo Article 39 Weibo Article 40
主站蜘蛛池模板: 国产日韩视频 | 免费大片黄 | 丁香综合 | 亚洲福利一区二区 | 最新国产视频 | 国产丝袜一区 | 91福利资源站 | 午夜资源| 精品久久亚洲 | 91精品国产综合久久久久久丝袜 | 亚洲一区二区三区视频 | 国产精品久久久久久久久久久新郎 | 精品视频网 | 中文字幕不卡在线观看 | 欧美一区二区三区久久精品 | 国产欧美精品一区二区三区 | 免费观看一级特黄欧美大片 | 国产亚洲精品美女久久久久久久久久 | 国产成人精品免高潮在线观看 | а天堂中文官网 | 视频二区 | 亚洲男性天堂 | 欧美一区二区三区xxxx监狱 | 久久久久久久国产 | 久久成人国产精品 | 91精品国产91久久久久久 | 一区欧美 | jizzjizzjizz亚洲女 | 亚洲的天堂 | 成年人在线观看 | 91在线视频观看 | 国产精品一区二区三区在线 | 天天看天天爽 | 精品成人在线视频 | 亚洲三区在线观看 | 精品久久久久国产 | 天天天天操 | 欧美日韩国产一区二区三区 | 91午夜理伦私人影院 | 高清中文字幕av | 国产精品美女久久久 |