Я испробовал различные варианты и обнаружил, что расчет вручную очень хорошо соответствует вашим требованиям вместо использования пути исключения или NSAttributedString
.
Вот снимок экрана, на котором я смог сделать WhatsApp как чат без использования Xib / раскадровки
и вот код и, где нужно, добавленные комментарии:
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
, но при попытке обнаружить, что он заставил меня написать много кода, и им было очень трудно управлять /update.