Я пытаюсь реализовать бесконечную прокрутку w / IGListKit
.Я следовал их примеру кода, однако это простая текстовая ячейка.
Я использую ячейки с саморазмером для визуализации изображений.
Мои изображения кэшируются с использованием Kingfisher
.Я ожидал бы, что представление прокрутки сохранит свою позицию и добавит все новые элементы ниже, существенно увеличив область прокрутки.
Вместо этого, мой канал переходит обратно к первому элементу после добавления новых элементов.
Я посмеялся над задержкой сетевого вызова в моем методе scrollViewWillEndDragging
, добавив новые элементы в конец коллекции и вызвав adapter.performUpdates(animated: false)
при запуске коллекции didSet
.
модель, которую я рендеринг:
class FeedImage {
let id = UUID()
let url: URL
let width: CGFloat
let height: CGFloat
init(url: String, size: CGSize) {
self.url = URL(string: url)!
self.width = size.width
self.height = size.height
}
var heightForFeed: CGFloat {
let ratio = CGFloat(width) / CGFloat(height)
let height = (UIScreen.main.bounds.width - 32) / ratio
return height
}
}
extension FeedImage: ListDiffable {
func isEqual(toDiffableObject object: ListDiffable?) -> Bool {
if let object = object as? FeedImage {
return url == object.url
}
return false
}
func diffIdentifier() -> NSObjectProtocol {
return id as NSObjectProtocol
}
}
Вы можете увидеть поведение здесь.
ImageFeedViewController
class ImageFeedViewController: UIViewController {
let vOne = [
FeedImage(url: "https://pbs.twimg.com/media/D-D70C8W4AEtCav.jpg", size: .init(width: 1280, height: 1657)),
FeedImage(url: "https://pbs.twimg.com/media/D-DpfrbWsAI6KaC.jpg", size: .init(width: 911, height: 683)),
FeedImage(url: "https://pbs.twimg.com/media/D-EU-79W4AAlIk6.jpg", size: .init(width: 499, height: 644 )),
FeedImage(url: "https://pbs.twimg.com/media/D-ECq-dX4AA1U40.jpg", size: .init(width: 1035, height: 1132)),
]
var feed = [FeedImage]() {
didSet {
self.adapter.performUpdates(animated: false)
loading = false
}
}
var loading = false
var hasHadded = false // prevent mock pagination from firing over and over
private lazy var collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.estimatedItemSize = .init(width: view.frame.width, height: 10)
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.translatesAutoresizingMaskIntoConstraints = false
collectionView.alwaysBounceVertical = true
collectionView.backgroundColor = .darkGray
return collectionView
}()
private lazy var adapter: ListAdapter = {
return ListAdapter(
updater: ListAdapterUpdater(),
viewController: self,
workingRangeSize: 0)
}()
override func viewDidLoad() {
super.viewDidLoad()
adapter.collectionView = collectionView
adapter.dataSource = self
adapter.scrollViewDelegate = self
view.addSubview(collectionView)
NSLayoutConstraint.activate([
collectionView.topAnchor.constraint(equalTo: view.topAnchor),
collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
collectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor)
])
DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) {
self.feed = self.vOne
}
}
}
extension ImageFeedViewController: ListAdapterDataSource {
func objects(for listAdapter: ListAdapter) -> [ListDiffable] {
return feed as [ListDiffable]
}
func listAdapter(_ listAdapter: ListAdapter, sectionControllerFor object: Any) -> ListSectionController {
return ImageSectionController()
}
func emptyView(for listAdapter: ListAdapter) -> UIView? {
return nil
}
}
extension ImageFeedViewController: UIScrollViewDelegate {
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
let distance = scrollView.contentSize.height - (targetContentOffset.pointee.y + scrollView.bounds.height)
if distance < 200 && !loading && !hasHadded {
loading = true
hasHadded = true
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
self.feed.append(contentsOf: [
FeedImage(url: "https://pbs.twimg.com/media/D-EL1DNXYAAMv1R.jpg", size: .init(width: 500, height: 616)),
FeedImage(url: "https://pbs.twimg.com/media/D-EHQDcWwAUImah.jpg", size: .init(width: 800, height: 592)),
FeedImage(url: "https://pbs.twimg.com/tweet_video_thumb/D-EZkIkXUAEQwHC.jpg", size: .init(width: 500, height: 280)),
])
}
}
}
}
ImageSectionController
class ImageSectionController: ListSectionController {
var image: FeedImage!
override func numberOfItems() -> Int {
return 1
}
override func sizeForItem(at index: Int) -> CGSize {
return .init(width: collectionContext!.containerSize.width, height: 1)
}
override func cellForItem(at index: Int) -> UICollectionViewCell {
let cell = collectionContext?.dequeueReusableCell(of: CustomCellTwo.self, for: self, at: index) as! CustomCellTwo
cell.render(model: image)
return cell
}
override func didUpdate(to object: Any) {
image = object as? FeedImage
}
}
CustomCellTwo
class CustomCellTwo: UICollectionViewCell {
private lazy var width: NSLayoutConstraint = {
let width = contentView.widthAnchor.constraint(equalToConstant: bounds.size.width)
width.isActive = true
return width
}()
var imageBodyBottomAnchor: NSLayoutConstraint!
var imageHeightAnchor: NSLayoutConstraint!
let image = UIImageView(frame: .zero)
lazy var imageHeight: CGFloat = 0
override init(frame: CGRect) {
super.init(frame: frame)
imageHeightAnchor = image.heightAnchor.constraint(equalToConstant: 0)
imageHeightAnchor.isActive = true
}
required init?(coder aDecoder: NSCoder) {
return nil
}
override func prepareForReuse() {
super.prepareForReuse()
image.kf.cancelDownloadTask()
}
override func systemLayoutSizeFitting(_ targetSize: CGSize, withHorizontalFittingPriority horizontalFittingPriority: UILayoutPriority, verticalFittingPriority: UILayoutPriority) -> CGSize {
width.constant = bounds.size.width
return contentView.systemLayoutSizeFitting(CGSize(width: targetSize.width, height: 1))
}
func render(model: FeedImage) {
image.translatesAutoresizingMaskIntoConstraints = false
imageHeightAnchor.constant = model.heightForFeed
image.kf.setImage(with: model.url)
contentView.addSubview(image)
NSLayoutConstraint.activate([
image.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 16),
image.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16),
image.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -16)
])
if let lastSubview = contentView.subviews.last {
imageBodyBottomAnchor = contentView.bottomAnchor.constraint(equalTo: lastSubview.bottomAnchor, constant: 0)
imageBodyBottomAnchor.priority = .init(999)
imageBodyBottomAnchor.isActive = true
}
}
}