【问题标题】:UITableViewCell automatic height incorrect until I scrollUITableViewCell 自动高度不正确,直到我滚动
【发布时间】:2015-12-24 16:40:35
【问题描述】:

我正在尝试在我的 UIViewController 子类中的 UITableView 中显示新闻文章(我需要其中的一些其他视图,这就是我不使用 UITableViewController 的原因)

单元格应该是全宽和自动高度。

问题是可见单元格在第一次加载时没有正确的高度,因此它们根本无法正确显示,它们只有在我向下滚动后才变得正确大小(其他已经正确大小的单元格是) 并备份。

我尝试向 UITableView 和单元格添加 setNeedsUpdateConstraintsupdateConstraintslayoutSubviewslayoutIfNeeded 和其他类似方法的各种组合,但它根本没有任何效果。

我非常感谢任何帮助,因为我已经尝试解决这个问题很长时间了,但从未想出解决方案。

我的设置

我有 MyStoryCell 类型的自定义单元格,它存储在 .xib 文件中:

MyStoryCell.xib in Interface Builder

它的类如下所示:

class MyStoryCell: UITableViewCell
{
    // MARK: - Properties
    @IBOutlet weak var badgeView: UIImageView!
    @IBOutlet weak var thumbnailView: UIImageView!

    @IBOutlet weak var dateLabel: UILabel!
    @IBOutlet weak var taglineLabel: UILabel!
    @IBOutlet weak var titleLabel: UILabel!

    // MARK: - Methods
    func setTaglineText(text: String)
    {
        ....
    }

    func setTitleText(text: String)
    {
        ...
    }

    // MARK: - Overrides
    override func awakeFromNib() {
        super.awakeFromNib()
    }

    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
    }

    override func layoutSubviews() {
        super.layoutSubviews()

        if let image = self.thumbnailView?.image
        {
            // Using PureLayout
            self.thumbnailView?.autoSetDimension(.Height, toSize: (self.contentView.frame.width * image.size.height / image.size.width))
        }
    }
}

视图控制器(函数fetchTableData)从网络上拉取一些文章,将它们存储在一个数组中(currentStories),然后将它们全部添加到 UITableView 使用:

self.table.insertRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.None)

在视图控制器的 viewDidLoad 覆盖我有:

override func viewDidLoad()
{
    super.viewDidLoad()

    // Setting up table view
    table.delegate = self
    table.dataSource = self
    table.registerNib(UINib(nibName: "MyStoryCell", bundle: nil), forCellReuseIdentifier: "StoryCell")

    // Setting cells to automatic height
    table.estimatedRowHeight = 300
    table.rowHeight = UITableViewAutomaticDimension

    // ... some more code

    fetchTableData()
}

我的表格视图功能是:

func numberOfSectionsInTableView(tableView: UITableView) -> Int
{
    return 1
}

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
    return currentStories.count
}

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
    var cell: MyStoryCell? = tableView.dequeueReusableCellWithIdentifier("StoryCell", forIndexPath: indexPath) as? MyStoryCell
    if cell == nil
    {
        tableView.registerNib(UINib(nibName: "MyStoryCell", bundle: nil), forCellReuseIdentifier: "StoryCell")
        cell = tableView.dequeueReusableCellWithIdentifier("StoryCell", forIndexPath: indexPath) as? MyStoryCell
    }

    if currentStories.count >= indexPath.row + 1
    {
        let currentStory: Story = currentStories[indexPath.row]

        dispatch_async(get_user_queue()) {
            let badgeImage = codeToFetchBadgeImage

            dispatch_async(dispatch_get_main_queue(), {
                cell?.badgeView.image = badgeImage
            })

            let thumbnailImage = codeToFetchThumbnailImage

            dispatch_async(dispatch_get_main_queue(), {
                cell?.thumbnailView.image = thumbnailImage
            })
        }

        // Set labels
        cell?.dateLabel.text = currentStory.storyDate
        cell?.setTitleText(currentStory.storyTitle) // Attributed string
        cell?.setTaglineText(currentStory.storyTagline) // Attributed string
    }

    return cell!
}

fetchTableData 实现:

