【问题标题】:Expand UITextView and UITableView When UITextView's Text Extends Beyond 1 Line当 UITextView 的文本超出 1 行时展开 UITextView 和 UITableView
【发布时间】:2016-05-03 21:45:38
【问题描述】:

我有一个 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 的高度?

【问题讨论】:

    标签: ios swift uitableview uitextview


    【解决方案1】:

    我的回答是基于我们在生产社交应用 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)
            }
        }
    } 
    

    【讨论】:

    • 感谢您的回答!我似乎无法让它工作我有两个并排的文本视图。两者都没有设置高度约束,但有一个宽度约束。我尝试启用滚动,但单元格仍然没有扩展,textView 只是被向上推以适应新行。有什么想法吗?
    • 救了我该死的一天!
    【解决方案2】:

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

    func textViewDidChange(textView: UITextView) {
    
        var frame : CGRect = textView.bounds
        frame.size.height = textView.contentSize.height
        textView.bounds = frame
    }
    

    【讨论】:

    • 我仍然遇到同样的问题。我的 textView 是并排的,没有设置高度约束。我应该在我的自定义单元格类中调用 textViewDidChange 并且我的 tableVC 中的自动行高可以吗?
    猜你喜欢
    • 1970-01-01
    • 2017-07-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-23
    • 2016-05-18
    相关资源
    最近更新 更多