如何使用ion-grid实现GIPHY同款瀑布流布局并修复Android端滚动失效问题
问题描述
我想要实现类似GIPHY的UI界面,界面参考图如下:
我需要使用ion-grid实现这种相邻列高度不一致的瀑布流网格布局。目前我通过2列的grid布局,每列内置多个ion-card已经实现了效果尚可的瀑布流网格布局,但该方案在web端可以正常滚动,打包为Android安装包后滚动功能失效,我使用的滚动组件是ion-infinite-scroll,请问该问题的产生原因是什么?以下是我的实现代码:
<ion-grid> <div *ngIf="!isSomeGiphiesLoaded() && loadingNext" align="center" class="div-center"> <ion-spinner style="transform: scale(2)"></ion-spinner> </div> <app-no-item-found [label]="'No search results found!'" *ngIf="!isSomeGiphiesLoaded() && !loadingNext"></app-no-item-found> <ion-row> <ion-col size="6"> <ion-card class="ion-no-margin ion-no-padding" *ngFor="let giphy of giphiesLeft; let i = index"> <app-giphy-view [giphy]="giphy"></app-giphy-view> </ion-card> </ion-col> <ion-col size="6"> <ion-card class="ion-no-margin ion-no-padding" *ngFor="let giphy of giphiesRight; let i = index"> <app-giphy-view [giphy]="giphy"></app-giphy-view> </ion-card> </ion-col> <ion-infinite-scroll *ngIf="queryString===''" (ionInfinite)="loadDataV2($event)" threshold="100px"> <ion-infinite-scroll-content loadingSpinner="bubbles" loadingText="Loading more gifs..."> </ion-infinite-scroll-content> </ion-infinite-scroll> <ion-infinite-scroll *ngIf="queryString!==''" (ionInfinite)="loadSearchedData($event)" threshold="100px"> <ion-infinite-scroll-content loadingSpinner="bubbles" loadingText="Loading more gifs..."> </ion-infinite-scroll-content> </ion-infinite-scroll> </ion-row> </ion-grid>
原因分析
- ion-infinite-scroll放置位置错误:当前组件放在ion-row内部,和两列ion-col同级,Android端WebView渲染时,ion-row高度受两列独立高度影响,无法正确识别滚动边界,导致组件无法捕获滚动到底部的事件。
- 滚动上下文不匹配:ion-infinite-scroll必须依附于可滚动的ion-content容器,若外层没有配置正确的ion-content,或是ion-content关闭了纵向滚动,Android端会无法识别滚动事件。
- 父容器高度计算异常:两列分别渲染数据的布局下,ion-row默认不会自动适配两列的最大高度,导致整体内容高度计算错误,ion-infinite-scroll误判已经滚动到底部,不会触发加载逻辑。
解决方案
- 调整组件位置:将ion-infinite-scroll从ion-row内部移出,放在ion-grid外、ion-content的最底部,保证组件可以正确监听整个内容区域的滚动事件。
- 合并重复的ion-infinite-scroll:无需写两个组件,直接在触发事件中判断queryString调用对应方法,减少冗余DOM避免Android端渲染冲突,调整后的代码如下:
<ion-content scrollY="true"> <ion-grid> <div *ngIf="!isSomeGiphiesLoaded() && loadingNext" align="center" class="div-center"> <ion-spinner style="transform: scale(2)"></ion-spinner> </div> <app-no-item-found [label]="'No search results found!'" *ngIf="!isSomeGiphiesLoaded() && !loadingNext"></app-no-item-found> <ion-row> <ion-col size="6"> <ion-card class="ion-no-margin ion-no-padding" *ngFor="let giphy of giphiesLeft; let i = index"> <app-giphy-view [giphy]="giphy"></app-giphy-view> </ion-card> </ion-col> <ion-col size="6"> <ion-card class="ion-no-margin ion-no-padding" *ngFor="let giphy of giphiesRight; let i = index"> <app-giphy-view [giphy]="giphy"></app-giphy-view> </ion-card> </ion-col> </ion-row> </ion-grid> <ion-infinite-scroll (ionInfinite)="queryString === '' ? loadDataV2($event) : loadSearchedData($event)" threshold="100px"> <ion-infinite-scroll-content loadingSpinner="bubbles" loadingText="Loading more gifs..."> </ion-infinite-scroll-content> </ion-infinite-scroll> </ion-content>
- 增加CSS适配高度:给ion-row和ion-col增加样式强制高度自适应,避免父容器高度计算错误:
ion-row { display: flex; align-items: flex-start; height: auto; } ion-col { height: auto; }
- 手动更新滚动状态:数据加载完成后调用
complete()方法更新ion-infinite-scroll状态:
// 对应你的加载逻辑调整即可 loadDataV2(event) { // 加载数据逻辑 setTimeout(() => { event.target.complete(); }, 500); } loadSearchedData(event) { // 加载搜索结果逻辑 setTimeout(() => { event.target.complete(); }, 500); }
内容的提问来源于stack exchange,提问作者Ahmed Samin Yeaser Kabir
相关产品推荐
相关产品推荐

