在 UITableView 中滚动时视图被替换

2024-02-06

我是一名 Android 开发人员,对 iOS 应用程序开发非常陌生。我正在尝试构建一个简单的聊天系统,每个单元格中只有一行数据。

我正在使用自定义UIView类来生成气泡和UILabel and an UIImageView以编程方式。

当我第一次运行该应用程序时,一切看起来都很好。请看下图:

但是,当我滚动时出现问题UITableView向上,我不明白为什么气泡会向右侧移动。见下图:

SO 中的一些帖子说这是UITableView.

我应该如何解决这个问题?

如果您需要应用程序任何部分的任何代码片段,请在下面评论。

PS:我使用 Xcode 9 和 iOS 11.4 作为测试设备和 Swift 4 编程。

任何帮助,将不胜感激。谢谢。

下边是BubbleView Class:

EDIT

import UIKit
import Foundation

class BubbleView: UIView {

    var incomingColor = UIColor(white: 0.9, alpha: 1)
    var outgoingColor = UIColor(red: 0.09, green: 0.54, blue: 1, alpha: 1)

    var isIncoming: Bool = false

    init(isIncoming: Bool) {
        self.isIncoming = isIncoming
        super.init(frame: UIScreen.main.bounds);
    }

    required init?(coder decoder: NSCoder) {
        super.init(coder: decoder)
    }

    override func draw(_ rect: CGRect) {
        let width = rect.width
        let height = rect.height

        let bezierPath = UIBezierPath()

        if self.isIncoming == true {
            bezierPath.move(to: CGPoint(x: 22, y: height))
            bezierPath.addLine(to: CGPoint(x: width - 17, y: height))
            bezierPath.addCurve(to: CGPoint(x: width, y: height - 17), controlPoint1: CGPoint(x: width - 7.61, y: height), controlPoint2: CGPoint(x: width, y: height - 7.61))
            bezierPath.addLine(to: CGPoint(x: width, y: 17))
            bezierPath.addCurve(to: CGPoint(x: width - 17, y: 0), controlPoint1: CGPoint(x: width, y: 7.61), controlPoint2: CGPoint(x: width - 7.61, y: 0))
            bezierPath.addLine(to: CGPoint(x: 21, y: 0))
            bezierPath.addCurve(to: CGPoint(x: 4, y: 17), controlPoint1: CGPoint(x: 11.61, y: 0), controlPoint2: CGPoint(x: 4, y: 7.61))
            bezierPath.addLine(to: CGPoint(x: 4, y: height - 11))
            bezierPath.addCurve(to: CGPoint(x: 0, y: height), controlPoint1: CGPoint(x: 4, y: height - 1), controlPoint2: CGPoint(x: 0, y: height))
            bezierPath.addLine(to: CGPoint(x: -0.05, y: height - 0.01))
            bezierPath.addCurve(to: CGPoint(x: 11.04, y: height - 4.04), controlPoint1: CGPoint(x: 4.07, y: height + 0.43), controlPoint2: CGPoint(x: 8.16, y: height - 1.06))
            bezierPath.addCurve(to: CGPoint(x: 22, y: height), controlPoint1: CGPoint(x: 16, y: height), controlPoint2: CGPoint(x: 19, y: height))

            incomingColor.setFill()

        } else {
            bezierPath.move(to: CGPoint(x: width - 22, y: height))
            bezierPath.addLine(to: CGPoint(x: 17, y: height))
            bezierPath.addCurve(to: CGPoint(x: 0, y: height - 17), controlPoint1: CGPoint(x: 7.61, y: height), controlPoint2: CGPoint(x: 0, y: height - 7.61))
            bezierPath.addLine(to: CGPoint(x: 0, y: 17))
            bezierPath.addCurve(to: CGPoint(x: 17, y: 0), controlPoint1: CGPoint(x: 0, y: 7.61), controlPoint2: CGPoint(x: 7.61, y: 0))
            bezierPath.addLine(to: CGPoint(x: width - 21, y: 0))
            bezierPath.addCurve(to: CGPoint(x: width - 4, y: 17), controlPoint1: CGPoint(x: width - 11.61, y: 0), controlPoint2: CGPoint(x: width - 4, y: 7.61))
            bezierPath.addLine(to: CGPoint(x: width - 4, y: height - 11))
            bezierPath.addCurve(to: CGPoint(x: width, y: height), controlPoint1: CGPoint(x: width - 4, y: height - 1), controlPoint2: CGPoint(x: width, y: height))
            bezierPath.addLine(to: CGPoint(x: width + 0.05, y: height - 0.01))
            bezierPath.addCurve(to: CGPoint(x: width - 11.04, y: height - 4.04), controlPoint1: CGPoint(x: width - 4.07, y: height + 0.43), controlPoint2: CGPoint(x: width - 8.16, y: height - 1.06))
            bezierPath.addCurve(to: CGPoint(x: width - 22, y: height), controlPoint1: CGPoint(x: width - 16, y: height), controlPoint2: CGPoint(x: width - 19, y: height))

            outgoingColor.setFill()
        }

        bezierPath.close()
        bezierPath.fill()
    }

}

