如何在MessagesCollectionView单元格不足时显示滚动指示器?
我正在把MessagesCollectionView做成气泡对话框样式,为了让滚动指示器正常显示,我在viewDidLoad里设置了collectionView?.showsVerticalScrollIndicator = true,但因为单元格数量太少、内容高度不够填满collectionView的可见区域,这个设置完全没效果。我的viewDidLoad代码如下:
override func viewDidLoad() { super.viewDidLoad() tabBarController?.tabBar.isHidden = true collectionView?.backgroundColor = UIColor.white collectionView?.register(ChatLogMessageCell.self, forCellWithReuseIdentifier: cellId) collectionView?.alwaysBounceVertical = true collectionView?.showsVerticalScrollIndicator = true collectionView?.scrollIndicatorInsets = UIEdgeInsets(top: 0,left: 0,bottom: (tabBarController?.tabBar.frame.size.height)!,right: 0) }
请问有没有办法在单元格数量不足、内容高度不够的情况下,仍然让滚动指示器显示出来?如果可行的话,麻烦给我具体的解决思路。
当然可以实现!系统默认的滚动指示器只会在内容尺寸大于容器可视尺寸时才会显示,所以我们要做的就是“欺骗”系统,让它认为内容足够长,同时还要保证实际的滚动行为不受影响。这里有两种靠谱的思路:
思路一:动态调整CollectionView的ContentSize
通过手动修改contentSize,让内容高度至少比collectionView的可视高度大一点点(比如1pt),这样系统就会认为有滚动空间,从而显示滚动指示器。
你可以在viewDidLayoutSubviews或者数据源刷新后添加这段代码:
override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() guard let collectionView = collectionView else { return } let visibleHeight = collectionView.bounds.height var contentSize = collectionView.contentSize // 如果内容高度小于可视高度,强制把内容高度设为可视高度+1 if contentSize.height < visibleHeight { contentSize.height = visibleHeight + 1 collectionView.contentSize = contentSize } }
注意:这种方法会让collectionView允许轻微的垂直滚动(因为内容多了1pt),但用户几乎察觉不到,同时滚动指示器会正常显示。如果不想让用户能滚动,你可以额外设置collectionView.isScrollEnabled = false,但这样滚动指示器会变成灰色不可交互状态,你可以根据需求选择。
思路二:自定义滚动指示器
如果不想修改contentSize,你可以自己创建一个UIView来模拟系统的滚动指示器,把它添加到collectionView的上层,完全自主控制它的显示和样式。
大致步骤和示例代码:
private var customScrollIndicator: UIView! override func viewDidLoad() { super.viewDidLoad() // ... 你的原有代码 ... // 创建自定义滚动指示器 customScrollIndicator = UIView() customScrollIndicator.backgroundColor = UIColor.systemGray2 customScrollIndicator.layer.cornerRadius = 2 // 模拟系统圆角样式 customScrollIndicator.isHidden = false // 强制显示 collectionView?.addSubview(customScrollIndicator) // 设置约束:和系统指示器位置对齐 customScrollIndicator.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ customScrollIndicator.trailingAnchor.constraint(equalTo: collectionView!.trailingAnchor, constant: -8), customScrollIndicator.widthAnchor.constraint(equalToConstant: 4), customScrollIndicator.topAnchor.constraint(equalTo: collectionView!.topAnchor, constant: 8), customScrollIndicator.bottomAnchor.constraint(equalTo: collectionView!.bottomAnchor, constant: -8) ]) }
这种方式完全不受系统逻辑限制,你还可以自由调整指示器的颜色、宽度、圆角等样式;如果需要模拟滚动时的位置变化,只需要监听collectionView的contentOffset,根据滚动比例调整自定义指示器的frame即可。
内容的提问来源于stack exchange,提问作者Ninja

