Cell高度自适应的问题真多。如今,若是内部有webView,内容动态装入,大小也是各不相同的,而且高度必须根据内容,而不是view自己的高度来适应,怎么办呢?特别是若是有多个webView的状况下。
这样就能够了:html
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
window?.makeKeyAndVisible()
window?.rootViewController = TableViewController()
return true
}
}
class Cell:UITableViewCell{
var webView = UIWebView()
override func layoutSubviews() {
self.contentView.addSubview(webView)
}
}
class TableViewController: UITableViewController, UIWebViewDelegate {
fileprivate let reuserId = "BookTableViewCellIdentifier"
override func viewDidLoad() {
self.tableView.register(Cell.self, forCellReuseIdentifier: reuserId)
}
var content : [String] = ["test1<br>test1<br>test1<br>test1<br>", "test22<br>test22<br>test22<br>test22<br>test22<br>test22"]
var contentHeights : [CGFloat] = [0.0, 0.0]
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return content.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: reuserId, for: indexPath) as! Cell
let htmlString = content[indexPath.row]
var htmlHeight = contentHeights[indexPath.row]
if htmlHeight == 0.0{
htmlHeight = 100
}
cell.webView.tag = indexPath.row
cell.webView.delegate = self
cell.webView.loadHTMLString(htmlString, baseURL: nil)
cell.webView.frame = CGRect(x:10, y:0, width:cell.frame.size.width, height:htmlHeight)
return cell
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat{
return contentHeights[indexPath.row]
}
func webViewDidFinishLoad(_ webView: UIWebView)
{
if (contentHeights[webView.tag] != 0.0)
{
// we already know height, no need to reload cell
return
}
contentHeights[webView.tag] = webView.scrollView.contentSize.height
print(contentHeights)
tableView.reloadRows(at: [IndexPath(row: webView.tag, section:0)], with: .automatic)
}
}复制代码
首先webview只有装入内容完成,才知道内容的高度的,所以须要经过委托,监听事件webViewDidFinishLoad,在此处得到高度。web
其次,多个webview会须要在一个事件内监听,所以,必须区别它们,代码中采用了webview.tag属性,赋值为此webview的cell的indexPath,把它记录到高度数组内。若是数组内的高度有值了,那么就没必要在写入了。swift
最后,tableView是能够局部刷新的,那个高度变了就从新装入那个cell,作法就是使用reloadRows方法便可。数组
此案例的好处是简单,能够用来讲明问题,可是明显存在着适应性问题,好比webview.tag内存储的是indexPath.row,而不是indexPath,那么在有多个section的TableView时,此代码就没法完成功能了。接下来的代码会更有通用性:bash
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
window?.makeKeyAndVisible()
window?.rootViewController = TableViewController()
return true
}
}
class Cell:UITableViewCell{
var title = UILabel()
var webView = TJWeb()
override func layoutSubviews() {
self.contentView.addSubview(webView)
self.contentView.addSubview(title)
// layout code
let view2 = webView
let view1 = title
let view = self.contentView
view2.translatesAutoresizingMaskIntoConstraints = false
view1.translatesAutoresizingMaskIntoConstraints = false
let views = ["view1":view1,"view2":view2]
let hConstraint1=NSLayoutConstraint.constraints(withVisualFormat: "H:|-[view1]-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: views)
view.addConstraints(hConstraint1)
let hConstraint2=NSLayoutConstraint.constraints(withVisualFormat: "H:|-[view2]-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: views)
view.addConstraints(hConstraint2)
let vConstraint1=NSLayoutConstraint.constraints(withVisualFormat: "V:|-5-[view1]-5-[view2]-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: views)
view.addConstraints(vConstraint1)
}
}
class TJWeb : UIWebView,UIWebViewDelegate{
var indexPath : IndexPath!
override func layoutSubviews() {
isUserInteractionEnabled = false
}
}
class Item {
init(_ title : String?,_ content : String?){
self.title = title
self.content = content
}
var title : String?
var content : String?
}
var data = [
Item("1","test1<br>test1<br>test1<br>test1<br>"),
Item("2","test22<br>test22<br>test22<br>test22<br>test22<br>test22"),
Item("3","test22<br>test22<br>test22<br>test22<br>test22<br>test22"),
Item("4","test22<br>test22<br>test22<br>test22<br>test22<br>test22"),
Item("5","test22<br>test22<br>test22<br>test22<br>test22<br>test22"),
Item("6","test22<br>test22<br>test22<br>test22<br>test22<br>test22"),
]
class TableViewController: UITableViewController, UIWebViewDelegate
{
fileprivate let reuserId = "BookTableViewCellIdentifier"
override func viewDidLoad() {
self.tableView.register(Cell.self, forCellReuseIdentifier: reuserId)
}
var contentHeights : [IndexPath:CGFloat] = [:]
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: reuserId, for: indexPath) as! Cell
let htmlString = data[indexPath.row].content
var htmlHeight = contentHeights[indexPath]
if htmlHeight == nil{
htmlHeight = 100
}
cell.webView.indexPath = indexPath
cell.webView.delegate = self
cell.webView.loadHTMLString(htmlString!, baseURL: nil)
cell.title.text = data[indexPath.row].title
cell.title.backgroundColor = .blue
// layout section
// cell.webView.frame = CGRect(x:0.0, y:webTop, width:cell.frame.size.width, height:htmlHeight!)
// cell.title.frame = CGRect(x:0.0, y: 5.0 , width:cell.frame.size.width, height:titleHeight)
return cell
}
let fixWidth : CGFloat = 30
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat{
if contentHeights[indexPath] != nil {
return contentHeights[indexPath]! + fixWidth
}
return 44
}
func webViewDidFinishLoad(_ webView: UIWebView)
{
let web = webView as! TJWeb
if (contentHeights[web.indexPath] != nil)
{
// we already know height, no need to reload cell
return
}
contentHeights[web.indexPath] = webView.scrollView.contentSize.height
print(contentHeights)
tableView.reloadRows(at: [web.indexPath], with: .automatic)
}
}复制代码
要点在于,传入cell的webview是子类化的了,新的类内有一个属性,能够用来存在此webview所在的cell的indexPath。app
还有就是,webview高度一旦肯定,就会从新装入对应的cell,并刷新此cell的高度,而webview的高度,使用了布局技术,让它能够跟随cell高度而伴随增大。这样就没必要本身计算视图的frame了。ide