并且,tableView 的东西:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCell(withIdentifier: "BiddingHistoryIdentifier", for: indexPath) as! BiddingHistoryTableViewCell

    let row = indexPath.row

    var strNew: [String] = splitString[row].components(separatedBy: "-")
    let strFirst = strNew[0].trimmingCharacters(in: .whitespacesAndNewlines)
    let strSecond = strNew[1].trimmingCharacters(in: .whitespacesAndNewlines)

    if !strFirst.elementsEqual(VendorLoginSetterGetter.strName.trimmingCharacters(in: .whitespacesAndNewlines)) {

        let text = strSecond
        let label =  UILabel()
        label.numberOfLines = 0
        label.font = UIFont.systemFont(ofSize: 18)
        label.textColor = .black
        label.text = text

        let constraintRect = CGSize(width: 0.66 * cell.frame.width,
                                    height: .greatestFiniteMagnitude)
        let boundingBox = text.boundingRect(with: constraintRect,
                                            options: .usesLineFragmentOrigin,
                                            attributes: [.font: label.font],
                                            context: nil)
        label.frame.size = CGSize(width: ceil(boundingBox.width),
                                    height: ceil(boundingBox.height))

        let bubbleSize = CGSize(width: label.frame.width + 28,
                                height: label.frame.height + 20)

        let bubbleView = BubbleView(isIncoming: true)
        bubbleView.frame.size = bubbleSize
        bubbleView.backgroundColor = .clear

        //bubbleView.center = cell.center
        bubbleView.frame.origin.y = (cell.frame.size.height / 2) - 20
        bubbleView.frame.origin.x = 50
        cell.addSubview(bubbleView)

        label.center = bubbleView.center
        cell.addSubview(label)

        let imageView = UIImageView(frame: CGRect(x: 8, y: 0, width: 35, height: 35))
        imageView.image = UIImage(named: "ic_vendor_black.png")
        imageView.frame.origin.y = (cell.frame.size.height / 2) - 15
        cell.addSubview(imageView)

    }
    else {

        let text = strSecond
        let label =  UILabel()
        label.numberOfLines = 0
        label.font = UIFont.systemFont(ofSize: 18)
        label.textColor = .white
        label.text = text

        let constraintRect = CGSize(width: 0.66 * cell.frame.width,
                                    height: .greatestFiniteMagnitude)
        let boundingBox = text.boundingRect(with: constraintRect,
                                            options: .usesLineFragmentOrigin,
                                            attributes: [.font: label.font],
                                            context: nil)
        label.frame.size = CGSize(width: ceil(boundingBox.width),
                                  height: ceil(boundingBox.height))

        let bubbleSize = CGSize(width: label.frame.width + 28,
                                height: label.frame.height + 20)

        let bubbleView = BubbleView(isIncoming: false)
        bubbleView.frame.size = bubbleSize
        bubbleView.backgroundColor = .clear

        //bubbleView.center = cell.center
        bubbleView.frame.origin.y = (cell.frame.size.height / 2) - 20
        bubbleView.frame.origin.x = cell.frame.size.width - 200
        cell.addSubview(bubbleView)

        label.center = bubbleView.center
        cell.addSubview(label)

        let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 28, height: 28))
        imageView.image = UIImage(named: "ic_user_black.png")
        imageView.frame.origin.y = (cell.frame.size.height / 2) - 15
        imageView.frame.origin.x = cell.frame.size.width - 8
        cell.addSubview(imageView)

    }
    return cell
}

