首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >TableView在滚动到另一个单元时崩溃:奇怪的行为

TableView在滚动到另一个单元时崩溃:奇怪的行为
EN

Stack Overflow用户
提问于 2019-01-20 16:52:52
回答 5查看 1.4K关注 0票数 4

我有一个带有聊天泡泡的tableView。

如果character countmore than 250,这些气泡就会缩短。

如果用户单击气泡

  • 先前的选择被取消选举(缩短)
  • 新的选集扩展并揭示了整个内容。
  • 新的选择顶部约束更改(从0到4)

我想实现什么?

如果已经选择了一个长气泡,但是用户选择了另一个气泡,我希望tableView滚动到新选择的气泡的位置。

我会分享一段关于这件事的视频

如果没有这个滚动,contentOffset仍然是一样的,而且看起来很糟糕。

(在视频中:右边)

视频:

Right:没有上述滚动的 左侧:带滚动的

-peZycZEAE

来了一个问题:

在左边,你可以注意到它是有瑕疵的。

  • 随机的幽灵细胞无缘无故地出现了。
  • 有时它甚至会弄乱一些气泡的高度(在视频中没有)。

为什么会这样呢?

代码:

代码语言:javascript
复制
func bubbleTappedHandler(sender: UITapGestureRecognizer) {
        
        let touchPoint = sender.location(in: self.tableView)
        if let indexPath = tableView.indexPathForRow(at: touchPoint) {
            
            if indexPath == currentSelectedIndexPath {

                // Selected bubble is tapped, deselect it
                self.selectDeselectBubbles(deselect: indexPath)

            } else {
                if (currentSelectedIndexPath != nil){

                    // Deselect old bubble, select new one
                    self.selectDeselectBubbles(select: indexPath, deselect: currentSelectedIndexPath)
                    
                } else {

                    // Select bubble
                    self.selectDeselectBubbles(select: indexPath)

                }
            }

        }
    }
    
    
    
    func selectDeselectBubbles(select: IndexPath? = nil, deselect: IndexPath? = nil){
        
        
        var deselectCell : WorldMessageCell?
        var selectCell : WorldMessageCell?
        
        if let deselect = deselect {
            deselectCell = tableView.cellForRow(at: deselect) as? WorldMessageCell
        }
        if let select = select {
            selectCell = tableView.cellForRow(at: select) as? WorldMessageCell
        }
        
        
        // Deselect Main
        if let deselect = deselect, let deselectCell = deselectCell {

            tableView.deselectRow(at: deselect, animated: false)
            currentSelectedIndexPath = nil
            // Update text
            deselectCell.messageLabel.text = self.dataSource[deselect.row].message.shortened()

            
        }
        // Select Main
        if let select = select, let selectCell = selectCell {

            tableView.selectRow(at: select, animated: true, scrollPosition: .none)
            currentSelectedIndexPath = select
            // Update text
            deselectCell.messageLabel.text = self.dataSource[select.row].message.full()
        }
        
        
        UIView.animate(withDuration: appSettings.defaultAnimationSpeed) {
                
            // Deselect Constraint changes
            
            if let deselect = deselect, let deselectCell = deselectCell {
                // Constarint change
                deselectCell.nickNameButtonTopConstraint.constant = 0
                deselectCell.timeLabel.alpha = 0.0
                deselectCell.layoutIfNeeded()
                
            }
            
            // Select Constraint changes
            if let select = select, let selectCell = selectCell {
                
                // Constarint change
                selectCell.nickNameButtonTopConstraint.constant = 4
                selectCell.timeLabel.alpha = 1.0
                selectCell.layoutIfNeeded()
                
                
            }
            
            
        }

        self.tableView.beginUpdates()
        self.tableView.endUpdates()
        
        
        
        UIView.animate(withDuration: appSettings.defaultAnimationSpeed) {
            if let select = select, deselect != nil, self.tableView.cellForRow(at: deselect!) == nil && deselectCell != nil {

                // If deselected row is not anymore on screen
                // but was before the collapsing,
                // then scroll to new selected row  

                self.tableView.scrollToRow(at: select, at: .top, animated: false)
            }
        }

    }

