Ios UITableView添加WebView和ImageView单元格

Ios UITableView添加WebView和ImageView单元格,ios,swift,uitableview,webview,Ios,Swift,Uitableview,Webview,我需要以编程方式向UITableView添加两种不同类型的单元格。这些单元格的内容直到运行时才知道。第一种类型是HTML格式的字符串,第二种类型是图像。这些细胞可以是任意组合,并且可以以任意顺序出现 在IB中,我设置了两个原型单元,一个id为“htmlCell”,另一个id为“imageCell”。以下是相关代码: public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UI

我需要以编程方式向UITableView添加两种不同类型的单元格。这些单元格的内容直到运行时才知道。第一种类型是HTML格式的字符串,第二种类型是图像。这些细胞可以是任意组合,并且可以以任意顺序出现

在IB中,我设置了两个原型单元,一个id为“htmlCell”,另一个id为“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之后。只是猜测而已

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


有人知道我如何使这些视图按正确的顺序着陆吗?谢谢。

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

如果在IB中定义了原型单元,并且tableView已正确链接到xib或故事板文件,则应将单元出列,而不是构建它们

试试这个:

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…
add后:

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内容


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

非常感谢。这真的很有帮助。我的第一个Swift项目进展有点慢。不能告诉你我有多感激你。