簡體   English   中英

UICollectionView 不會滾動到項目(在:IndexPath,在:位置)

[英]UICollectionView Won't scrollToItem(at: IndexPath, at: position)

我正在使用這種方法來滾動我的收藏視圖。

import UIKit
extension UICollectionView {
    func scrollToLast() {
        guard numberOfSections > 0 else {
            print("number of sections < 0")
            return
        }
        let lastSection = numberOfSections - 1
        guard numberOfItems(inSection: lastSection) > 0 else {
            print("number of items < 0")
            return
        }
        let lastItemIndexPath = IndexPath(item: numberOfItems(inSection: lastSection) - 1,
                                          section: lastSection)
        self.scrollToItem(at: lastItemIndexPath, at: .centeredVertically, animated: true)
        print("last Item (section, item #): \(lastItemIndexPath)")
    }
}

在視圖加載並且集合視圖中有項目之前,我不會調用此方法。 它之前一直在工作,直到我將 label 添加到我的單元原型中,現在雖然視圖看起來與新的 label 一樣,但使用此方法不會滾動任何內容。 我仍然可以手動滾動視圖。 注意:上述方法的output在調用該方法時正確列出了最后一個indexPath的最后一項。

我在控制台中有以下警告/錯誤,但它似乎與調用滾動時不一致,所以不確定它是否相關:

2019-11-04 06:01:13.017384-0800 AppName[17598:4494554] [CollectionView] 在 prepareLayout 調用(即重入調用)已在進行時准備布局的嘗試已被忽略。 請提交一個錯誤。 UICollectionView 實例為 (; layer =; contentOffset: {0, 0}; contentSize: {0, 0};adjustedContentInset: {0, 0, 0, 0}; layout: ; dataSource: appBundle.instance

我如何稱呼它的一個例子:(這是在 viewDidLoad 中)

DataService.instance.messageListener(roomId: room.id, { (result) in
        self.messageArr.append(result)
        self.messageArr = self.messageArr.sorted(by: { $0.date < $1.date})
        self.collection.reloadData()
        self.collection.scrollToLast()
        self.messageTextArea.text = ""
})

編輯:我已經刪除了對主隊列的所有調用,並且行為已經改變。 當 messageListener 方法被觸發時,視圖現在將滾動到集合視圖的頂部,但是當在其他地方使用相同的scrollToLast()方法時,視圖會滾動到它應該的最后一項 - 但只有視圖手動滾動到底部。 我也嘗試根據下面的答案將代碼移動到viewDidAppear ,但沒有任何效果。

這與您的問題無關,但我有一些建議:
1)調用self.scrollToItem之前不需要調用DispatchQueue.main.async,因為在DataService.instance.messageListener中已經切換到主線程。
2) messageArr 存在潛在的多線程問題,因為您從 DataService messageListener completionHandlers 線程中編輯了它(它可能在線程上)。 據我了解 messageArr 是您的集合視圖的數據源。 因此,當您滾動集合視圖或重新加載集合視圖時,collectionView 將從主線程訪問 messageArr。 這將導致崩潰或未定義的行為,因為您從兩個線程訪問 messageArr 數組而沒有鎖定。 解決方案之一是將整個 DataService.instance.messageListener 完成處理程序異步到主隊列。

    DataService.instance.messageListener(roomId: room.id, { (result) in
        DispatchQueue.main.async {
            self.messageArr.append(result)
            self.messageArr = self.messageArr.sorted(by: { $0.date < $1.date })
            self.collection.reloadData()
            self.collection.scrollToLast()
            self.messageTextArea.text = ""
        }
    })

當調用viewDidLoad時,所有視圖都將被加載,但我發現集合視圖和表視圖不一定已經加載了所有數據。 嘗試在viewWillAppearviewDidAppear中調用您的滾動方法。

我不確定為什么此方法不起作用,但我已將方法更改為滾動到內容視圖的底部而不是滾動到特定項目,這可以作為一種解決方法。 這不應該是這個問題的公認答案,所以我會保持打開狀態,以防有人可以解決原始問題。

這是解決方法:

extension UICollectionView {
    func scrollToBottomOfContent() {
        let contentHeight: CGFloat = self.contentSize.height
        let heightAfterInserts: CGFloat = self.frame.size.height - (self.contentInset.top + self.contentInset.bottom)
        if contentHeight > heightAfterInserts {
            self.setContentOffset(CGPoint(x: 0, y: self.contentSize.height - self.frame.size.height), animated: true)
        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM