如何实现一种方法,在调用时,表格视图单元格的高度会发生变化?

时间:2016-06-18 09:26:51

标签: ios swift uitableview

我想实现一个看起来像这样的方法:

setCellHeightForIndexPath(someIndexPath, 80)

然后该索引路径的表格视图单元格突然高度为80。

我想这样做的原因是因为我希望在完成加载HTML后,将单元格的高度设置为Web视图内容的高度。由于我只能在完成加载后获取网页视图的内容大小,因此我不能立即设置单元格高度。

有关详细信息,请参阅此question

因此,在webViewDidFinishLoad方法中,我可以获取Web视图的内容高度,将Web视图的高度设置为该高度,并调用此方法来设置单元格的高度。

看起来细胞高度只能在调用heightForRowAtIndexPath时改变。我认为该方法将使用与my answer to this question类似的方法。我想我需要存储一系列高度?我只是想不出一种实现这个的方法!

我该如何实现这样的方法?

注意:不要告诉我这是不可能的。在Instagram应用程序中,我可以看到具有不同高度的不同图像完美地适合表格视图单元格。这些图像与我的网络视图类似。他们都需要时间来加载。

编辑:

让我展示一下我的一些尝试:

var results: [Entry] = []
var cellHeights: [CGFloat] = []
var webViews: [UIWebView] = []

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

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

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("resultCell")
    let webView = cell!.contentView.viewWithTag(1) as! UIWebView
    webView.loadHTMLString(results[indexPath.row].htmlDescriptionForSearchMode(.TitleOnly), baseURL: nil)
    webView.delegate = self
    webView.scrollView.scrollEnabled = false
    webViews.append(webView)
    cellHeights.append(400)

    webView.stringByEvaluatingJavaScriptFromString("highlightSearch(\"day\")")

    return cell!
}

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return indexPath.row < cellHeights.count ? cellHeights[indexPath.row] : 400
}

func webViewDidFinishLoad(webView: UIWebView) {
    let height = CGFloat(webView.stringByEvaluatingJavaScriptFromString("document.height")!.toFloat()!)
    webView.frame = CGRect(origin: webView.frame.origin, size: CGSizeMake(webView.frame.width, height))
    print(height)
    if let index = webViews.indexesOf(webView).first {
        cellHeights[index] = height
        tableView.beginUpdates()
        tableView.reloadRowsAtIndexPaths([NSIndexPath(forRow: index, inSection: 0)], withRowAnimation: .None)
        tableView.endUpdates()
    }
}

results是我想要在网络视图中显示的内容。 cellHeights用于存储每个单元格的高度。我将所有网络视图都放入webViews数组中,以便我可以在indexOf中调用webViewDidFinishLoad来确定加载了哪个网络视图。

编辑:

所以我在我的表视图控制器中编写了这段代码,并参考了Andre的答案:

class SearchResultsController: UITableViewController, UIWebViewDelegate {
    var entries: [Entry] = []
    lazy var results: [Result] = {
        return self.entries.map { Result(entry: $0) }
    }()
    var cellHeights: [CGFloat] = []

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

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

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let result = results[indexPath.section]
        var cell = result.cell
        if cell == nil {
            print("cellForRow called")

            cell = tableView.dequeueReusableCellWithIdentifier("resultCell") as! ResultCell
            cell.webView.delegate = self
            print(cell == nil)

            print("loading \(result.entry.title)...")
            cell.webView.loadHTMLString(result.entry.htmlDescriptionForSearchMode(.TitleOnly), baseURL: nil)

            result.cell = cell
        }

        return cell
    }

    override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
        return indexPath.row < cellHeights.count ? cellHeights[indexPath.row] : 400
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        tableView.estimatedRowHeight = 169
        tableView.rowHeight = UITableViewAutomaticDimension

        tableView.tableFooterView = UIView()
    }

    func webViewDidFinishLoad(webView: UIWebView) {
        print("didFinishLoad called")

        if webView.loading {
            return
        }

        guard let cell = webView.superview?.superview as? ResultCell else {
            print("could not get cell")
            return
        }

        guard let index = results.map({$0.cell}).indexOf(cell) else {
            print("could not get index")
            return
        }

        let result = results[index]
        print("finished loading \(result.entry.title)...")

        guard let heightString = webView.stringByEvaluatingJavaScriptFromString("document.height") else {
            print("could not get heightString")
            return
        }

        guard let contentHeight = Float(heightString) else {
            print("could not convert heightString")
            return
        }

        cell.webViewHeightConstraint.constant = CGFloat(contentHeight)
        tableView.beginUpdates()
        tableView.endUpdates()
    }

}

class ResultCell: UITableViewCell {
    @IBOutlet weak var webView: UIWebView!
    @IBOutlet weak var webViewHeightConstraint: NSLayoutConstraint!
}

class Result {
    let entry: Entry
    var contentHeight: Float?
    var cell: ResultCell!

    init(entry: Entry) {
        self.entry = entry
    }
}

3 个答案:

答案 0 :(得分:2)

你不能推动&#34;将新单元格高度放到表格视图上。相反,你需要制作表格视图&#34; pull&#34;来自heightForRowAtIndexPath的新高度,并准备好提供新的高度。

当行r的单元格加载完成时,您需要更新模型,使其知道行r的新高度。之后,您需要告诉您的表视图重新加载自己,如下所示:

tableView.beginUpdates()
tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.None)
tableView.endUpdates()

这将开始更新您的单元格的过程。 heightForRowAtIndexPath将被调用。您的代码将返回新的高度。之后将调用cellForRowAtIndexPath。您的代码应准备好返回已完成加载的单元格,而不会启动新的数据加载。

答案 1 :(得分:1)

我尝试使用自动自动布局和自动单元格高度计算来实现它。

也许有助于指出正确的方向: https://github.com/andreslotta/WebViewCellHeight

只是摘录:

func webViewDidFinishLoad(webView: UIWebView) {
    if webView.loading {
        return
    }

    guard let cell = webView.superview?.superview as? WebViewCell else {
        print("could not get cell")
        return
    }

    guard let index = websites.map({$0.cell}).indexOf(cell) else {
        print("could not get index")
        return
    }

    // get website
    let website = websites[index]
    print("finished loading \(website.urlString)...")

    // get contentheight from webview
    guard let heightString = webView.stringByEvaluatingJavaScriptFromString("document.height") else {
        print("could not get heightString")
        return
    }

    guard let contentHeight = Float(heightString) else {
        print("could not convert heightString")
        return
    }

    cell.webViewHeightConstraint.constant = CGFloat(contentHeight)
    tableView.beginUpdates()
    tableView.endUpdates()
}

答案 2 :(得分:0)

您可以像这样实施

将一个全局CGFloat用于高度和一个索引路径 现在当你需要更改高度时设置两个值并使用

[self.yourTableview beginUpdate] [self.yourTableview endUpdate]

将更新您的手机

并且在cellForRowAtIndexPath中你应该使用dequeueReusableCellWithIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)来确保你每次都有更新的单元格

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {

     if (indexPath == yourIndexpath) {

        return gloablVariable;
    } else {
        return defauleHeight
    }
 }

希望有所帮助