ios - 当UITextView的文本超出1行时展开UITextView和UITableView

标签 ios swift uitableview uitextview

我有一个 UITableView,每个单元格内并排有两个 UITextView。我希望 UITableViewCell 和 UITextView 都增加高度,这样用户就不需要在 UITextView 中滚动。这是我尝试过的:

在 TableViewController 类中:

    self.tableView.estimatedRowHeight = 44
    self.tableView.rowHeight = UITableViewAutomaticDimension

在 TableViewCell 类中(从 here 获得):

func textViewDidChange(textView: UITextView) {

    var frame : CGRect = textView.frame
    frame.size.height = textView.contentSize.height
    textView.frame = frame
}

当用户键入超出 UITextView 的设置宽度时,UITableView 的高度会从 44 增加到大约 100,而 UITextView 的高度不会增加。我设置了约束,以便 UITextView 的高度等于 UITableViewCell 的高度。

知道为什么会发生这种情况以及如何正确地动态更改 UITextView 和 UITableView 的高度吗?

最佳答案

我的答案是基于我们在生产社交应用程序时使用的内容 Impether ,因为你在 Twitter 上问我你使用过这个应用程序,你看到那里扩展了 UITextView。

首先,我们有一个自定义UITableViewCell包含UITextView的基类,将展开(该类也有对应的xib文件,可自行设计):

class MultiLineTextInputTableViewCell: UITableViewCell {

    //our cell has also a title, but you
    //can get rid of it
    @IBOutlet weak var titleLabel: UILabel!
    //UITextView we want to expand
    @IBOutlet weak var textView: UITextView!

    override init(style: UITableViewCellStyle, reuseIdentifier: String!) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    /// Custom setter so we can initialize the height of the text view
    var textString: String {
        get {
            return textView?.text ?? ""
        }
        set {
            if let textView = textView {
                textView.text = newValue
                textView.delegate?.textViewDidChange?(textView)
            }
        }
    }

    override func awakeFromNib() {
        super.awakeFromNib()        
        // Disable scrolling inside the text view so we enlarge to fitted size
        textView?.scrollEnabled = false        
    }

    override func setSelected(selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        if selected {
            textView?.becomeFirstResponder()
        } else {
            textView?.resignFirstResponder()
        }
    }
}

定义了自定义单元格后,您可以在基于 UITableViewController 的类中使用它,如下所示:

class YourTableViewController: UITableViewController {

    //in case where you want to have
    //multiple expanding text views
    var activeTextView: UITextView?

    override func viewDidLoad() {
        super.viewDidLoad()

        //registering nib for a cell to reuse
        tableView.registerNib(
            UINib(nibName: "MultiLineTextInputTableViewCell", bundle: nil),
            forCellReuseIdentifier: "MultiLineTextInputTableViewCell")

    }

    override func viewWillDisappear(animated: Bool) {
        super.viewWillDisappear(animated)
        //hide keyboard when view controller disappeared
        if let textView = activeTextView {
            textView.resignFirstResponder()
        }
    }

    // MARK: - Table view data source

    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        //put your value here
        return 1
    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        //put your value here
        return 2
    }

    override func tableView(tableView: UITableView,
                            cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let row = indexPath.row
        let cell = tableView.dequeueReusableCellWithIdentifier(
            "MultiLineTextInputTableViewCell",
            forIndexPath: indexPath) as! MultiLineTextInputTableViewCell

        let titleText = "Title label for your cell"
        let textValue = "Text value you want for your text view"

        cell.titleLabel.text = titleText
        cell.textView.text = textValue

        //store row of a cell as a tag, so you can know
        //which row to reload when the text view is expanded
        cell.textView.tag = row
        cell.textView.delegate = self

        return cell

    }

    override func tableView(tableView: UITableView,
                            estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
        //standard row height
        return 44.0
    }

    override func tableView(tableView: UITableView,
                            heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
        return UITableViewAutomaticDimension
    }

    // Override to support conditional editing of the table view.
    override func tableView(tableView: UITableView,
                            canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
        // Return false if you do not want the specified item to be editable.
        return true
    }
}

//extension containing method responsible for expanding text view
extension YourTableViewController: UITextViewDelegate {

    func textViewDidEndEditing(textView: UITextView) {
        let value = textView.text
        //you can do something here when editing is ended
    }

    func textView(textView: UITextView, shouldChangeTextInRange range: NSRange,
                  replacementText text: String) -> Bool {
        //if you hit "Enter" you resign first responder
        //and don't put this character into text view text
        if text == "\n" {
            textView.resignFirstResponder()
            return false
        }
        return true
    }

    func textViewDidBeginEditing(textView: UITextView) {
        activeTextView = textView
    }

    //this actually resize a text view
    func textViewDidChange(textView: UITextView) {

        let size = textView.bounds.size
        let newSize = textView.sizeThatFits(CGSize(width: size.width,
            height: CGFloat.max))

        // Resize the cell only when cell's size is changed
        if size.height != newSize.height {
            UIView.setAnimationsEnabled(false)
            tableView?.beginUpdates()
            tableView?.endUpdates()
            UIView.setAnimationsEnabled(true)

            let thisIndexPath = NSIndexPath(forRow: textView.tag, inSection: 0)
            tableView?.scrollToRowAtIndexPath(thisIndexPath,
                                              atScrollPosition: .Bottom,
                                              animated: false)
        }
    }
} 

关于ios - 当UITextView的文本超出1行时展开UITextView和UITableView,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37014919/

相关文章:

ios - 如何在较新的 Xcode 上安装较旧的 iOS 运行时?

swift - 按 double 对 UITableView 进行排序

iphone - 核心数据: UITableView with multiple NSFetchedResultControllers

swift - 如何给UITableViewCell添加左右边距

ios - UISearchDisplayDelegate 弃用解决方法

ios - 在单元测试中使用不可用的初始值设定项模拟 Cocoa 对象

ios - 有没有一种方法可以检查 2 个 NSDictionaries 是否包含相同的键?

ios - 如何删除使用 Aspect Fit ScrollView 中的 ImageView 中的多余空间?

ios - 如何在外侧 UIButton 单击时获取 CollectionViewCell indexPath

ios - 非可选代表的弱与无主