简体   繁体   中英

Dynamically resizing an IOS tableview cells which have a textview embedded in swift

I have tried the following code which gives the correct textview frame height

func textViewDidChange(_ textView: UITextView) {

    myToDoList[keyArray[sect]]![row] = textView.text
    var frame = textView.frame
    frame.size.height = textView.contentSize.height
    textView.frame = frame
    print(frame)

    let indexPath = self.tableView.indexPathForView(textView)
    print(inputActive,indexPath)

    self.tableView.indexPathForView(inputActive)
    self.tableView.rowHeight = frame.size.height
}

The answer from "Krunal" is missing a piece or two...

Start with the cell layout / constraints:

在此处输入图片说明

And use this code:

import UIKit

class WithTextViewCell: UITableViewCell, UITextViewDelegate {

    @IBOutlet var theTextView: UITextView!

    var callBack: ((UITextView) -> ())?

    override func awakeFromNib() {
        super.awakeFromNib()
        // in case these were not set in IB
        theTextView.delegate = self
        theTextView.isScrollEnabled = false
    }

    func textViewDidChange(_ textView: UITextView) {
        // tell controller the text changed
        callBack?(textView)
    }

}

class TableWithTextViewTableViewController: UITableViewController {

    var cellData = [
        "UITableViewController implements the following behaviors:",
        "If a nib file is specified via the init(nibName:bundle:) method (which is declared by the superclass UIViewController), UITableViewController loads the table view archived in the nib file. Otherwise, it creates an unconfigured UITableView object with the correct dimensions and autoresize mask. You can access this view through the tableView property.",
        "If a nib file containing the table view is loaded, the data source and delegate become those objects defined in the nib file (if any). If no nib file is specified or if the nib file defines no data source or delegate, UITableViewController sets the data source and the delegate of the table view to self.",
        "When the table view is about to appear the first time it’s loaded, the table-view controller reloads the table view’s data. It also clears its selection (with or without animation, depending on the request) every time the table view is displayed. The UITableViewController class implements this in the superclass method viewWillAppear(_:). You can disable this behavior by changing the value in the clearsSelectionOnViewWillAppear property.",
        "When the table view has appeared, the controller flashes the table view’s scroll indicators. The UITableViewController class implements this in the superclass method viewDidAppear(_:).",
        "It implements the superclass method setEditing(_:animated:) so that if a user taps an Edit|Done button in the navigation bar, the controller toggles the edit mode of the table.",
        "You create a custom subclass of UITableViewController for each table view that you want to manage. When you initialize the controller in init(style:), you must specify the style of the table view (plain or grouped) that the controller is to manage. Because the initially created table view is without table dimensions (that is, number of sections and number of rows per section) or content, the table view’s data source and delegate—that is, the UITableViewController object itself—must provide the table dimensions, the cell content, and any desired configurations (as usual). You may override loadView() or any other superclass method, but if you do be sure to invoke the superclass implementation of the method, usually as the first method call.",
        ]

    override func viewDidLoad() {
        super.viewDidLoad()

        tableView.rowHeight = UITableViewAutomaticDimension
        tableView.estimatedRowHeight = 100

    }

    // MARK: - Table view data source
    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return cellData.count
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "WithTextViewCell", for: indexPath) as! WithTextViewCell

        // Configure the cell...
        cell.theTextView.text = cellData[indexPath.row]

        cell.callBack = {
            textView in
            // update data source
            self.cellData[indexPath.row] = textView.text
            // tell table view we're starting layout updates
            tableView.beginUpdates()
            // get current content offset
            var scOffset = tableView.contentOffset
            // get current text view height
            let tvHeight = textView.frame.size.height
            // telll text view to size itself
            textView.sizeToFit()
            // get the difference between previous height and new height (if word-wrap or newline change)
            let yDiff = textView.frame.size.height - tvHeight
            // adjust content offset
            scOffset.y += yDiff
            // update table content offset so edit caret is not covered by keyboard
            tableView.contentOffset = scOffset
            // tell table view to apply layout updates
            tableView.endUpdates()
        }

        return cell
    }

}

The "key" parts:

  1. Add a "call back" closure to your cell, so we can tell the controller when the text has changed.

  2. When the call back occurs, have the table view controller: update the dataSource with the edited text; tell the text view to resize itself; and adjust the content offset to avoid having the caret (the text insertion point) disappear behind the keyboard.

Its very easy to implement dynamic cell height when you design cell with interfaceBuilder directly as prototype cell or xib, where you just need to set top an bottom constraints properly and rest of the thing is done by tableViewAutoDimension.

override func viewDidLoad() {
  super.viewDidLoad()
  tableView.estimatedRowHeight = 50
  tableView.rowHeight = UITableViewAutomaticDimension
}

自动尺寸设计单元

Set UITextview height according to your content (text) size using sizeToFit and enable translatesAutoresizingMaskIntoConstraints in cellForRowAtIndexPath

Try this and see

class TextViewCell: UITableViewCell {

    @IBOutlet weak var textview: UITextView!


    func adjustTextViewHeight(textview : UITextView) {
        textview.translatesAutoresizingMaskIntoConstraints = true
        textview.sizeToFit()
        textview.isScrollEnabled = false
    }
}


class TableController: UIViewController, UITableViewDataSource, UITableViewDelegate {

    @IBOutlet weak var table: UITableView!


    override func viewDidLoad() {
        super.viewDidLoad()

        // Don't forget to set dataSource and delegate for table
        table.dataSource = self
        table.delegate = self

        // Set automatic dimensions for row height
        table.rowHeight = UITableViewAutomaticDimension
        table.estimatedRowHeight = UITableViewAutomaticDimension
    }



    // UITableViewAutomaticDimension calculates height of label contents/text
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return UITableViewAutomaticDimension
    }


    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 10
    }


    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "textview") as! TextViewCell
        cell.adjustTextViewHeight(textview: cell.textview)
        return cell
    }

}

Here is Storyboard Layout:

在此处输入图片说明

And here is result:

在此处输入图片说明

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM