首次通过UICollectionView Cell push视图失败,UINavigationController对象变更问题
问题原因
你遇到的问题核心是自定义UICollectionViewCell持有的父Controller引用失效,具体触发逻辑如下:
- UICollectionView存在Cell复用机制,首次渲染Cell时你给Cell赋值了父Controller引用,此时点击跳转正常
- push新页面后返回列表,已经渲染完成的Cell没有触发复用逻辑,持有的旧Controller引用可能因为导航栈状态变化变为非活动状态/无效引用,导致
NavigationController.PushViewController调用不生效 - 滚动列表时不可见的Cell会触发复用,你在
GetCell方法里重新给Cell的Controller属性赋值了最新的实例,所以滚动后功能恢复
解决方案
最优方案(推荐):调整架构,把跳转逻辑移到父Controller处理
Cell属于视图层,不应该持有Controller引用也不应该处理页面跳转逻辑,改用回调机制把点击事件抛给父Controller处理,从根源避免引用失效问题:
- 给自定义Cell定义点击回调
public class CustomCollectionViewCell : UICollectionViewCell { // 声明点击回调,参数可以按你的需要传 public Action<string> OnCellTapped; private void TapDetected() { var username = this.username.Text; OnCellTapped?.Invoke(username); } // 其他原有逻辑保留 }
- 在父ViewController的
GetCell复用方法里绑定回调
public override UICollectionViewCell GetCell(UICollectionView collectionView, NSIndexPath indexPath) { var cell = collectionView.DequeueReusableCell("你的Cell复用ID", indexPath) as CustomCollectionViewCell; // 原有给Cell赋值数据的逻辑保留 // 绑定点击回调,跳转逻辑直接在父Controller里执行 cell.OnCellTapped = (username) => { var profileViewController = new ProfileViewController(username); profileViewController.ModalPresentationStyle = UIModalPresentationStyle.FullScreen; this.NavigationController.PushViewController(profileViewController, true); }; return cell; }
- 删掉Cell里所有和持有、调用父Controller相关的代码即可。
临时修复方案(不推荐,仅适配现有逻辑)
如果你不想改动现有架构,只需要在每次Cell复用时(也就是GetCell方法给Cell赋值的阶段),都重新给Cell的controller属性赋值当前父ViewController的最新实例,保证Cell持有的引用永远有效。
冗余代码清理
删掉你TapDetected方法里的controller.ModalPresentationStyle = UIModalPresentationStyle.FullScreen;这行代码,你要push的是ProfileViewController,修改父Controller的模态展示风格完全没有作用,反而可能引发导航栈状态异常。
内容的提问来源于stack exchange,提问作者Blackie
相关产品推荐
相关产品推荐

