flutter-實現瀑布流布局及下拉刷新上拉加載更多

文章目錄

  • 1. 效果預覽
  • 2. 結構分析
  • 3. 完整代碼
  • 4. 總結

1. 效果預覽

在 Flutter 應用開發中,瀑布流布局常用于展示圖片、商品列表等需要以不規則但整齊排列的內容。同時,下拉刷新和上拉加載更多功能,能夠極大提升用戶體驗,讓用戶方便地獲取最新和更多的數據。預覽圖如下:

預覽

2. 結構分析

  1. 先安裝依賴插件
# 瀑布流布局:https://pub.dev/packages/waterfall_flowwaterfall_flow: ^3.0.3# 上拉加載更多+下拉刷新:https://pub.dev/packages/pull_to_refreshpull_to_refresh: ^2.0.0
  1. 引入必要的庫
import 'dart:async';
import 'package:demo3/constant/imageEnum.dart';
import 'package:flutter/material.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
import 'package:waterfall_flow/waterfall_flow.dart';
  • dart:async:提供了處理異步操作的能力,在我們的代碼中用于處理刷新和加載更多時的延遲操作。
  • package:demo3/constant/imageEnum.dart:這是一個自己的本地圖片Map庫,用于引入圖片枚舉數據,在代碼中用于獲取瀑布流展示的圖片資源路徑。
  • package:flutter/material.dart:Flutter 的核心 UI 庫,提供了構建用戶界面所需的各種組件,如Scaffold、SafeArea、Container、Text等。
  • package:pull_to_refresh/pull_to_refresh.dart:這個庫用于實現下拉刷新和上拉加載更多的功能,是實現頁面交互性的關鍵庫。
  • package:waterfall_flow/waterfall_flow.dart:專門用于創建瀑布流布局的庫,讓我們能夠輕松實現不規則的列表排列效果。
  1. 定義ImageWaterfallFlow組件
class ImageWaterfallFlow extends StatefulWidget {const ImageWaterfallFlow({super.key});State<ImageWaterfallFlow> createState() => ImageWaterfallFlowState();
}

這里定義了ImageWaterfallFlow組件,它是一個有狀態的組件。有狀態組件允許我們在運行時根據用戶操作或其他事件改變組件的狀態,從而動態更新 UI。createState方法返回了ImageWaterfallFlowState實例,這個實例負責管理組件的狀態和構建具體的 UI。

  1. ImageWaterfallFlowState類的詳細解析
class ImageWaterfallFlowState extends State<ImageWaterfallFlow> {/// 字體樣式final TextStyle myTxtStyle = const TextStyle(color: Colors.white, fontSize: 24, fontWeight: FontWeight.w800);/// 模擬數據(初始數據)List imageList = [ImageEnum.banner1,ImageEnum.banner2,ImageEnum.banner3,ImageEnum.model1,ImageEnum.model2,ImageEnum.model3,ImageEnum.model4,ImageEnum.banner1,ImageEnum.banner2,ImageEnum.banner3,ImageEnum.model1,ImageEnum.model2,ImageEnum.model3,ImageEnum.model4];/// 模擬數據(加載更多使用)List moreList = [ImageEnum.banner1, ImageEnum.banner2, ImageEnum.banner3];/// 上拉下拉控制器final RefreshController myRefreshController = RefreshController();
  • 字體樣式定義:myTxtStyle定義了一種字體樣式,包括白色字體顏色、24 的字體大小和粗體字重,用于在瀑布流的圖片容器中顯示圖片序號。
  • 模擬數據定義:
    imageList用于存儲瀑布流初始顯示的圖片數據。這里通過ImageEnum枚舉引入了多個圖片資源,組成了一個初始的圖片列表。
  • moreList是用于上拉加載更多時的數據。當用戶觸發加載更多操作時,這個列表中的數據會被添加到imageList中。
  • 上拉下拉控制器:myRefreshController是一個RefreshController實例,它來自pull_to_refresh庫。這個控制器用于控制下拉刷新和上拉加載更多的操作狀態,比如完成刷新、完成加載等。
  1. 刷新和加載更多的方法
/// 刷新
void onRefresh() async {await Future.delayed(const Duration(milliseconds: 1000));myRefreshController.refreshCompleted();
}/// 加載更多
void onLoadMore() async {await Future.delayed(const Duration(milliseconds: 1000));imageList.addAll(moreList);if (mounted) {setState(() {});}myRefreshController.loadComplete();
}
  • 刷新方法onRefresh:當用戶觸發下拉刷新操作時,這個方法會被調用。Future.delayed函數模擬了一個 1 秒的延遲,代表實際應用中可能需要的網絡請求或數據處理時間。延遲結束后,調用myRefreshController.refreshCompleted()方法通知pull_to_refresh庫刷新操作已經完成,此時頁面會恢復到正常狀態。
  • 加載更多方法onLoadMore:當用戶觸發上拉加載更多操作時,該方法被執行。同樣先通過Future.delayed模擬 1 秒的延遲。然后將moreList中的數據添加到imageList中,更新數據源。if (mounted)條件判斷確保組件仍然在 Widget 樹中(防止在組件被銷毀后嘗試更新狀態),然后通過setState(() {})方法通知 Flutter 框架狀態發生了變化,需要重新構建 UI 以顯示新添加的數據。最后調用myRefreshController.loadComplete()方法表示加載更多操作完成。
  1. 構建 UI 的方法
/// 布局

Widget build(BuildContext context) {return Scaffold(backgroundColor: Colors.black,body: SafeArea(child: SizedBox(width: MediaQuery.of(context).size.width,height: MediaQuery.of(context).size.height,child: listWidget())));
}

在build方法中,首先創建了一個Scaffold組件,設置背景顏色為黑色。Scaffold是 Flutter 應用的基本結構,它提供了一個默認的導航欄、抽屜等布局。接著,使用SafeArea組件確保內容不會被設備的劉海屏或其他安全區域遮擋。在SafeArea內部,通過SizedBox設置了一個與屏幕大小相同的區域,并將listWidget()返回的內容作為其子組件。listWidget()方法負責構建包含瀑布流和刷新、加載更多功能的實際內容。

