UITableView添加WebView和ImageView Cells

时间:2017-09-06 23:32:05

标签: ios swift uitableview webview

我需要以编程方式将两种不同类型的单元格添加到我的UITableView中。直到运行时才知道这些单元格的内容。第一种类型是HTML格式的字符串,第二种是图像。可以存在这些细胞的任何组合,它们可以以任何顺序发生。

在IB中,我设置了两个原型单元格,一个是id'htmlCell',另一个是'imageCell'。以下是相关代码:

public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        var cell = UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: "htmlCell")
        let thisSection = self.sections[indexPath.row]

        if thisSection.type! == "html" {


            let htmlString = thisSection.text
            let htmlHeight = contentHeights[indexPath.row]
            let webView:UIWebView = UIWebView(frame: CGRect(x:0, y:0, width:cell.frame.size.width, height:htmlHeight))
            cell.addSubview(webView)
            webView.tag = indexPath.row
            webView.scrollView.isScrollEnabled = false
            webView.isUserInteractionEnabled = false
            webView.delegate = self
            webView.loadHTMLString(htmlString!, baseURL: nil)

        } else if thisSection.type! == "image" {
            cell = UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: "imageCell")
            let imageName = "logo"
            let image = UIImage(named: imageName)
            let imageView = UIImageView(image: image)

            imageView.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width-20, height: 200)
            cell.addSubview(imageView)
            return cell

        }

        return cell
    }

    func webViewDidFinishLoad(_ webView: UIWebView) {
        if (contentHeights[webView.tag] != 0.0) {
            // we already know height, no need to reload cell
            return
        }

        let strHeight = webView.stringByEvaluatingJavaScript(from: "document.body.scrollHeight")
        contentHeights[webView.tag] = CGFloat(Float(strHeight!)!)
        tableView.reloadRows(at: [NSIndexPath(item: webView.tag, section: 0) as IndexPath], with: UITableViewRowAnimation.automatic)
    }

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return self.contentHeights[indexPath.row]
    }

内容加载,但有点乱。这是一个提供示例的屏幕截图。在这种情况下,图像应出现在两个webview之间。但正如您所看到的,图像直接落在第二个webview的顶部,两个顶部边框对齐。

另外,当我点击图像时,它会完全消失。我假设它落后于第二个webview。只是一个猜测。

enter image description here

我正在使用的CGRects目前有一些任意的宽度和高度。我怀疑这是问题的一部分所在。最后,无论webview内容的真实高度如何,webViewDidFinishLoad始终返回667.0的高度。

任何人都知道如何让这些观点以正确的顺序着陆?谢谢。

1 个答案:

答案 0 :(得分:1)

这里有很多潜在的问题,让我们解决其中的一些问题,看看你是否会这样做:)

如果您在IB中定义了原型单元格并且tableView已正确链接到xib或storyboard文件,那么您应该将单元格出列而不是构造它们。

试试这个:

public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let cell: UITableViewCell //declare but don't assign yet. Use let because after we assign once, we wont be reassigning.
    ...

    if thisSection.type! == "html" {
        cell = tableView.dequeueReusableCell(withIdentifier: "htmlCell", for: indexPath)
        ...

    } else if thisSection.type! == "image" {
        cell = tableView.dequeueReusableCell(withIdentifier: "imageCell", for: indexPath)
        ...

    }

    return cell
}

注意,我们在顶级范围内声明并返回单元格,并仅在我们知道它将是什么类型时分配单元格。现在您已经出列,这些单元格将在适当时重复使用,并减少用户滚动制作应用程序时所分配的数量。

接下来,由于您要向单元格添加子视图,因此每次出列单元格时都需要清除子视图。这需要一些额外的代码,但从长远来看会使事情变得更加清洁。

每次致电dequeueReusableCell...后添加:

cell.contentView.subviews.forEach({ $0.removeFromSuperview() })

到目前为止一切顺利。你已经让细胞干净利落,但现在我们需要确保正确设置细胞。

首先,html单元格: 删除行:

let htmlHeight = contentHeights[indexPath.row]

tableView最终负责调整单元格的大小,内容将占用单元格的全部大小。用这个代替接下来的两行:

let webView = UIWebView(frame: cell.contentView.bounds)
webView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
cell.contentView.addSubview(webView)

自动调整大小确保如果单元格的内容视图大小发生更改,Web视图也会调整大小。由于内容视图由iOS管理,因此webview将始终是tableview的宽度,高度将是您在委托方法heightForRow中提供的任何内容。另请注意,我们从不直接将子视图添加到单元格中,始终使用它的contentView。

接下来,我们将对imageCell执行相同的操作:

let image = UIImage(named: "logo")
let imageView = UIImageView(frame: cell.contentView.bounds)
imageView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
imageView.contentMode = .aspectFit //this makes sure the image take ups the full size of the image view, but no more. and this keeps the image's aspect ratio. Adjust this to other content modes if necessary.
imageView.image = image
cell.contentView.addSubview(imageView)

好的,现在我们正在设置正在设置的单元格,并将尺寸排除在等式之外。因此,让我们在适当的地方进行调整:

您在构建此项目时面临的最大挑战是如何正确地提升细胞高度。由于图像在你的包中,你一旦实例化UIImage就会知道它们的大小,但是我们不希望这样做超过绝对必要。您可能希望稍后提出一种更高效的方法,但是现在我们将创建一个UIImage并获得它的高度:

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    if thisSection.type! == "html" {
        return self.contentHeights[indexPath.row]
    } else if thisSection.type! == "image" {
        let image = UIImage(named: "logo")
        let imageHeight = (image.size.height * tableView.bounds.size.width) / image.size.width // The proportional size of the image stretched to the table view's width
        return imageHeight
    }
}

您计算Web视图高度和重新加载单元格的方法可能有效,但对用户来说可能会显得很笨拙。此时我的建议是返回Web内容的固定高度。当用户点击Web单元格时,您可以使用可显示所有内容的Web视图来推送新的视图控制器。否则,您可以尝试让所有html生成大小相同的Web内容。

好的,这很长,但希望能让你有个好的开始:)如果你需要更多的澄清,我很乐意跟进。