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

时间:2016-05-03 21:45:38

标签: ios swift uitableview uitextview

我有一个UITableView,每个单元格内有两个UITextViews。我希望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的高度?

2 个答案:

答案 0 :(得分:11)

我的回答是基于我们在社交应用Overriding Templates via a Theme的制作中使用的内容,因为您在Twitter上告诉我您使用了该应用,并且您看到了在那里扩展UITextView。

首先,我们有一个基于自定义Impether的类,其中包含UITextView,它将被展开(此类也有相应的xib文件,您可以自行设计):< / p>

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)
        }
    }
} 

答案 1 :(得分:1)

首先确保您的自动布局约束不会与您设置的帧冲突。 (如果一切正常但仍然无效)请尝试将frame更改为bounds。视图框架(CGRect)是其超视图坐标系中矩形的位置。根据我的经验,使用frame可能会导致奇怪的问题。

func textViewDidChange(textView: UITextView) {

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