簡體   English   中英

UIImageView最初不會在UITableViewCell中顯示圖像

[英]UIImageView does not initially display image in UITableViewCell

我有一個UITableView從服務加載圖像。 它使用NSURLSession.sharedSession().dataTaskWithURL獲取URL並下載圖像NSURLSession.sharedSession().dataTaskWithURL

NSURLSession.sharedSession().dataTaskWithURL(url, completionHandler: { (data, _, error) -> Void in
                            guard
                                let data = data where error == nil,
                                let image = UIImage(data: data)
                                else {
                                    print(error?.localizedDescription)
                                    return
                            }
                            dispatch_async(dispatch_get_main_queue()) {
                                [unowned self] in
                                self.pictureView.image = image
                                self.pictureView.layoutIfNeeded()
                            }
                        }).resume()

UIImageView是故事板場景的出口。 UIImageView內容模式是Aspect Fit。

用於可見單元格的UIImageView最初顯示為空(無圖像),即使我已確認已設置圖像。 直到單元格在屏幕上滾動,單元格才會重繪(?)並顯示圖像。

所以這似乎是某種時間問題,但我無法弄明白。 在設置映像后,我嘗試在dispatch_async塊中調用以下所有內容:

self.pictureView.setNeedsDisplay()
self.pictureView.setNeedsUpdateConstraints()
self.pictureView.setNeedsLayout()
self.pictureView.reloadInputViews()

這些都沒有解決問題。 是什么導致此圖像僅在單元格滾出/進入視圖后顯示?

編輯:可能需要注意的是,這是在筆尖和相關類中發生的。 筆尖被加載,然后我開始下載。 我想知道筆尖是否自行放置,當我的圖像下載並在UIImageView上設置時,布局傳遞已經完成。 然后通過在屏幕上移動單元格(包含筆尖),單元格再次執行布局,並且所有內容都正確顯示。 只是一個猜測,我仍然堅持這一點。

編輯2:進一步澄清過程:

1)我的UIViewController包含一個UITableView

2)此UITableView從名為PostCell的自定義UITableViewCell類加載單元格。

3)PostCell的全部內容是從名為PostView(帶有PostView類)的筆尖加載的單個視圖。 在initCell中的init:style:reuseIdentifier期間發生了這種加載:

postView = NSBundle.mainBundle().loadNibNamed("PostView", owner: self, options: nil).first as? PostView

4)然后我在postView上設置一個Post對象:

postView.post = Post

請注意,這是在PostView上調用awakeFromNib()之后發生的。

5)PostView上的post屬性有一個didSet觀察者,它根據post對象中的URL(上面的代碼)啟動圖像下載。 下載圖像並在名為pictureViewUIImageView上設置。

編輯3:

這是tableView(_:cellForRowAtIndexPath:)的代碼:

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

    var cell = tableView.dequeueReusableCellWithIdentifier(postCellIdentifier) as? PostCell

        if cell == nil {
           cell = PostCell()
        }

        if let postCell = cell,
            let postArray = postArray,
            let post = postArray[indexPath.row] {
            postCell.post = post
            return postCell
        }

        // This section is hit during a refresh.
        let emptyCell = UITableViewCell()
        emptyCell.contentView.backgroundColor = .whiteColor()
        return emptyCell

    }

編輯4:

我發現如果我通過在筆尖中預先設置占位符圖像來“ UIImageViewUIImageView ,然后將我的圖像加載到UIImageView ,圖像將顯示在占位符的高度。 當我將該單元格從屏幕拉出然后再次打開時, UIImageView將使用筆尖中的約束設置以正確的大小繪制圖像。

因此,看起來UIImageView的約束和大小是在圖像加載時設置的,並且將其拉出/關閉會導致重新繪制某種類型,從而正確調整圖像大小。 如果我能以編程方式觸發重繪它會有所幫助,但請參閱上面我已經嘗試過的內容。

編輯6:

這是在行動。 請注意,我在筆尖中設置了占位符圖像。 這似乎導致圖像在最初加載時顯示,但在占位符的維度上顯示。 在屏幕外滾動它會導致調整大小,然后正確顯示。 在此輸入圖像描述

編輯7:

我在我的應用程序的其他地方使用PostView nib沒有問題。 加載時,圖像大小正確。 問題似乎只出現在nib嵌入在UITableViewCell

編輯8:

我找到了這個問題的根本原因,在我的UIViewController viewDidLoad中調用:

tableView.estimatedRowHeight = 500
tableView.rowHeight = UITableViewAutomaticDimension