更新1:添加Github项目

链接: https://github.com/krptia/test2

我制作了一个小版本的应用程序,这样你就可以看到并测试我的问题所在。如果有人能帮助解决这个问题,我会非常感激的!

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2019-01-29 09:47:09

首先,让我们来定义我们所说的“不滚动”是什么意思--我们的意思是细胞更少地保持不变。所以我们想要找到一个我们想成为锚细胞的细胞。从更改之前到更改后,从单元格顶部到屏幕顶部的距离是相同的。

代码语言:javascript
复制
var indexPathAnchorPoint: IndexPath?
var offsetAnchorPoint: CGFloat?

func findHighestCellThatStartsInFrame() -> UITableViewCell? {
  return self.tableView.visibleCells.filter {
     $0.frame.origin.y >= self.tableView.contentOffset.y
  }.sorted {
     $0.frame.origin.y > $1.frame.origin.y
  }.first
}

func setAnchorPoint() {
  self.indexPathAnchorPoint = nil;
  self.offsetAnchorPoint = nil;

  if let cell = self.findHighestCellThatStartsInFrame() {
    self.offsetAnchorPoint = cell.frame.origin.y - self.tableView.contentOffset.y
    self.indexPathAnchorPoint = self.tableView.indexPath(for: cell)
  }
}

我们在开始做事之前就把这个叫做。

代码语言:javascript
复制
 func bubbleTappedHandler(sender: UITapGestureRecognizer) {
    self.setAnchorPoint()
     ....

接下来,我们需要在进行更改之后设置内容偏移量,这样单元格就会移动到应该移动的位置。

代码语言:javascript
复制
func scrollToAnchorPoint() {
  if let indexPath = indexPathAnchorPoint, let offset = offsetAnchorPoint {
    let rect = self.tableView.rectForRow(at: indexPath)
    let contentOffset = rect.origin.y - offset
    self.tableView.setContentOffset(CGPoint.init(x: 0, y: contentOffset), animated: false)
  }
}

接下来,我们在完成更改后调用它。

代码语言:javascript
复制
  self.tableView.beginUpdates()
  self.tableView.endUpdates()
  self.tableView.layoutSubviews()
  self.scrollToAnchorPoint()

动画可能有点奇怪,因为同时发生了很多事情。我们同时更改内容偏移量和单元格的大小,但是如果您将手指放在顶部可见的第一个单元格旁边,您将看到它在正确的位置结束。

票数 2
EN

Stack Overflow用户

发布于 2019-01-20 23:36:34

尝试在willDisplay上使用UITableViewDelegate api

代码语言:javascript
复制
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    if (indexPath == currentSelectedIndexPath) {
        // logic to expand your cell
        // you don't need to animate it since still not visible
    }
}
票数 0
EN

Stack Overflow用户

发布于 2019-01-23 07:02:58

用这个替换bubbleTappedHandler的代码,然后运行并检查:

代码语言:javascript
复制
func bubbleTappedHandler(sender: UITapGestureRecognizer) {

    let touchPoint = sender.location(in: self.tableView)
    if let indexPath = tableView.indexPathForRow(at: touchPoint) {

        if indexPath == currentSelectedIndexPath {
            currentSelectedIndexPath = nil
            tableView.reloadRows(at: [indexPath], with: .automatic)
        } else {
            if (currentSelectedIndexPath != nil){
                if let prevSelectedIndexPath = currentSelectedIndexPath {
                    currentSelectedIndexPath = indexPath
                    tableView.reloadRows(at: [prevSelectedIndexPath, indexPath], with: .automatic)
                }
            } else {
                currentSelectedIndexPath = indexPath
                tableView.reloadRows(at: [indexPath], with: .automatic)
            }

        }

        DispatchQueue.main.asyncAfter(deadline: .now() + 0.1, execute: { [weak self] in
            let currentIndexPath = self?.currentSelectedIndexPath ?? indexPath
            self?.tableView.scrollToRow(at: currentIndexPath, at: .top, animated: false)
        })
    }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54278738

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档