  1. 構建瀑布流列表的方法
/// 列表
Widget listWidget() {return SmartRefresher(enablePullDown: true,enablePullUp: true,header: const ClassicHeader(),footer: const ClassicFooter(),controller: myRefreshController,onRefresh: onRefresh,onLoading: onLoadMore,child: WaterfallFlow.builder(physics: const BouncingScrollPhysics(),gridDelegate: SliverWaterfallFlowDelegateWithFixedCrossAxisCount(crossAxisCount: 2,crossAxisSpacing: 20,mainAxisSpacing: 20,viewportBuilder: (int index1, int index2) {print('變化:$index1-$index2');},lastChildLayoutTypeBuilder: (index) => index == imageList.length? LastChildLayoutType.fullCrossAxisExtent: LastChildLayoutType.none,),itemCount: imageList.length,itemBuilder: (BuildContext context, int index) {return Container(color: Colors.white,height: (index + 1) % 2 == 0? 100 : 200,child: Container(alignment: Alignment.center,decoration: BoxDecoration(color: Colors.blue.shade300,image: DecorationImage(image: AssetImage(imageList[index]),fit: BoxFit.cover,)),child: Text('第${index + 1}張', style: myTxtStyle)),);},),);
}
  • 使用SmartRefresher組件:這是pull_to_refresh庫中的核心組件,用于實現下拉刷新和上拉加載更多功能。
  • enablePullDown: true和enablePullUp: true分別啟用了下拉刷新和上拉加載更多功能。
  • header: const ClassicHeader()和footer: const ClassicFooter()分別設置了下拉刷新和上拉加載更多時顯示的頭部和底部樣式,這里使用了pull_to_refresh庫提供的經典樣式。
  • controller: myRefreshController關聯了之前定義的刷新控制器。
  • onRefresh: onRefresh和onLoading: onLoadMore分別指定了下拉刷新和上拉加載更多時執行的回調函數,即前面定義的onRefresh和onLoadMore方法。
  • 使用WaterfallFlow.builder構建瀑布流:
  • physics: const BouncingScrollPhysics()設置了瀑布流的滾動物理效果,這里使用了類似于 iOS 的彈性滾動效果。
  • gridDelegate屬性:
    • crossAxisCount: 2指定了瀑布流每行顯示兩個項目。
    • crossAxisSpacing: 20和mainAxisSpacing: 20分別設置了項目在交叉軸(水平方向)和主軸(垂直方向)上的間距。
  • viewportBuilder是一個回調函數,只是簡單打印了索引變化,但在實際應用中可以用于監控視口內項目的變化情況。
  • lastChildLayoutTypeBuilder用于設置最后一個子項的布局類型。當索引等于imageList的長度時,將最后一個子項設置為占據整個交叉軸寬度,否則不進行特殊設置。
  • itemCount: imageList.length指定了瀑布流中項目的數量,即imageList的長度。
  • itemBuilder屬性:這個回調函數用于構建每個瀑布流項目。每個項目是一個Container,外層- Container設置了白色背景,高度根據索引奇偶性分別為 100 或 200。內層Container設置了藍色背景和圖片裝飾,圖片通過AssetImage從imageList中獲取,并使用BoxFit.cover進行適配。同時,在圖片上顯示了圖片的序號,使用了之前定義的myTxtStyle字體樣式。

3. 完整代碼

import 'dart:async';
import 'package:demo3/constant/imageEnum.dart';
import 'package:flutter/material.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
import 'package:waterfall_flow/waterfall_flow.dart';/// 瀑布流
class ImageWaterfallFlow extends StatefulWidget {const ImageWaterfallFlow({super.key});State<ImageWaterfallFlow> createState() => ImageWaterfallFlowState();
}/// 瀑布流狀態
class ImageWaterfallFlowState extends State<ImageWaterfallFlow> {/// 字體樣式final TextStyle myTxtStyle = const TextStyle(color: Colors.white, fontSize: 24, fontWeight: FontWeight.w800);/// 模擬數據(初始數據)List imageList = [ImageEnum.banner1,ImageEnum.banner2,ImageEnum.banner3,ImageEnum.model1,ImageEnum.model2,ImageEnum.model3,ImageEnum.model4,ImageEnum.banner1,ImageEnum.banner2,ImageEnum.banner3,ImageEnum.model1,ImageEnum.model2,ImageEnum.model3,ImageEnum.model4];/// 模擬數據(加載更多使用)List moreList = [ImageEnum.banner1, ImageEnum.banner2, ImageEnum.banner3];/// 上拉下拉控制器final RefreshController myRefreshController = RefreshController();/// 刷新void onRefresh() async {await Future.delayed(const Duration(milliseconds: 1000));myRefreshController.refreshCompleted();}/// 加載更多void onLoadMore() async {await Future.delayed(const Duration(milliseconds: 1000));imageList.addAll(moreList);if (mounted) {setState(() {});}myRefreshController.loadComplete();}/// 布局Widget build(BuildContext context) {return Scaffold(backgroundColor: Colors.black,body: SafeArea(child: SizedBox(width: MediaQuery.of(context).size.width,height: MediaQuery.of(context).size.height,child: listWidget())));}/// 列表Widget listWidget() {return SmartRefresher(enablePullDown: true,enablePullUp: true,header: const ClassicHeader(),footer: const ClassicFooter(),controller: myRefreshController,onRefresh: onRefresh,onLoading: onLoadMore,child: WaterfallFlow.builder(physics: const BouncingScrollPhysics(),gridDelegate: SliverWaterfallFlowDelegateWithFixedCrossAxisCount(crossAxisCount: 2,crossAxisSpacing: 20,mainAxisSpacing: 20,viewportBuilder: (int index1, int index2) {print('變化:$index1-$index2');},lastChildLayoutTypeBuilder: (index) => index == imageList.length? LastChildLayoutType.fullCrossAxisExtent: LastChildLayoutType.none,),itemCount: imageList.length,itemBuilder: (BuildContext context, int index) {return Container(color: Colors.white,height: (index + 1) % 2 == 0 ? 100 : 200,child: Container(alignment: Alignment.center,decoration: BoxDecoration(color: Colors.blue.shade300,image: DecorationImage(image: AssetImage(imageList[index]),fit: BoxFit.cover,)),child: Text('第${index + 1}張', style: myTxtStyle)),);},),);}
}

4. 總結

通過這段代碼,我們成功地在 Flutter 中實現了一個帶有瀑布流布局、下拉刷新和上拉加載更多功能的頁面。從引入必要的庫,到定義組件、管理狀態以及構建復雜的 UI 結構,每一步都緊密配合。pull_to_refresh庫和waterfall_flow庫的使用是實現這些功能的關鍵,合理地設置各種屬性和回調函數,讓頁面具備了良好的交互性和美觀的布局效果。希望這篇文章能幫助你理解并在自己的 Flutter 項目中運用類似的功能。


本次分享就到這兒啦,我是鵬多多,如果您看了覺得有幫助,歡迎評論,關注,點贊,轉發,我們下次見~

往期文章

