Reputation: 42660
Currently, we try to place multiple UITextView
s in UICollectionView
.
To ensure UICollectionView
's cell height, will adjust based on the dynamic content of UITextView
, this is what we have done.
UITextView
..estimated(CGFloat(44))
for UICollectionViewCompositionalLayout
collectionView.collectionViewLayout.invalidateLayout()
. This is a critical step to ensure cell height will adjust accordingly.However, calling collectionView.collectionViewLayout.invalidateLayout()
does come with a side effect.
The current scroll position of UICollectionView
will be reset, after calling collectionView.collectionViewLayout.invalidateLayout()
.
Does anyone know how can I
UICollectionView
will auto scroll to current cursor position, so that what is current being typed is visible to user?The code to demonstrate this problem is as follow - https://github.com/yccheok/checklist-demo
Here's the code snippet, on what was happening as typing goes on
func textViewDidChange(_ checklistCell: ChecklistCell) {
//
// Critical code to ensure cell will resize based on cell content.
//
// (But comes with a side effect which will reset scroll position.)
self.collectionView.collectionViewLayout.invalidateLayout()
//
// Ensure our checklists data structure in sync with UI state.
//
guard let indexPath = collectionView.indexPath(for: checklistCell) else { return }
let item = indexPath.item
let text = checklistCell.textView.text
self.checklists[item].text = text
}
Note, the closest solution we have came across is posted at https://medium.com/@georgetsifrikas/embedding-uitextview-inside-uitableviewcell-9a28794daf01
In UITableViewController
, during text change, the author is using
DispatchQueue.main.async {
tableView?.beginUpdates()
tableView?.endUpdates()
}
It works well. But, what is the equivalent solution for UICollectionView
?
We can't try out with self.collectionView.performBatchUpdates
, as our solution is built around Diffable Data Source.
I have tried
DispatchQueue.main.async {
self.collectionView.collectionViewLayout.invalidateLayout()
}
That doesn't solve the problem either.
Upvotes: 1
Views: 865
Reputation: 77433
Unless you are taking advantage of other layout features of UICollectionViewCompositionalLayout
, I would think using a table view would be a better route.
However, if you make these 2 changes to your textViewDidChange(...)
function, you may get the results you're after:
func textViewDidChange(_ checklistCell: ChecklistCell) {
//
// Critical code to ensure cell will resize based on cell content.
//
// 1. DO NOT call this here...
//self.collectionView.collectionViewLayout.invalidateLayout()
//
// Ensure our checklists data structure in sync with UI state.
//
guard let indexPath = collectionView.indexPath(for: checklistCell) else { return }
let item = indexPath.item
let text = checklistCell.textView.text
self.checklists[item].text = text
// 2. update your diffable data source here
applySnapshot(true)
}
Upvotes: 1