UITextView scrolling indicator cut off at top

Sample app

A collection view controller with list layout, 1 section and 1 row.

The cell's content view contains a text view.

class ViewController: UICollectionViewController {
    var snapshot: NSDiffableDataSourceSnapshot<Section, String> {
        var snapshot = NSDiffableDataSourceSnapshot<Section, String>()
        snapshot.appendSections([.main])
        snapshot.appendItems(["one", "two"], toSection: .main)
        return snapshot
    }
    var dataSource: UICollectionViewDiffableDataSource<Section, String>?
    
    enum Section {
        case main
    }
    
    init() {
        super.init(collectionViewLayout: .init())
        
        collectionView.collectionViewLayout = createLayout()
        configureDataSource() // more likely and automatically avoid unpleasant animations on iOS 15 by configuring the data source in the init rather than in view did load
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    func configureDataSource() {
        let cellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, String> { cell, indexPath, itemIdentifier in
            let textView = UITextView()
            textView.font = .systemFont(ofSize: UIFont.labelFontSize)
            
            cell.contentView.addSubview(textView)
            textView.translatesAutoresizingMaskIntoConstraints = false
            NSLayoutConstraint.activate([
                textView.topAnchor.constraint(equalTo: cell.contentView.topAnchor, constant: 8),
                textView.bottomAnchor.constraint(equalTo: cell.contentView.bottomAnchor, constant: -8),
                textView.leadingAnchor.constraint(equalTo: cell.contentView.leadingAnchor, constant: cell.directionalLayoutMargins.leading),
                textView.trailingAnchor.constraint(equalTo: cell.contentView.trailingAnchor, constant: -cell.directionalLayoutMargins.trailing)
            ])
        }
        
        dataSource = .init(collectionView: collectionView) { collectionView, indexPath, itemIdentifier in
            collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: itemIdentifier)
        }
        
        dataSource?.apply(self.snapshot, animatingDifferences: false)
    }
    
    func createLayout() -> UICollectionViewLayout {
        return UICollectionViewCompositionalLayout { section, layoutEnvironment in
            let config = UICollectionLayoutListConfiguration(appearance: .insetGrouped)
            return NSCollectionLayoutSection.list(using: config, layoutEnvironment: layoutEnvironment)
        }
    }
}

Question 1

Can anybody edit the provided sample code so that the text view's vertical indicator inset is not cut off at the top?

Question 2

It seems to me that Apple has successfully implemented text views inside table view cells: can anybody provide Apple documentation as per how to do so?

What I've tried and didn't work

  1. textView.verticalScrollIndicatorInsets.top = 30 // does nothing
  2. Adding the text view to a custom view and the view to the cell's content view
textView.contentInset = .zero
textView.scrollIndicatorInsets = .zero  
textView.textContainerInset = .zero
textView.textContainer.lineFragmentPadding = 0
  1. Centering the text view vertically and constraining its height to that of the content view with an 8 points constant to leave some padding
  2. Constraining the top and bottom anchors of the text view to the cell's layout margins guide's top and bottom anchors

Constraint

I need the text view to have some padding from the top and bottom of the cell for aesthetic reasons.

Answered by Filippo02 in 802079022

Make the cell taller.

Updated cell registration:

let textView = UITextView()
textView.font = .systemFont(ofSize: UIFont.labelFontSize)

cell.contentView.addSubview(textView)
textView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
    textView.centerYAnchor.constraint(equalTo: cell.contentView.centerYAnchor),
    textView.heightAnchor.constraint(equalToConstant: textView.font!.pointSize * 4 - 16),
    textView.leadingAnchor.constraint(equalTo: cell.contentView.leadingAnchor, constant: cell.directionalLayoutMargins.leading),
    textView.trailingAnchor.constraint(equalTo: cell.contentView.trailingAnchor, constant: -cell.directionalLayoutMargins.trailing),
    
    cell.contentView.heightAnchor.constraint(greaterThanOrEqualToConstant: textView.font!.pointSize * 4)
])
Accepted Answer

Make the cell taller.

Updated cell registration:

let textView = UITextView()
textView.font = .systemFont(ofSize: UIFont.labelFontSize)

cell.contentView.addSubview(textView)
textView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
    textView.centerYAnchor.constraint(equalTo: cell.contentView.centerYAnchor),
    textView.heightAnchor.constraint(equalToConstant: textView.font!.pointSize * 4 - 16),
    textView.leadingAnchor.constraint(equalTo: cell.contentView.leadingAnchor, constant: cell.directionalLayoutMargins.leading),
    textView.trailingAnchor.constraint(equalTo: cell.contentView.trailingAnchor, constant: -cell.directionalLayoutMargins.trailing),
    
    cell.contentView.heightAnchor.constraint(greaterThanOrEqualToConstant: textView.font!.pointSize * 4)
])

There's probably a better solution though.

I can't unaccept my answer nor edit it in general though.

Better solution:

NSLayoutConstraint.activate([
    textView.topAnchor.constraint(equalTo: cell.contentView.topAnchor, constant: 8),
    textView.bottomAnchor.constraint(equalTo: cell.contentView.bottomAnchor, constant: -8),
    textView.leadingAnchor.constraint(equalTo: cell.contentView.leadingAnchor, constant: cell.directionalLayoutMargins.leading),
    textView.trailingAnchor.constraint(equalTo: cell.contentView.trailingAnchor, constant: -cell.directionalLayoutMargins.trailing),
    
    // minimum height to show the full vertical scroll indicator
    textView.heightAnchor.constraint(equalToConstant: 41.0),
])

Credit: https://stackoverflow.com/a/78935224/22697469.

Again, I can't unaccept the previously accepted answer.

UITextView scrolling indicator cut off at top
 
 
Q