使用自動尺寸會導致初始錯誤的行高。 出於某種原因,將單元格滾動到視圖中會正確地重新計算行高,並且圖像顯示在正確的高度。 刪除此代碼將顯示圖像,但行高不會從自動高度計算中受益。 自動計算行高的最佳方法是什么,仍然可以避免這個問題?

你可以嘗試這個擴展:

extension UIImageView {
    func downloadedFrom(link link:String, contentMode mode: UIViewContentMode) {
        guard
            let url = NSURL(string: link)
            else {return}
        contentMode = mode
        NSURLSession.sharedSession().dataTaskWithURL(url, completionHandler: { (data, response, error) -> Void in
            guard
                let httpURLResponse = response as? NSHTTPURLResponse where httpURLResponse.statusCode == 200,
                let mimeType = response?.MIMEType where mimeType.hasPrefix("image"),
                let data = data where error == nil,
                let image = UIImage(data: data)
                else { return }
            dispatch_async(dispatch_get_main_queue()) { () -> Void in
                self.image = image
            }
        }).resume()
    }
}

然后你可以把這條線放在你想要的任何地方

cell.cellPhoto.downloadedFrom(link: "customImageUrl", contentMode: .ScaleAspectFit) //Try changing contentMode

將表格視圖的單元格出列后,單元格和表格視圖的寬度可能不同 此時您的單元格尚未正確調整大小。 因此,從表視圖中出列后,請更改此代碼:

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    ...
    if let postCell = cell,
        let postArray = postArray,
        let post = postArray[indexPath.row] {

           // set the post with image after the cell is sized correctly 
           dispatch_async(dispatch_get_main_queue()) {
              postCell.post = post
           }
        return postCell
    }

確保已在單元格nib文件中正確設置約束。

我建議在控制器viewDidLoad方法中使用registerNib方法:

tableView?.registerNib(UINib(nibName: "PostCellName", bundle: NSBundle.mainBundle()), forCellReuseIdentifier: postCellIdentifier)

你見過WWDC 2014 Session 226嗎? 視頻可能會對您的問題有所了解。

在WWDC會話中,他們使用self.tableView.estimatedRowHeight = 100.0; 你已經完成了 ✅然后他們說你不需要任何來自表視圖控制器的虛擬原型單元。

問題是當故事板加載表視圖時,它將rowHeight屬性設置為xib / interface builder中的值。 要使用自動調整大小單元,您需要設置estimatedRowHeight並將rowHeight保留為默認值 - UITableViewAutomaticDimension 你做過 )✅

self.tableView.rowHeight = UITableViewAutomaticDimension

⚠️新問題是,在你有一個真正的行高之前,第一個單元格會加載。 訣竅可能是在視圖顯示時強制重新加載表格?

[super viewDidAppear:animated]
[self.tableView reloadData]

如果這不起作用,那么你可能會無意中在一些導致它無法正確調整大小的內容上設置一個顯式的 contentWidth / Height

下載完成后,您需要重新加載tableview數據。 嘗試在dispatch_async塊中調用self.tableview.reloadData()

此外,如果您想異步下載URL中的圖像,我建議使用Kingfisher

在查看編輯過程(當前8個)和響應者的更新之后,似乎您在init方法中遇到了導致此處提到的init錯誤的相同錯誤。

應該通過注冊筆尖給予Prcela正確的信譽,但下面提供了一個更優雅的解決方案:

在nib文件中創建自定義表格視圖單元格的最簡單方法(自iOS 5.0起可用)是在表格視圖控制器中使用registerNib:forCellReuseIdentifier :. 最大的優點是dequeueReusableCellWithIdentifier:然后在必要時自動從nib文件中實例化一個單元格。 你不再需要if(cell == nil)... part。

viewDidLoad下的表視圖控制器中

[self.tableView registerNib:[UINib nibWithNibName:@"CueTableCell" bundle:nil] forCellReuseIdentifier:@"CueTableCell"];

cellForRowAtIndexPath添加

CueTableCell *cell = [tableView dequeueReusableCellWithIdentifier:@"CueTableCell"];
// setup cell
return cell;

從nib文件加載的單元格使用initWithCoder進行實例化,如有必要,可以在子類中覆蓋它。 要修改UI元素,您應該覆蓋awakeFromNib(不要忘記調用“super”)。

我希望我能為這樣一個優雅的解決方案而受到贊譽,但這個功勞屬於同一篇文章中的Martin R.

暫無
暫無

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

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