UITextView在UITableViewCell中的奇怪行为

时间:2016-01-25 16:04:01

标签: ios swift uitableview uitextview

我有一个包含一些stackviews的单元格,底部stackView包含一个textView和一个自定义分隔符。

my cell

我想创建一个选项,当用户点击单元格时,它会显示点击文本视图的全文,因此该单元格中的最大行数为0,其他单元格中的最大行数应为3.

我使用了这个教程http://www.roostersoftstudios.com/2011/04/14/iphone-uitableview-with-animated-expanding-cells/,我修改了一下,我的代码:

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier(iden_tableViewCell4) as! TableViewCell4


    if let selectedCellIP = selectedIndexPath {
        if indexPath == selectedCellIP {
            cell.textTextVIew.textContainer.maximumNumberOfLines = 0
        }
        else {
            cell.textTextVIew.textContainer.maximumNumberOfLines = textVIewMaxNumberOfLines
        }

    }
    else {
        cell.textTextVIew.textContainer.maximumNumberOfLines = textVIewMaxNumberOfLines
    }

    return cell
}

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    tableView.deselectRowAtIndexPath(indexPath, animated: true)

    //The user is selecting the cell which is currently expanded
    //we want to minimize it back
    if selectedIndexPath == indexPath {
        selectedIndexPath = nil
        tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)

        return
    }

    //First we check if a cell is already expanded.
    //If it is we want to minimize make sure it is reloaded to minimize it back
    if let selIndexPath = selectedIndexPath {

        let previousPath = selIndexPath
        selectedIndexPath = indexPath
        tableView.reloadRowsAtIndexPaths([previousPath], withRowAnimation: .Fade)

    }


    //Finally set the selected index to the new selection and reload it to expand
    selectedIndexPath = indexPath
    tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)

}

在我设置的viewDidLoadtableView.estimatedRowHeight = 160 tableView.rowHeight = UITableViewAutomaticDimension

扩展和收缩效果很好,但其他单元格的textView高度有一个奇怪的行为。当第一个单元格被扩展时,我向下滚动,最后一个单元格也被扩展,而且不应该扩展。 enter image description here

2 个答案:

答案 0 :(得分:0)

在选择时动态调整UITableViewCell

使用个人选择索引是危险的事情。您不仅可能会错过didSelectRowAtIndexPath中的角落情况,也不可能适用于多种选择 您应该将单元格扩展/压缩通知拆分为2个不同的块(无需跟踪selectedIndexPath,更强大的代码)

<强>展开

override func tableView(_ tableView: UITableView,
                        didSelectRowAt indexPath: IndexPath) {
    self.reloadRowsAtIndexPaths(tableView,
                                indexPath:indexPath)
}

<强>合同

override func tableView(_ tableView: UITableView,
                        didDeselectRowAt indexPath: IndexPath) {
    self.reloadRowsAtIndexPaths(tableView,
                                indexPath:indexPath)
}

selectRowAtIndexPath

会破坏选择

这可以防止didDeselectRowAtIndexPath被调用。 解决方法是缓存整个选择,而不是单个索引,并在重新加载后恢复此类选择。

完整代码

注意维护cacheSelectedRows的时间和方式。这使用普通UITableViewCell。它所需要的只是reuseIdentifier

class TableViewController: UITableViewController {
    var cacheSelectedRows:[IndexPath]? = nil

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

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

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

        if let textLabel = cell.textLabel {
            textLabel.backgroundColor = UIColor.clear

            textLabel.numberOfLines = 1
            if let cacheSelectedRows = cacheSelectedRows {
                textLabel.numberOfLines = (cacheSelectedRows.contains(indexPath)) ? 0 : 1
            }
            textLabel.text = "\(1 + indexPath.row), Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
        }
        return cell
    }

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        self.reloadRowsAtIndexPaths(tableView, indexPath:indexPath)
    }

    override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
         self.reloadRowsAtIndexPaths(tableView, indexPath:indexPath)
    }

    func reloadRowsAtIndexPaths(_ tableView: UITableView, indexPath: IndexPath) {
        cacheSelectedRows = tableView.indexPathsForSelectedRows

        tableView.reloadRows(at: [indexPath], with: .fade)

        // Restore selection
        if let cacheSelectedRows = cacheSelectedRows {
            for path in cacheSelectedRows {
                self.tableView.selectRow(at: path, animated: false, scrollPosition: .none)
            }
        }
    }
}

<强>演示

Animated demo

►在GitHub上找到此解决方案,并在Swift Recipes上找到其他详细信息。

答案 1 :(得分:0)

我没有找到答案,为什么发生了textView和单元格高度的奇怪行为,但我有解决方案。

所以看起来tableView.estimatedRowHeight = 160tableView.rowHeight = UITableViewAutomaticDimension并不尊重textView所有单元格的最大行数。 cellForRow工作正常,它设置了限制,但行高有时会扩展,有时会收缩。

所以我从StackView中解开了textView和底部分隔符,用Label替换了TextView并设置了autolayaut约束。现在它工作正常,没有奇怪的行为。