请参见以下Whatsapp图片,尤其是红色圆圈内的文本:
在图像上有Lorum文本和消息时间戳的时间戳。我想知道Whatsapp如何做到这一点。
我认为Whatsapp正在使用UITextView
,但是我不确定。我想知道如何制作这种细胞。我尝试添加带有attributedText属性的时间戳,但是在为此计算正确的大小时遇到很多麻烦。也许有一个简单的解决方案。
注意:没有xibs / storyboard,只有代码。
注意2:如图片所示, UITextView中的文本环绕时间戳。这是我要复制的行为。
答案 0 :(得分:3)
我尝试了各种选择,发现手动计算可以很好地满足您的需求,而不是使用排除路径或NSAttributedString
。
这是一个屏幕截图,我无需使用任何Xib / storyboard就可以使WhatsApp像聊天视图一样
这是代码,以及需要添加注释的地方:
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)
我已经创建了一个虚拟测试项目,我想应该回答您的问题。
我将textView
用作文本占位符,并添加了一些imageView
。没有什么特别的约束。您可以看到一张图片。
然后所有神奇的事情都发生在tableView委托方法中:cellForRowAt indexPath:
,其中我使用imageView
中的UIBezierPath
排除了textView
框架。因此,您必须将rect
的{{1}}设置为右下角。
UIBezierPath
最终结果如下:
答案 3 :(得分:0)
答案 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
就是这样。当然,您应该在右下角添加时间戳容器视图。