Product frequently encountered UITableViewCell contains WebView requirements, also proposed several solutions, of course, more and more simple.

The old plan

Last year I came up with a solution that was perfect for calculating the height of loading UIWebView in a UITableViewCell, and here’s the idea:

  1. Get data to determine the number of cells and the initial height of the tableView.
  2. Refresh the tableView, fill each cell with content and initial height, assign the initial height to a cell variable, cellHeight, and load the webView.
  3. After the webView in cell I is loaded, its height h is calculated.
  4. Compare h with cellHeight. If the two heights are different, notify the tableView of the height h of the ith cell (i.e. the actual height of the webView in the cell) and call the following code to refresh the cell:
tableView.reloadRows(at: [IndexPath (row: i, section: 0)], with: .none)
Copy the code

If they are equal, OK, the ith cell is displayed correctly.

  1. Repeat 3.

A new scheme

Recently, I met this demand when I was making a new product. Originally, I wanted to copy the code directly from the previous project, but after reading it for a long time, I felt it was too tedious. In addition, I recently read some articles about the adaptive height of UITableViewCell, so I wanted to change the writing method.

In general, implementing UITableViewCell adaptive height does this:

  1. Set the UITableView adaptive Cell height
    tableView.estimatedRowHeight = 76
    tableView.rowHeight = UITableView.automaticDimension
Copy the code
  1. UITableViewCell sets the complete constraint from top to bottom
    questionWebView.snp.makeConstraints { (make) in
        make.edges.equalToSuperview().inset(UIEdgeInsets.init(top: 8, left: 16, bottom: 8, right: 16))
        make.height.equalTo(60)
    }
Copy the code

For a normal view, after these two steps you can achieve the adaptive height of the cell.

For a webView, however, the height of the webView is not fixed at the start of loading, so get its height and refresh the cell after the webView is loaded. This step eliminates the need to refresh the cell as in step4 of the old scenario.

First listen for webView loading:

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        tableView.separatorStyle = .none
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! ExerciseQuestionCell sets ExerciseQuestionCell. SetData (exerciseArray[indepath.row]) and listens for webView loading cell.questionWebView.delegate = self cell.selectionStyle = .nonereturn cell
    }
Copy the code

Gets the webView height.

func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {/ / when the webview loaded, calculation and refresh highly webview. EvaluateJavaScript ("document.body.scrollHeight") { (any, error) in// height is the height of the loaded webViewlet height = any as! Int
            
        }
    }
Copy the code

Adjust the height of the webView after obtaining the height:

func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {/ / when the webview loaded, calculation and refresh highly webview. EvaluateJavaScript ("document.body.scrollHeight") { (any, error) in// height is the height of the loaded webViewletheight = any as! Int / / height of the webView loadingWebView. SNP. UpdateConstraints {(make)inMake. Height. EqualTo (height)} / / refresh tableView exerciseTable. BeginUpdates () exerciseTable. EndUpdates ()}}Copy the code

That’s where the effect comes in

ExerciseQuestionCell’s setData(Exercise) method is called all the time. The setData method is as follows:

    func setData(_ exercise: Exercise) {
        do {
            let data = exercise.question.data(using: .utf8)
            let questionObject = try JSON.init(data: data!)
            let question = questionObject["question"].stringValue
            let questionHtml = DIV_HEAD + question + DIV_FOOT
            webView.loadHTMLString(htmlString, baseURL: nil)
        } catch {
            print(error)
        }
    }
Copy the code

SetData call webView.loadHTMLString method to loadHTML. After loading, refresh tableView…… ExerciseQuestionCell, so I’m putting a variable called loadedData inside ExerciseQuestionCell to record whether or not the cell is set to data, and if it is, it’s not set anymore:

    func setData(_ exercise: Exercise) {
        ifLoadedData {// Data is not set after setting, to prevent multiple refreshreturn
        }
        do {
            let data = exercise.question.data(using: .utf8)
            let questionObject = try JSON.init(data: data!)
            let question = questionObject["question"].stringValue
            let questionHtml = DIV_HEAD + question + DIV_FOOT
            questionWebView.loadHtmlString(questionHtml)
        } catch {
            print(error)
        }
        loadedData = true
    }
Copy the code

So it’s refreshing.