Flutter CustomScrollView嵌套GridView最后一行组件底部被裁剪
问题原因
最后一行组件被裁剪的核心是组件层级间的约束冲突:
SliverFillRemaining默认属性hasScrollBody: true,会给子组件TabBarView传递固定高度约束,高度值等于CustomScrollView当前剩余的可视区域高度- 你给
GridView设置NeverScrollableScrollPhysics禁用了自身滚动,但GridView默认shrinkWrap: false,会优先填满父组件传递的固定高度,不会根据内部item总长度自适应高度 - 当GridView内部所有item的总高度超过父组件给的固定高度时,超出的底部内容就会被父组件的固定高度边界裁剪。
你之前将physics设为可滚动时没有裁剪问题,是因为此时GridView自身的滚动视口生效,内容可以在固定高度内滚动,自然不会出现裁剪,但会触发内外两个滚动组件的手势冲突,不符合预期。
修复方案
按以下两点修改代码即可解决:
- 给
SliverFillRemaining添加参数hasScrollBody: false,告知组件内部子组件不是占满剩余高度的滚动体,允许子组件高度超出剩余视口,Sliver自身高度会随子组件内容自适应撑开 - 给两个
GridView.builder都添加shrinkWrap: true参数,让GridView根据内部所有item的总高度计算自身高度,不再强行撑满父组件传递的高度约束
修改后的对应代码片段:
SliverFillRemaining( hasScrollBody: false, child: TabBarView( controller: _tabController, children: [ GridView.builder( physics: NeverScrollableScrollPhysics(), shrinkWrap: true, gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 3, childAspectRatio: 1, mainAxisSpacing: 1.h, mainAxisExtent: 100.h), itemCount: tagsToShow.length, itemBuilder: (context, index) { return hashtagThumbnail(index, tagsToShow); }, ), GridView.builder( physics: NeverScrollableScrollPhysics(), shrinkWrap: true, gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, ), itemCount: categories.length, itemBuilder: (context, index) { return Container( child: categoryThumbnail(index, categories), ); }, ), ], ), )
补充说明
如果修改后出现Tab切换时页面高度跳动,是因为两个Tab下的GridView内容总高度不一致,属于正常表现。如果需要两个Tab页保持统一高度,只需要给每个GridView外层包裹设置了统一最小高度的容器即可,不会影响整体滚动效果。
内容的提问来源于stack exchange,提问作者Mohammad Shah
相关产品推荐
相关产品推荐