func fetchTableData()
{
    /* removed unnecessary code for displaying loading indicator etc. */
    stories = [Story]()
    currentStories = [Story]()

    table.reloadData()

    // Go through all the feeds
    for feed in 0...rss_urls.count-1
    {
        // Set url of the RSS feed
        var rss_url: NSURL = rss_urls[feed]

        // Try to download the RSS feed
        if var rss_data: NSData = NSData(contentsOfURL: rss_url)
        {
            // Initialize the XML Parser and set its delegate to self
            parser = NSXMLParser(data: rss_data)
            parser.delegate = self

            // Start parsing XML
            parser.parse()
        }
        else
        {
            alert_rss_error_show()
        }
    }

    // Sort by ID
    stories.sort{ $0.storyId.toInt() > $1.storyId.toInt() }
}

class DataManager {
    func requestData(offset:Int, size:Int, array:[Story], listener:([Story]) -> ()) {
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
            //generate items
            var arr:[Story] = []
            var limit = offset + size
            if limit >= stories.count
            {
                limit = stories.count - 1
            }
            if offset > limit
            {
                allLoaded = true
                return
            }
            // For each story
            for i in offset...limit {

                // Story for current index
                var currentStory: Story = stories[i]

                if let badgeUrl = currentStory.storyBadgeUrl
                {
                    if !badgeUrl.isEmpty
                    {
                        if let currentBadge = badgeCache[badgeUrl] { }
                        else
                        {
                            if let badgeData = NSData(contentsOfURL: NSURL(string: badgeUrl)!)
                            {
                                var image = UIImage(data: badgeData)
                                badgeCache[badgeUrl] = image
                            }
                        }
                    }
                }

                // If story has a thumbnail stored in cache, skip the next step
                if let currentThumbnail = thumbnailCache[currentStory.storyLink] { }
                else if !currentStory.storyThumbLink.isEmpty
                {
                    if let thumbnailData = NSData(contentsOfURL: NSURL(string: currentStory.storyThumbLink)!)
                    {
                        var image = UIImage(data: thumbnailData)
                        thumbnailCache[currentStory.storyLink] = image
                    }
                }
                arr.append(currentStory)
            }

            //call listener in main thread
            dispatch_async(dispatch_get_main_queue()) {
                listener(arr)
            }
        }
    }

    loadSegment(0, size: PageSize)
}

func loadSegment(offset:Int, size:Int) {
    if (!self.isLoading) {
        self.isLoading = true

        let manager = DataManager()
        manager.requestData(offset, size: size, array: currentStories,
            listener: {(items:[Story]) -> () in
                for item in items {
                    var row = currentStories.count
                    var indexPath = NSIndexPath(forRow:row,inSection:0)
                    currentStories.append(item)
                    self.table.insertRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.None)
                }
                self.isLoading = false
            }
        )
    }
}

【问题讨论】:

  • 你能展示一下 fetchTableData() 的实现吗?
  • @GaneshKamath 按要求添加了它
  • 酷,Jan Bureš。您是否尝试在 viewWillAppear 中调用 reloadData?
  • @GaneshKamath 我做了,但没有任何改变。我认为问题在于缩略图是异步加载的,但不知道如何解决这个问题
  • 是的。如果您提取的数据中有图像尺寸(或纵横比)以显示在表格中,则可以解决此问题。

标签: ios iphone swift uitableview autolayout


【解决方案1】:

将此函数从 UITableViewDelegate 协议添加到您的表视图函数中:

func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat{
    return 300.0
}

您的表格视图询问您每个单元格的高度是多少。如果您不回复,它将使用 NIB 文件中的那个。

有关这些功能的更多信息,您可以在此处查看 Apple 文档:

https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITableViewDelegate_Protocol/#//apple_ref/occ/intfm/UITableViewDelegate/tableView:heightForRowAtIndexPath:

【讨论】:

  • 对不起,我可能应该说得更清楚些;我需要细胞具有自动高度。此外,当我将此函数的返回值设置为 UITableViewAutomaticDimension 时,它会执行相同的操作 - 我必须向下滚动并向上滚动才能更新布局
  • @JanBureš 你的意思是单元格内的自动布局而不是单元格大小?单元格大小是否正确?
猜你喜欢
  • 1970-01-01
  • 2021-09-26
  • 2015-01-16
  • 2016-06-19
  • 1970-01-01
  • 2015-08-29
  • 1970-01-01
  • 2019-07-30
  • 1970-01-01
相关资源
最近更新 更多