Xamarin.Forms iOS关联本地库重载ObservableCollection时FlowListView闪烁求解
问题根本原因
iOS 15 对 UITableView(FlowListView 底层在iOS端的封装实现)的布局重算、单元格复用逻辑做了调整,结合你开启了HasUnevenRows=true的配置,每个列表项的异步属性更新都会触发行高重算,进而触发整个列表的全局布局刷新:
- 你当前的实现是每个列表项单独触发异步数据库查询,查询完成后修改
likeButton1属性,相当于短时间内批量触发多次布局更新,就会出现你看到的内容跳动、闪烁问题 - 单独的单次异步更新不会有明显感知,批量同时触发的情况下就会被放大
可行解决方案
方案1:预批量查询点赞状态(最推荐,根治问题)
不要在列表绑定阶段为单个项单独做异步查询,改为在数据源请求完成后,批量查询所有列表项的点赞状态,同步完成属性赋值后再绑定到列表:
// 假设rawList是你从接口/其他地方拿到的原始列表数据 var allAdIds = rawList.Select(item => int.Parse(item.ID1)).ToList(); // 单次批量查询所有收藏记录,避免多次IO var allFavRecords = await App.DatabaseFAV.Table<ReadIfFavType>() .Where(fav => allAdIds.Contains(fav.adID)) .ToListAsync(); var favIdSet = allFavRecords.Select(f => f.adID).ToHashSet(); // 同步给所有项赋值点赞图标,没有异步回调 foreach(var xR in rawList) { var iconPath = favIdSet.Contains(int.Parse(xR.ID1)) ? "btn_item_favorite.png" : "btn_item_nofavorite.png"; xR.likeButton1 = ImageSource.FromFile(iconPath); } // 最后再更新绑定到FlowListView的ObservableCollection // 建议使用ObservableRangeCollection等支持批量更新的集合,只触发一次集合变更通知 YourBoundCollection.ReplaceRange(rawList);
方案2:适配iOS 15 列表默认属性
iOS 15 新增了UITableView.SectionHeaderTopPadding属性,默认值为非0,会在列表重载时额外增加头部边距,也是导致列表跳动的常见原因,全局禁用该属性即可:
// 在页面初始化或App启动时执行 if (Device.RuntimePlatform == Device.iOS && Device.Version >= new Version(15, 0)) { UIKit.UITableView.Appearance.SectionHeaderTopPadding = 0; }
方案3:优化异步查询触发时机
如果无法做批量预查询,就把单个项的点赞查询延迟到单元格即将展示时触发,避免批量同时触发异步回调:
- 首先给所有列表项设置默认点赞图标(比如默认显示未点赞状态),绑定阶段不需要做任何异步操作
- 在
FlowItemAppearing事件中,获取当前即将展示的项,单独触发该条的点赞状态查询,完成后仅更新这一个项的likeButton1属性
这样同一时间最多只有2-3个异步查询在执行,不会批量触发布局重算,闪烁问题会消失。
方案4:禁用列表重载动画
如果以上方案都不能完全解决,可自定义FlowListView的iOS端Renderer,在列表重载时禁用默认的动画效果:
// 自定义Renderer中重写ReloadData逻辑 public override void ReloadData() { UIView.PerformWithoutAnimation(() => { base.ReloadData(); }); }
内容的提问来源于stack exchange,提问作者innom
相关产品推荐
相关产品推荐

