在键入时调整包含UITextView的UITableViewCell

vib*_*vib 19 cocoa-touch uitableview uitextview ios autolayout

我有一个包含自定义单元格的UITableViewController.每个单元格都是使用nib创建的,并包含一个不可滚动的UITextView.我在每个单元格中添加了约束,以便单元格将其高度调整为UITextView的内容.所以最初我的控制器看起来像这样:

初始状态

现在我希望当用户在单元格中键入内容时,其内容会自动适应.这个问题已被多次询问,特别是这里第二个答案.因此,我在代码中编写了以下代理:

- (BOOL) textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString*)text {
    [self.tableView beginUpdates];
    [self.tableView endUpdates];
    return YES;
}
Run Code Online (Sandbox Code Playgroud)

然而,它会导致以下奇怪的行为:忽略所有约束,并且所有单元格高度都会崩溃到最小值.见下图:

错误的行为

如果我向下滚动tableView以强制进行新的cellForRowAtIndexPath调用,我将恢复单元格的正确高度:

正确的行为

请注意,我并没有如我所料的autoLayout来照顾这实现heightForRowAtIndexPath.

有人能告诉我我做错了什么或帮助我吗?非常感谢你 !

atl*_*lwx 44

这是一个快速的解决方案,对我来说很好.如果使用自动布局,则需要为estimatedRowHeight分配值,然后为行高返回UITableViewAutomaticDimension.最后在文本视图委托中执行类似下面的操作.

override func viewDidLoad() {
    super.viewDidLoad()
    self.tableView.estimatedRowHeight = 44.0
}

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

// MARK: UITextViewDelegate
func textViewDidChange(textView: UITextView) {

    // Calculate if the text view will change height, then only force 
    // the table to update if it does.  Also disable animations to
    // prevent "jankiness".

    let startHeight = textView.frame.size.height
    let calcHeight = textView.sizeThatFits(textView.frame.size).height  //iOS 8+ only

    if startHeight != calcHeight {

        UIView.setAnimationsEnabled(false) // Disable animations
        self.tableView.beginUpdates()
        self.tableView.endUpdates()

        // Might need to insert additional stuff here if scrolls
        // table in an unexpected way.  This scrolls to the bottom
        // of the table. (Though you might need something more
        // complicated if editing in the middle.)

        let scrollTo = self.tableView.contentSize.height - self.tableView.frame.size.height
        self.tableView.setContentOffset(CGPointMake(0, scrollTo), animated: false)

        UIView.setAnimationsEnabled(true)  // Re-enable animations.
}
Run Code Online (Sandbox Code Playgroud)

  • 对于Swift 3+,将`CGPointMake(0,scrollTo)`更改为`CGPoint(x:0,y:scrollTo)`;) (2认同)

Yai*_*iba 12

我的解决方案类似于@atlwx,但有点短.用静态表测试.UIView.setAnimationsEnabled(false)需要防止单元格的内容"跳",而表更新单元格的高度

override func viewDidLoad() {
    super.viewDidLoad()
    self.tableView.estimatedRowHeight = 44.0
}

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

func textViewDidChange(_ textView: UITextView) {
    UIView.setAnimationsEnabled(false)
    textView.sizeToFit()
    self.tableView.beginUpdates()
    self.tableView.endUpdates()
    UIView.setAnimationsEnabled(true)
}
Run Code Online (Sandbox Code Playgroud)


fl0*_*034 6

在iOS 12上测试

我真的尝试了很多解决方案,最后在这里找到了一个不错的解决方案

这可以与动画一起使用,并且看起来很漂亮。诀窍是DispatchQueue.async障碍。我还曾经TPKeyboardAvoidingTableView确保键盘不会重叠任何东西。

func textViewDidChange(_ textView: UITextView) {
    // Animated height update
    DispatchQueue.main.async {
        self.tableView?.beginUpdates()
        self.tableView?.endUpdates()
    }        
}
Run Code Online (Sandbox Code Playgroud)

更新

我遇到了奇怪的跳跃问题TPKeyboardAvoidingTableView。尤其是当我滚动到底部然后UITextView开始活动时。因此,我TPKeyboardAvoidingTableView由本地人代替,UITableView自己处理插图。表格视图是本地滚动的。