Потяните, чтобы обновить для UICollectionView в ViewController, при применении NSDiffableDataSourceSnapshot

#ios #swift #uicollectionview

Вопрос:

Я добавил UICollectionView в качестве подвида в свой ViewController. Я также установил UIRefreshControl для UICollectionView, который применяет NSDiffableDataSourceSnapshot, когда я нажимаю для обновления. Анимация скачет при применении моментального снимка (обратите внимание, что это происходит, даже если заголовок панели навигатора невелик).

введите описание изображения здесь

Вот соответствующие фрагменты кода

 var collectionView: UICollectionView! = nil
var dataSource: UICollectionViewDiffableDataSource<Section, Item>! = nil

override func viewDidLoad() {
    super.viewDidLoad()
    
    let collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: 
    generateLayout())
    view.addSubview(collectionView)
    collectionView.autoresizingMask = [.flexibleHeight, .flexibleWidth]
    collectionView.backgroundColor = .systemGroupedBackground
    self.collectionView = collectionView
    collectionView.delegate = self

    let refreshControl = UIRefreshControl()
    refreshControl.addTarget(self, action: #selector(doSomething), for: .valueChanged)
    collectionView.refreshControl = refreshControl
}
    
@objc func doSomething(refreshControl: UIRefreshControl) {
    DispatchQueue.main.async {
        var dataSourceSnapshot = NSDiffableDataSourceSnapshot<Section, Item>()
        // add data
        dataSource.apply(dataSourceSnapshot)
    }
    refreshControl.endRefreshing()
}
 

Есть ли какие-либо изменения, которые я могу внести, чтобы применить снимок без внезапного скачка?

Ответ №1:

К сожалению, инженеры Apple не могут должным образом решить эту проблему, начиная с iOS 6.

Короче говоря: вы не хотите, чтобы endRefreshing во время просмотра прокрутки isTracking . UIRefreshControl изменяет contentInset и contentOffset представление прокрутки, и это всегда вызывало такие скачки.

Если у вас где-либо есть состояние сетевого запроса или любой другой флаг, указывающий на то, что загрузка продолжается, вы можете просто сделать:

 @objc func doSomething(refreshControl: UIRefreshControl) {
    loading = true
    DispatchQueue.main.async {
        var dataSourceSnapshot = NSDiffableDataSourceSnapshot<Section, Item>()
        // add data
        dataSourceSnapshot.appendSections([.test])
        dataSourceSnapshot.appendItems([.test])
        self.dataSource.apply(dataSourceSnapshot)
        self.loading = false
        
    }
}

override func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
    if !loading amp;amp; collectionView.refreshControl!.isRefreshing {
        collectionView.refreshControl!.endRefreshing()
    }
}
 

Мне не совсем нравятся loading такие флаги, но это всего лишь пример. Надеюсь, у вас есть лучший источник истины, указывающий, продолжается ли еще какая-то «работа».

Я предполагаю, что может быть более приятный способ решения этой проблемы (путем исправления классов во время выполнения), но обычно для исследования требуется время. Интересно, удовлетворяет ли это решение вашим потребностям?