我有一个带聊天气泡的tableView.
如果字符数超过250,则会缩短这些气泡
如果用户点击了气泡
>取消选择(缩短)先前的选择
>新选择扩展并显示整个内容
>新选择顶部约束更改(从0到4)
我想要实现什么?
If a long bubble is selected already, but the user selects another bubble, I want the tableView to scroll to the position of the new selected bubble.
我会分享一个关于它的视频
没有这个滚动,contentOffset保持不变,看起来很糟糕.
(在视频中:右侧)
视频:
Right: without the mentioned scrolling
Left: with scrolling
问题出现了:
在左边,你可以注意到它是毛病.
>随机幽灵细胞无缘无故地出现.
>有时甚至会弄乱一些气泡的高度(不在视频中)
为什么会这样?
码:
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
我制作了一个小版本的应用程序,以便您可以查看并测试我的问题所在.如果有人能帮忙解决这个问题,我会非常感激! :C
最佳答案 首先让我们通过“不滚动”来定义我们的意思 – 我们的意思是更少的细胞保持不变.所以我们想找到一个我们想成为锚细胞的细胞.从更改之前到更改之后,从单元格的顶部到屏幕顶部的距离是相同的.
var indexPathAnchorPoint:IndexPath?
var offsetAnchorPoint:CGFloat?
func findHighestCellThatStartsInFrame() -> UITableViewCell? {
var anchorCell:UITableViewCell?
for cell in self.tableView.visibleCells {
let topIsInFrame = cell.frame.origin.y >= self.tableView.contentOffset.y
if topIsInFrame {
if let currentlySelected = anchorCell{
let isHigerUpInView = cell.frame.origin.y < currentlySelected.frame.origin.y
if isHigerUpInView {
anchorCell = cell
}
}else{
anchorCell = cell
}
}
}
return anchorCell
}
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)
}
}
我们在开始做之前先调用它.
func bubbleTappedHandler(sender: UITapGestureRecognizer) {
self.setAnchorPoint()
....
接下来,我们需要在进行更改后设置内容偏移量,以便单元格移回到它所设想的位置.
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)
}
}
接下来我们在完成更改后调用它.
self.tableView.beginUpdates()
self.tableView.endUpdates()
self.tableView.layoutSubviews()
self.scrollToAnchorPoint()
动画可能有点奇怪,因为有很多东西在同一时间发生.我们正在同时更改内容偏移量和单元格的大小,但如果您将手指放在第一个单元格旁边,顶部可见,您将看到它最终位于正确的位置.