在UITextView中放置其他文本-WhatsApp时间戳副本

时间:2019-05-12 18:56:30

标签: swift uitextview

请参见以下Whatsapp图片,尤其是红色圆圈内的文本:

enter image description here

在图像上有Lorum文本和消息时间戳的时间戳。我想知道Whatsapp如何做到这一点。

我认为Whatsapp正在使用UITextView,但是我不确定。我想知道如何制作这种细胞。我尝试添加带有attributedText属性的时间戳,但是在为此计算正确的大小时遇到​​很多麻烦。也许有一个简单的解决方案。

注意:没有xibs / storyboard,只有代码。

注意2:如图片所示, UITextView中的文本环绕时间戳。这是我要复制的行为。

5 个答案:

答案 0 :(得分:3)

我尝试了各种选择,发现手动计算可以很好地满足您的需求,而不是使用排除路径或NSAttributedString

这是一个屏幕截图,我无需使用任何Xib / storyboard就可以使WhatsApp像聊天视图一样 enter image description here

这是代码,以及需要添加注释的地方:

func createChatView() {

    let msgViewMaxWidth = UIScreen.main.bounds.width * 0.7 // 70% of screen width

    let message = "Filler text is text that shares some characteristics of a real written text, but is random or otherwise generated. It may be used to display a sample of fonts, generate text for testing, or to spoof an e-mail spam filter."

    // Main container view
    let messageView = UIView(frame: CGRect(x: UIScreen.main.bounds.width * 0.1, y: 150, width: msgViewMaxWidth, height: 0))
    messageView.backgroundColor = UIColor(red: 0.803, green: 0.99, blue: 0.780, alpha: 1)
    messageView.clipsToBounds = true
    messageView.layer.cornerRadius = 5

    let readStatusImg = UIImageView()
    readStatusImg.image = UIImage(named: "double-tick-indicator.png")
    readStatusImg.frame.size = CGSize(width: 12, height: 12)

    let timeLabel = UILabel(frame: CGRect(x: 0, y: 0, width: messageView.bounds.width, height: 0))
    timeLabel.font = UIFont.systemFont(ofSize: 10)
    timeLabel.text = "12:12 AM"
    timeLabel.sizeToFit()
    timeLabel.textColor = .gray

    let textView = UITextView(frame: CGRect(x: 0, y: 0, width: messageView.bounds.width, height: 0))
    textView.isEditable = false
    textView.isScrollEnabled = false
    textView.showsVerticalScrollIndicator =  false
    textView.showsHorizontalScrollIndicator = false
    textView.backgroundColor = .clear
    textView.text = message

    // Wrap time label and status image in single view
    // Here stackview can be used if ios 9 below are not support by your app.
    let rightBottomView = UIView()
    let rightBottomViewHeight: CGFloat = 16
    // Here 7 pts is used to keep distance between timestamp and status image
    // and 5 pts is used for trail space.
    rightBottomView.frame.size = CGSize(width: readStatusImg.frame.width + 7 + timeLabel.frame.width + 5, height: rightBottomViewHeight)
    rightBottomView.addSubview(timeLabel)
    readStatusImg.frame.origin = CGPoint(x: timeLabel.frame.width + 7, y: 0)
    rightBottomView.addSubview(readStatusImg)

    // Fix right and bottom margin
    rightBottomView.autoresizingMask = [.flexibleLeftMargin, .flexibleTopMargin]

    messageView.addSubview(textView)
    messageView.addSubview(rightBottomView)

    // Update textview height
    textView.sizeToFit()
    // Update message view size with textview size
    messageView.frame.size = textView.frame.size

    // Keep at right bottom in parent view
    rightBottomView.frame.origin = CGPoint(x: messageView.bounds.width - rightBottomView.bounds.width, y: messageView.bounds.height - rightBottomView.bounds.height)

    // Get glyph index in textview, make sure there is atleast one character present in message
    let lastGlyphIndex = textView.layoutManager.glyphIndexForCharacter(at: message.count - 1)
    // Get CGRect for last character
    let lastLineFragmentRect = textView.layoutManager.lineFragmentUsedRect(forGlyphAt: lastGlyphIndex, effectiveRange: nil)

    // Check whether enough space is avaiable to show in last line of message, if not add extra height for timestamp
    if lastLineFragmentRect.maxX > (textView.frame.width - rightBottomView.frame.width) {
        // Subtracting 5 to reduce little top spacing for timestamp
        messageView.frame.size.height += (rightBottomViewHeight - 5)
    }
    self.view.addSubview(messageView)
}

我希望这能解决您的问题。

在使用其他方法创建聊天视图时遇到的挑战是:

  • UITextView exclusionPaths -并非在所有情况下都有效,我还注意到了一些问题,例如有时它会在排除路径周围提供更多的额外空间。当文本恰好占据UITextView空间时,它也会失败,在这种情况下,时间戳记应换行,但这不会发生。

  • NSAttributedString -实际上,我无法使用NSAttributedString进行此聊天,但是在尝试时发现它使我编写了很多代码,而且非常难以管理/更新。

答案 1 :(得分:1)

为了实现WhatsApp聊天行的布局,即消息+时间,我使用了以下策略。 使用2标签。第一个消息和第二个日期。首先,我将视图限制为顶部,底部,左侧和右侧。对于第二个,我将其限制在View的右下方。

现在为了避免第一和第二重叠,我在聊天消息的末尾添加了“空白”。例如,如果消息为"Hi",则发送给"Hi "。这样可以确保我的时间和刻度不会重叠。

答案 2 :(得分:1)

我已经创建了一个虚拟测试项目,我想应该回答您的问题。

enter image description here

我将textView用作文本占位符,并添加了一些imageView。没有什么特别的约束。您可以看到一张图片。

然后所有神奇的事情都发生在tableView委托方法中:cellForRowAt indexPath:,其中我使用imageView中的UIBezierPath排除了textView框架。因此,您必须将rect的{​​{1}}设置为右下角。

UIBezierPath

最终结果如下:

enter image description here

答案 3 :(得分:0)

您可以制作一个.xib文件,并将文本放入textView中,将时间放入标签中,对于复选框,请使用ImageView。像这样:

enter image description here

答案 4 :(得分:0)

该任务的主要问题是告诉TextView避免在时间戳上方输入文本。

您可以使用pipeline { agent any environment { ... } parameters { booleanParam(name: 'TEST', defaultValue: false, description: 'Run task in test mode') choice(name: 'TASK', choices: ['REFRESH', 'BUILD'], description: 'Pick task') } ... } 轻松完成此操作:

Configure

就是这样。当然,您应该在右下角添加时间戳容器视图。

文档:enter image description here