【发布时间】:2020-08-03 06:37:17
【问题描述】:
关于 SO 的第一个问题,请耐心等待。我创建了一个 UICollectionViewController,它有一个标题和 1 个单元格。单元格内部是一个表格视图,表格视图内部有多个静态单元格。其中之一有一个水平的 UICollectionView,其中包含具有 UITextViews 的单元格。
问题:点击 UITextView 时,集合视图会滚动/跳转
在右侧,您可以看到 y 偏移值。在第一次点击时,它变为 267 - 标题高度。连续点击它会下降到 400 - 最底部。无论我尝试做什么,都会发生这种情况。
注意:在我的整个应用程序中,我都在使用 IQKeyboardManager
我尝试了什么:
完全禁用 IQKeyboardManager 并
- 点击文本视图
- 将其替换为基于旧 SO 答案的自定义键盘管理方法
设置collectionView.shouldIgnoreScrollingAdjustment = true为:
- VC 中的所有可滚动视图
- 个人可滚动视图
注意:此属性源自 IQKeyboardManager 库,据我了解,它应该禁用滚动调整偏移。
尝试在 viewDidLoad() 以及此 VC 中的所有其他位置完全禁用滚动。我用过:
collectionView.isScrollEnabled = false
collectionView.alwaysBounceVertical = false
值得注意的是,我尝试在文本 viewDidBeginEditing 以及自定义键盘管理方法中禁用滚动。
我的代码:
主 UICollectionView 及其一个单元格在情节提要中创建。其他一切都是以编程方式完成的。这是决定唯一单元格大小的流布局函数:
extension CardBuilderCollectionViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout:
UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let height = view.frame.size.height
let width = view.frame.size.width
return CGSize(width: width * cellWidthScale, height: height * cellHeigthScale)
}
}
另外,collectionView.contentInsetAdjustmentBehavior = .never
该单元格子类中的 TableView 是这样创建的:
let tableView: UITableView = {
let table = UITableView()
table.estimatedRowHeight = 300
table.rowHeight = UITableView.automaticDimension
return table
}()
和:
override func awakeFromNib() {
super.awakeFromNib()
dataProvider = DataProvider(delegate: delegate)
addSubview(tableView)
tableView.fillSuperview() // Anchors to 4 corners of superview
registerCells()
tableView.delegate = dataProvider
tableView.dataSource = dataProvider
}
表格视图中的单元格都是GeneralTableViewCell类的子类,它包含以下确定单元格高度的方法:
var cellHeightScale: CGFloat = 0.2 {
didSet {
setContraints()
}
}
private func setContraints() {
let screen = UIScreen.main.bounds.height
let heightConstraint = heightAnchor.constraint(equalToConstant: screen*cellHeightScale)
heightConstraint.priority = UILayoutPriority(999)
heightConstraint.isActive = true
}
表格视图中嵌套单元格(带有TextView)的高度使用与主视图中唯一一个单元格相同的方法确定。
最后使用自定义 FlowLayout 创建标题:
class StretchyHeaderLayout: UICollectionViewFlowLayout {
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
let layoutAttributes = super.layoutAttributesForElements(in: rect)
layoutAttributes?.forEach({ (attribute) in
if attribute.representedElementKind == UICollectionView.elementKindSectionHeader && attribute.indexPath.section == 0 {
guard let collectionView = collectionView else { return }
attribute.zIndex = -1
let width = collectionView.frame.width
let contentOffsetY = collectionView.contentOffset.y
print(contentOffsetY)
if contentOffsetY > 0 { return }
let height = attribute.frame.height - contentOffsetY
attribute.frame = CGRect(x: 0, y: contentOffsetY, width: width, height: height)
}
})
return layoutAttributes
}
override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
return true
}
}
这是我第一次使用主要是程序化方法设计复杂的布局。因此,我可能错过了一些明显的东西。但是,尽管浏览了许多旧问题,但我无法找到解决方案。任何解决方案或指导表示赞赏。
编辑:
根据要求,这里是自定义键盘方法:
在 viewDidLoad() 中
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
然后:
var scrollOffset : CGFloat = 0
var distance : CGFloat = 0
var activeTextFeild: UITextView?
var safeArea: CGRect?
@objc func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
var safeArea = self.view.frame
safeArea.size.height += collectionView.contentOffset.y
safeArea.size.height -= keyboardSize.height + (UIScreen.main.bounds.height*0.04)
self.safeArea = safeArea
}
}
private func configureScrollView() {
if let activeField = activeTextFeild {
if safeArea!.contains(CGPoint(x: 0, y: activeField.frame.maxY)) {
print("No need to Scroll")
return
} else {
distance = activeField.frame.maxY - safeArea!.size.height
scrollOffset = collectionView.contentOffset.y
self.collectionView.setContentOffset(CGPoint(x: 0, y: scrollOffset + distance), animated: true)
}
}
// prevent scrolling while typing
collectionView.isScrollEnabled = false
collectionView.alwaysBounceVertical = false
}
@objc func keyboardWillHide(notification: NSNotification) {
if distance == 0 {
return
}
// return to origin scrollOffset
self.collectionView.setContentOffset(CGPoint(x: 0, y: scrollOffset), animated: true)
scrollOffset = 0
distance = 0
collectionView.isScrollEnabled = true
}
最后:
//MARK: - TextViewDelegate
extension CardBuilderCollectionViewController: UITextViewDelegate {
func textViewDidBeginEditing(_ textView: UITextView) {
self.activeTextFeild = textView
configureScrollView()
}
}
【问题讨论】:
-
您能向我们展示您的自定义键盘管理吗?你在那里处理滚动?
-
我已将这些添加到问题的底部
标签: ios swift uicollectionview uikit uikeyboard