  • flutter-使用extended_image操作圖片的加載和狀態處理以及緩存和下載
  • flutter-制作可縮放底部彈出抽屜評論區效果
  • flutter-實現Tabs吸頂的PageView效果
  • Vue2全家桶+Element搭建的PC端在線音樂網站
  • 助你上手Vue3全家桶之Vue3教程
  • 助你上手Vue3全家桶之VueX4教程
  • 助你上手Vue3全家桶之Vue-Router4教程
  • 超詳細!Vue的九種通信方式
  • 超詳細!Vuex手把手教程
  • 使用nvm管理node.js版本以及更換npm淘寶鏡像源
  • vue中利用.env文件存儲全局環境變量,以及配置vue啟動和打包命令

個人主頁

  • CSDN
  • GitHub
  • 簡書
  • 博客園
  • 掘金

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/73670.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/73670.shtml
英文地址,請注明出處:http://en.pswp.cn/web/73670.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

在 Ubuntu 下通過 Docker 部署 Nginx 服務器

1. Docker 和 Nginx 簡介以及實驗環境 Docker 是一個開源的容器化平臺&#xff0c;允許開發者將應用程序及其依賴項打包成一個輕量級的、可移植的容器。通過 Docker&#xff0c;開發者可以在任何支持 Docker 的環境中運行應用&#xff0c;從而實現一致的開發和生產環境。Docke…

IoT平臺實時監測機器人狀態的實現方案

通過IoT平臺實時監測機器人狀態的實現方案與可執行路徑 一、整體架構設計 #mermaid-svg-6xMlDfFSZM4Wc8tA {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-6xMlDfFSZM4Wc8tA .error-icon{fill:#552222;}#mermaid-sv…

mybatis里in關鍵字拼接id問題

我們一般會把ids集合用StrUtil.join(‘,’)轉成"1,2,3"這種形式 然后放入in中 我們會這么寫: select id, nick_name, icon from tb_user where id in (#{ids}) order by FIELD(id, #{ids})結果發現sql執行是這樣的: select id, nick_name, icon from tb_user where…

4.用 Excel 錄入數據

一 用 Excel 錄入數據的兩種方式 用鼠標鍵盤錄入數據和從網上爬取數據。 二 用鼠標鍵盤錄入數據 1.錄入數據的規范 橫著錄入數據&#xff08;橫著一條條錄入數據&#xff09;。 2.使用快捷鍵進行數據錄入 tab 鍵和 enter 鍵。 tab 鍵&#xff1a;向右移動一個單元格。 tab 鍵…

C++類與對象-3.23筆記

今天學習了類的概述和寫類的基本框架 在嗶哩嗶哩學習的這個老師的C面向對象高級語言程序設計教程&#xff08;118集全&#xff09;講的很不錯&#xff08;真的&#xff01;&#xff01;&#xff01;&#xff09;&#xff0c;C語言也是在這個老師的帶領下學習的 #include<io…

Android讀寫權限分析

Android系統使用的是Linux內核&#xff0c;所以Android系統沿用了linux系統的那一套文件讀寫權限。 目錄 1&#xff0c;權限解讀1.1&#xff0c;權限分為三種類型&#xff1a;1.2&#xff0c;權限針對的三類對象&#xff1a;1.3&#xff0c;文件和目錄的權限區別1.3.1&#xf…

Python二分查找【清晰易懂】

1. 二分查找是什么&#xff1f; 想象你在玩“猜數字”游戲&#xff1a; 對方心里想一個 1~100 的數字&#xff0c;你每次猜一個數&#xff0c;對方會告訴你是“大了”還是“小了”。 最快的方法&#xff1a;每次都猜中間的數&#xff01;比如第一次猜50&#xff0c;如果大了&…

關于Qt的各類問題

目錄 1、問題&#xff1a;Qt中文亂碼 2、問題&#xff1a;啟動時避免ComBox控件出現默認值 博客會不定期的更新各種Qt開發的Bug與解決方法,敬請關注! 1、問題&#xff1a;Qt中文亂碼 問題描述&#xff1a;我在設置標題時出現了中文亂碼 this->setWindowTitle("算法…

關于我對接了deepseek之后部署到本地將數據存儲到mysql的過程

寫在前面 今天寫一下使用nodejs作為服務端&#xff0c;vue作為客戶端&#xff0c;mysql的數據庫&#xff0c;對接deepseek的全過程&#xff0c;要實現一個很簡單的效果就是&#xff0c;可以自由的詢問&#xff0c;然后可以將詢問的過程存儲到mysql的數據庫中。 文檔對接 deeps…

游戲引擎學習第182天

回顧和今天的計劃 昨天的進展令人驚喜&#xff0c;原本的調試系統已經被一個新的系統完全替換&#xff0c;新系統不僅能完成原有的所有功能&#xff0c;還能捕獲完整的調試信息&#xff0c;包括時間戳等關鍵數據。這次的替換非常順利&#xff0c;效果很好。 今天的重點是在此基…

CSS終極指南:從基礎到高級實踐

目錄 一、CSS基礎概念與核心語法 1.1 CSS的本質與作用 1.2 CSS語法結構 二、CSS與HTML結合的四種方式 2.1 內聯樣式&#xff08;Inline Style&#xff09; 2.2 內部樣式表&#xff08;Internal Style Sheet&#xff09; 2.3 外部樣式表&#xff08;External Style Sheet…

MATLAB 2024b深度學習新特性全面解析與DeepSeek大模型集成開發

MATLAB 2024b深度學習工具箱通過架構創新與功能強化&#xff0c;為科研創新和行業應用提供了全棧式解決方案。 第一&#xff1a;MATLAB 2024b深度學習工具箱新特性 1、MATLAB Deep Learning Toolbox 2、實時腳本&#xff08;Live Script&#xff09;與交互控件&#xff08…

.NET開源的智能體相關項目推薦

一、AntSK 由AIDotNet團隊開發的人工智能知識庫與智能體框架&#xff0c;支持多模型集成和離線部署能力。 核心能力&#xff1a; ? 支持OpenAI、Azure OpenAI、星火、阿里靈積等主流大模型&#xff0c;以及20余種國產數據庫&#xff08;如達夢&#xff09; ? 內置語義內核&a…

Qt彈出新窗口并關閉(一個按鈕)

參考&#xff1a;Qt基礎 練習&#xff1a;彈出新窗口并關閉的兩種實現方式&#xff08;兩個按鈕、一個按鈕&#xff09;_qt打開一個窗口另一個關閉-CSDN博客 實現&#xff1a; 一個按鈕&#xff0c;點擊一次&#xff0c;按鈕的名字從open window變為close window&#xff0c;…

PHP中yield關鍵字的使用

PHP版本>5.5 原理&#xff1a;yield關鍵字會生成一個Generator類的對象&#xff0c;PHP通過Generator實例計算出下一次迭代的值&#xff0c;再次返回一個Generator對象并停止循環&#xff08;即循環一次執行一次&#xff09;。 理解&#xff1a;使用在for/foreach/while循…

SpringBoot集成騰訊云OCR實現身份證識別

OCR身份證識別 官網地址&#xff1a;https://cloud.tencent.com/document/product/866/33524 身份信息認證&#xff08;二要素核驗&#xff09; 官網地址&#xff1a;https://cloud.tencent.com/document/product/1007/33188 代碼實現 引入依賴 <dependency><…

Tabby 一:如何在Mac配置保姆級教程(本地模型替換hugging face下載)

1. brew安裝 mac需要先安裝brew&#xff0c;如果本地已經安裝過brew這一步可以忽略&#xff0c;遇到問題可以自己ai問 /bin/bash -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)" 可能遇到source .zprofile失敗&#xff0c;因為…

C++中使用CopyFromRecordset將記錄集拷貝到excel中時,如果記錄集為0個,函數崩潰,是什么原因

文章目錄 原因分析解決方案1. 檢查記錄集是否為空2. 安全調用COM方法3.進行異常捕獲4. 替代方案&#xff1a;手動處理空數據 總結 在C中使用CopyFromRecordset將空記錄集&#xff08;0條記錄&#xff09;復制到Excel時崩潰的原因及解決方法如下&#xff1a; 原因分析 空記錄集…

【算法學習計劃】貪心算法(上)

目錄 前言&#xff08;什么是貪心&#xff09; leetcode 860.檸檬水找零 leetcode 2208.將數組和減半的最少操作次數 leetcode 179.最大數 leetcode 376.擺動序列 leetcode 300.最長遞增子序列 leetcode 334.遞增的三元子序列 leetcode 674.最長連續遞增序列 leetcode …

PC名詞解釋-筆記本的S0,S1,S2,S3,S4,S5狀態

?&#x1f393;作者簡介&#xff1a;程序員轉項目管理領域優質創作者 &#x1f48c;個人郵箱&#xff1a;[2707492172qq.com] &#x1f310;PMP資料導航&#xff1a;PM菜鳥&#xff08;查閱PMP大綱考點&#xff09; &#x1f4a1;座右銘&#xff1a;上善若水&#xff0c;水善利…