代码按要求更新。


您需要移动将子视图添加到单元格的代码cellForRowAt委托给各自的单元类内部。

现在的问题就像 @PeteMorris 所说,是你将被重复使用的细胞将already拥有您在第一次出列时添加的子视图。因此,每当同一个单元格出队时,都会向其中添加子视图again.

  • The elegant解决方案是将设置视图的代码移至单元类内部。

  • 如果您正在寻找hotfix您可以从单元格中删除所有子视图prepareForReuse。 (每次在出队之前重用单元时都会调用此方法)

您的重用方法将如下所示。 (这个方法在你的细胞类中)

override func prepareForReuse() {
    super.prepareForReuse()

    for view in subviews {
        view.removeFromSuperview()
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 UITableView 中滚动时视图被替换 的相关文章

随机推荐

  • 当分支存在时,有没有办法优雅地改变 git 分支的历史记录?

    我想使用 git 更正一些无效的作者信息过滤器分支 http coffee geek nz node 22723特征 问题是分支存在分叉 从而导致不同步 是否有办法将对提交日志的更改合并到分支中 重写历史记录会创建新的提交 并且无法从外部存
  • 使用移动设备时 MathJax 方程不适合窗口宽度

    在我的博客文章 用 Hugo 编译 中我有本节 https oren0e github io 2020 04 27 mab thompson mathematical proof for beta distribution being co
  • 在Python中,如何将列表分成大小均匀的块,从前一个块的最后一个元素开始?

    转换列表的最Pythonic方法是什么 mylist 0 1 2 3 4 5 6 7 8 分成大块n始终从前一个块的最后一个元素开始的元素 最后一个块的最后一个元素应该与第一个块的第一个元素相同 以使数据结构循环 喜欢 0 1 2 3 3
  • CMakeLists.txt CMAKE_PREFIX_PATH 处出现 CMake 错误

    我已经从以下网站下载了人脸分析SDK的源代码http face ci2cv net http face ci2cv net 现在我正在努力让它运行 我下载了所有必要的软件并按照安装说明进行操作 当我尝试执行 cmake options 时出
  • 为 JS 修改 Sublime Text 2

    我几乎是 Mathematica 之外的编程初学者 我使用 Sublime Text 2 主要需要用 JS 进行编码 并且我想使用与首选项中已存在的颜色主题不同的颜色主题 例如 我想使用 我尝试安装 Eclipse 尚未成功 我使用的是装有
  • java中的SSH客户端和服务器

    哪些流行的库可用于在 java 中实现自定义 SSH 客户端和服务器 我知道 Jsch http www jcraft com jsch http www jcraft com jsch 是一个流行的java ssh客户端 是否有良好且安全
  • 匹配和删除字符串中的 Twitter 主题标签

    仅当主题标签位于字符串末尾以外的任何位置时 我才需要从主题标签中删除 字符 例子 这个月我要去 迪士尼 WDW 这个月我要去 迪士尼 WDW 奥兰多 这个月我要去 迪士尼 WDW 奥兰多 它们需要转换为 这个月我要去迪士尼 这个月我要去迪士
  • 当 Passportjs 上使用 Google Auth 时,自定义回调从未被调用

    我尝试使用 PassportJS 登录 Google 但是当我使用自定义回调时 Google 策略从未调用回调 我究竟做错了什么 我的代码如下 端点 var router express Router router get passport
  • UITableView滚动到底部

    我有这行代码 tableView contentOffset CGPointMake 0 0f 10000000 0f 内容大小比10000000 0f 但是 UITableView 仍然没有滚动到底部 我该怎么做 滚动到tableView
  • Clock() 函数总是返回 0 [重复]

    这个问题在这里已经有答案了 可能的重复 The C clock 函数只返回零 https stackoverflow com questions 2134363 the c clock function just returns a zer
  • 在 C++ 中将矩阵定义为数组数组并计算其逆矩阵

    不幸的是 我在 C 方面没有太多经验 并且我正在努力在 C 方面取得进步 首先 我定义了数组数组 以便形成一个 3x3 矩阵 array lt array lt double gt gt input gcnew array lt array
  • C++ 中如何解析嵌套模板?

    我最近问了一个关于确定迭代器在编译时是否指向复数值的问题 并收到了有效的答案 问题在这里 如何专门针对指向复数值的迭代器的算法 https stackoverflow com questions 59954327 how can i spe
  • Espresso:匹配对话框下的视图

    我的测试用例相当简单 在主活动视图上 我有一个抽屉 该抽屉中的一个菜单项可打开一个对话框 我想断言 单击此菜单项 在打开对话框之前关闭抽屉 这是我现在所拥有的 Opens the drawer onView withId R id acti
  • WebDriver Wait '.until(ExpectedConditions.elementToBeClickable' 仅当我将 Thread.sleep(500) 添加到代码中时才有效?

    我正在尝试使用 webdriver wait 单击页面上可见的按钮 但 webdriver 仅在添加后才能单击该按钮Thread sleep到代码 在执行代码之前 我还检查了按钮是否可见 True returns true 按钮可见性检查
  • 钥匙串中的 macOS 安装程序证书评估错误:扩展密钥用法无效

    我生成了一个用于代码签名的 mac 安装程序证书 但收到一个错误 该错误阻止我使用证书对安装程序进行签名 在评估钥匙串访问中的证书时 出现错误 无效的扩展密钥用法 以下是尝试评估安装程序证书以进行代码签名时出现的错误序列 我发现使用 Xco
  • 如何启用 Android 内部应用程序共享?

    我已在 Play 控制台中上传 Android App Bundle 进行 Alpha 测试 但当我打开测试 URL 时 它显示在下面的对话框中 尝试以下选项以启用内部应用程序共享 Option 1 Step 1 打开 Play 商店 St
  • IntelliJ 中的 Google Play、Drive API 示例代码

    我正在关注Android 版 Google 云端硬盘快速入门说明 https developers google com drive quickstart android并让它在 Eclipse Kepler 中工作 Juno 就是很狡猾
  • 值不能为空。参数名称:实体集

    我有一个相当标准的设置 只有 POCO 类 public class Project public int ProjectId get set public string Name get set public int ClientId g
  • 将图像拖放到画布上 (FabricJS)

    问题 我想用图像而不是canvas目的 这意味着您必须先将要添加的内容添加到画布并作为画布的一部分 然后才能添加它 这些图像实际上是网站的一部分 因此不需要做一些复杂的事情 我在这里找到的这段代码仅适用于对象而不是实际元素的情况 顺便说一句
  • 在 UITableView 中滚动时视图被替换

    我是一名 Android 开发人员 对 iOS 应用程序开发非常陌生 我正在尝试构建一个简单的聊天系统 每个单元格中只有一行数据 我正在使用自定义UIView类来生成气泡和UILabel and an UIImageView以编程方式 当我