Мой первый вопрос о ТАК, так что потерпите меня. Я создал UICollectionViewController с заголовком и 1 ячейкой. Внутри ячейки находится табличное представление, внутри табличного представления имеется несколько ячеек stati c. Один из них имеет горизонтальный UICollectionView с ячейками, которые имеют UITextViews.
Проблема: При нажатии на UITextView представление коллекции прокручивается / перескакивает
Иллюстрация проблемы
Справа вы можете увидеть значения смещения по оси Y. При первом нажатии он меняется на 267 - высота заголовка. При последовательном нажатии опускается до 400 - самый низ. Это происходит независимо от того, что я пытался сделать.
Примечание: В моем приложении я использую IQKeyboardManager
Что я пробовал:
Полное отключение IQKeyboardManager и
- Нажатие на текстовое представление
- Замена его на собственные методы управления клавиатурой на основе старых ответов SO
Установите collectionView.shouldIgnoreScrollingAdjustment = true
для:
- всех прокручиваемых представлений в V C
- Прокручиваемых представлений отдельных лиц
Примечание. Это свойство происходит из библиотеки IQKeyboardManager. и, насколько я понимаю, предполагается отключить смещение регулировки прокрутки.
Пытался полностью отключить прокрутку в viewDidLoad (), а также во всех других местах в этом V C. Я использовал:
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
}
}
Это мой первый раз, когда я проектирую сложную компоновку, используя в основном программный подход. Следовательно, возможно, я упустил что-то очевидное. Однако, несмотря на просмотр множества старых вопросов, я не смог найти решения. Приветствуются любые решения или рекомендации.
Изменить:
По запросу здесь приведены настраиваемые методы клавиатуры:
In 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()
}
}