Flutter吸頂Tabbar+流式佈局

来源:https://www.cnblogs.com/XDJcc/archive/2022/07/05/16447389.html
-Advertisement-
Play Games

實現APP首頁tabbar滾動吸頂功能 首頁代碼: WillPopScope( child: Scaffold( backgroundColor: Colors.white, appBar: PreferredSize( preferredSize: Size(double.infinity, 0. ...


實現APP首頁tabbar滾動吸頂功能

首頁代碼:

           WillPopScope(
            child: Scaffold(
              backgroundColor: Colors.white,
              appBar: PreferredSize(
                preferredSize: Size(double.infinity, 0.w),
                child: AppBar(
                  backgroundColor: Colors.transparent,
                  shadowColor: Colors.transparent,
                  elevation: 0,
                  title: const Text(""),
                ),
              ),
              body: NestedScrollView(
                controller: scrollController,
                headerSliverBuilder:
                    (BuildContext context, bool innerBoxIsScrolled) {
                  return <Widget>[
                    buildHeaderWidget(), // tabbar上面被隱藏的部分
                    SliverOverlapAbsorber(
                      handle: NestedScrollView.sliverOverlapAbsorberHandleFor(
                          context),
                      sliver: SliverPersistentHeader(
                        pinned: true,
                        // floating: true,
                        delegate: StickyTabBarDelegate(
                          child: BrnTabBar(  //生成tabbar
                            controller: tabController,
                            tabs: tabs, 
                            showMore: true,
                            moreWindowText: "欄目總覽",
                            onTap: (state, index) {
                              state.refreshBadgeState(index);
                              // scrollController.animateTo(
                              //     globalKey.currentContext!.size!.height,
                              //     duration: Duration(milliseconds: 200),
                              //     curve: Curves.linear);
                            },
                            onMorePop: () {},
                            closeController: closeWindowController,
                          ),
                        ),
                      ),
                    ),
                    SliverToBoxAdapter(
                      child: SizedBox(
                        height: 60.w,
                      ),
                    )
                  ];
                },
                body: TabBarView(
                  controller: tabController,
                  children: catTabList.map<Widget>((e) {
                    return HomeArticlesListPage(e.id,
                        showTopContainer: showTopContainer);
                  }).toList(),
                ),

                //
              ),
            ),
            onWillPop: () {
              if (closeWindowController!.isShow) {
                closeWindowController!.closeMoreWindow();
                return Future.value(false);
              }
              return Future.value(true);
            },
          );

tabbar下 各頁面流式佈局代碼:

流式佈局使用的是 MasonryGridView.count();
因為是要在tabbar下的頁面 所以 要關閉滾動 且不能綁定 controller;
綁定controller會導致 首頁有滾動事件滾動首頁部分
流式佈局組件滾動流式佈局的界面 然會吸頂 就會失效。

我一開始就犯了這個錯誤  雖然設置了 physics: const NeverScrollableScrollPhysics(),
讓流式佈局不滾動 但是忘記去除綁定的 controller 就導致吸頂的動畫出錯了。

import 'package:communityApp/app/router/routers.dart';
import 'package:communityApp/app/utils/local_storage.dart';
import 'package:communityApp/components/cache_Image_widget.dart';
import 'package:communityApp/home_system/request/homeRequest.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';

class HomeArticlesListPage extends StatefulWidget {
  final int activeCatId; //當前選擇的欄目ID
  Function? showTopContainer;
  HomeArticlesListPage(this.activeCatId, {Key? key, this.showTopContainer})
      : super(key: key);

  @override
  State<HomeArticlesListPage> createState() => _HomeArticlesListPageState();
}

class _HomeArticlesListPageState extends State<HomeArticlesListPage> {
  late ScrollController _scrollViewController;
  List _buildArticleList = []; // 瀑布留 數據列表
  bool _isOver = true; // 介面請求 防抖
  int _page = 1; //當前的頁數
  bool _haveMore = true; //是否有更多的數據

  @override
  void initState() {
    super.initState();

    _scrollViewController = ScrollController(initialScrollOffset: 0.w)
      ..addListener(() {
        // print(_scrollViewController.position.pixels);
        // if (_scrollViewController.position.pixels < 10) {
        //   widget.showTopContainer == null ? '' : widget.showTopContainer!(0.0);
        // } else {
        //   widget.showTopContainer == null ? '' : widget.showTopContainer!(-1.0);
        // }
        // 當滾動到最底部的時候,載入新的數據
        if (_scrollViewController.position.pixels ==
            _scrollViewController.position.maxScrollExtent) {
          //當還有更多數據的時候才會進行載入新數據
          if (_haveMore) {
            _getListViewList();
          }
        }
      });
    _getListViewList();
  }

  // 載入更多 數據
  void _getListViewList() async {
    if (!_isOver) return;
    _isOver = false;
    if (_haveMore) {
      var userId = await LocalStorage.get(LocalStorage.userId);
      var result = await HomeRequest.getArticleList({
        'userId': userId,
        'articleCatId': widget.activeCatId,
        'pageSize': 10,
        'pageNum': _page
      });
      _isOver = true;
      if (mounted) {
        setState(() {
          if (_page == 1) {
            _buildArticleList = result;
          } else {
            _buildArticleList.addAll(result);
          }
          if (result.length == 10) {
            _page++;
          } else if (result.length < 10) {
            _haveMore = false;
          }
        });
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    double width = MediaQuery.of(context).size.width;
    double height = MediaQuery.of(context).size.height;
    return Container(
      padding: EdgeInsets.fromLTRB(20.w, 0.w, 20.w, 60.w),
      child: MasonryGridView.count(
        // controller: _scrollViewController,
        // 展示幾列
        crossAxisCount: 2,
        // 元素總個數
        itemCount: _buildArticleList.length,
        // 單個子元素
        itemBuilder: (BuildContext context, int index) {
          var item = _buildArticleList[index];
          var user = item['user'];
          return GestureDetector(
            onTap: () async {
              /* 跳轉 */
              if (item["type"] == 1) {
                /* 跳轉到動態 */
                var result = await Navigator.of(context).pushNamed(
                    CommunityAppRouter.articelDetailPage,
                    arguments: {"articleId": item["id"].toString()});
              } else {
                var result = await Navigator.of(context).pushNamed(
                    CommunityAppRouter.evaluationDetailPage,
                    arguments: {"articleId": item["id"].toString()});
              }
            },
            child: Container(
              child: Column(
                children: [
                  Container(
                    clipBehavior: Clip.hardEdge, //溢出隱藏c
                    decoration: BoxDecoration(
                      borderRadius: BorderRadius.circular(8.w),
                    ),
                    child: CaCheImageWidget(
                      item['frontCover'],
                    ),
                  ),
                  Container(
                    padding: EdgeInsets.all(8.w),
                    child: Text(
                      item['title'],
                      overflow: TextOverflow.ellipsis,
                      maxLines: 2,
                      style: TextStyle(
                        color: const Color.fromARGB(255, 0, 0, 0),
                        fontSize: 15.sp,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                  ),
                  Container(
                    padding: EdgeInsets.fromLTRB(8.w, 0, 8.w, 8.w),
                    child: Row(
                      crossAxisAlignment: CrossAxisAlignment.center,
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: [
                        Container(
                          width: 110.w,
                          decoration: BoxDecoration(),
                          clipBehavior: Clip.hardEdge,
                          child: Row(
                            crossAxisAlignment: CrossAxisAlignment.center,
                            mainAxisAlignment: MainAxisAlignment.spaceBetween,
                            children: [
                              ClipOval(
                                child: CaCheImageWidget(
                                  user['picture'],
                                  width: 14.w,
                                  height: 14.w,
                                ),
                              ),
                              Container(
                                width: 90.w,
                                margin: EdgeInsets.only(left: 4.w),
                                child: Text(
                                  user['nickName'],
                                  overflow: TextOverflow.ellipsis,
                                  maxLines: 2,
                                  style: TextStyle(
                                    color: Color(0xFFB3BBBD),
                                    fontSize: 11.sp,
                                  ),
                                ),
                              )
                            ],
                          ),
                        ),
                        Container(
                          child: Text(
                            '${item['viewNum']}看過',
                            style: TextStyle(
                              color: const Color(0xFFB3BBBD),
                              fontSize: 11.w,
                            ),
                          ),
                        )
                      ],
                    ),
                  ),
                ],
              ),
            ),
          );
        },
        // 縱向元素間距
        mainAxisSpacing: 10,
        // 橫向元素間距
        crossAxisSpacing: 10,
        //本身不滾動,讓外面的singlescrollview來滾動
        physics: const NeverScrollableScrollPhysics(),
        shrinkWrap: true, //收縮,讓元素寬度自適應
      ),
    );
  }

  @override
  void dispose() {
    _scrollViewController.dispose();
    super.dispose();
  }
}


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 目錄 一、前景回顧 二、實現中斷框架 三、代碼實現 四、中斷的壓棧和出棧過程分析 五、運行測試 一、前景回顧 前面我們已經講解了中斷的基本知識,接下來要開始進行代碼的實操。代碼主要有兩塊,其中一塊是關於可編程中斷控制器8259A的代碼,另一塊主要是整個中斷的代碼。 二、實現中斷框架 IDT:中斷描述 ...
  • 鏡像下載、功能變數名稱解析、時間同步請點擊 阿裡雲開源鏡像站 Ubuntu20.04伺服器版安裝 下載地址:https://ubuntu.com/download/desktop 一、語言選擇:English(按Done確認,Done按鈕在安裝視窗的最下麵) 二、Installer update avail ...
  • 鏡像下載、功能變數名稱解析、時間同步請點擊 阿裡雲開源鏡像站 OneForAll是一款功能強大的子域收集工具 我安裝到了kali git clone https://gitee.com/shmilylty/OneForAll.git git clone https://github.com/shmilylt ...
  • 本文會介紹如何安裝和部署ClickHouse,官方推薦的幾種安裝模式,以及安裝之後如何啟動,ClickHouse集群如何配置等。 簡單來說,ClickHouse的搭建流程如下: 環境檢查,環境依賴安裝 在對應的服務上下載安裝Click House 配置config.xml和user.xml,如果搭建 ...
  • mysql拆分字元串作為查詢條件 有個群友問一個問題 這表的ancestors列存放的是所有的祖先節點,以,分隔 例如我查詢dept_id為103的所有祖先節點,現在我只有一個dept_id該怎麼查 然後我去網上找到這樣一個神奇的sql,改改表名就成了下麵的這樣 SELECT substring_i ...
  • 在如今的業務場景下,高可用性要求越來越高,核心業務跨可用區已然成為標配。騰訊雲資料庫高級工程師劉家文結合騰訊雲資料庫的內核實戰經驗,給大家分享Redis是如何實現多可用區,內容包含Redis主從版、集群版原生架構,騰訊雲Redis集群模式主從版、多AZ架構實現以及多AZ關鍵技術點,具體可分為以下四個 ...
  • 本文主要介紹無損壓縮圖片的概要流程和原理,以及lepton無損壓縮在前期調研中遇到的問題。 ...
  • 安卓往系統中添加日程提醒,吭比較多。 首先有個需求(仿製 ios 日曆),為什麼仿製ios呢?這個得問產品了,我只是一個搬磚的程式員 (*´艸`) 捂嘴 大致有日期,時間,重覆設置,自定義重覆設置,位置提醒設置 跟系統日曆的設置類似,畢竟需要同步到系統,所以設置上面保持規範,都是設置好日期時間,然後 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...