Skip to content

Commit

Permalink
Text bubble fixes (#127)
Browse files Browse the repository at this point in the history
* Fixes diacritic marks being clipped.

This changes how text insetting is performed. By using non-zero textInsets, UITextView size is now bigger and diacritic marks can be seen.

* Fixes size of text not matching UITextView.sizeThatFits(_:) for some strings - which was leading to incorrect size of text bubbles -
  • Loading branch information
diegosanchezr committed May 12, 2016
1 parent 09a5951 commit 3b62da4
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -345,8 +345,8 @@ struct BaseMessageLayoutModel {
let horizontalInterspacing = parameters.horizontalInterspacing
let avatarSize = parameters.avatarSize

let preferredWidthForBubble = containerWidth * parameters.maxContainerWidthPercentageForBubbleView
let bubbleSize = bubbleView.sizeThatFits(CGSize(width: preferredWidthForBubble, height: CGFloat.max))
let preferredWidthForBubble = (containerWidth * parameters.maxContainerWidthPercentageForBubbleView).bma_round()
let bubbleSize = bubbleView.sizeThatFits(CGSize(width: preferredWidthForBubble, height: .max))
let containerRect = CGRect(origin: CGPoint.zero, size: CGSize(width: containerWidth, height: bubbleSize.height))


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@ public final class TextBubbleView: UIView, MaximumLayoutWidthSpecificable, Backg
textView.showsVerticalScrollIndicator = false
textView.layoutManager.allowsNonContiguousLayout = true
textView.exclusiveTouch = true
textView.textContainerInset = UIEdgeInsetsZero
textView.textContainer.lineFragmentPadding = 0
return textView
}()
Expand Down Expand Up @@ -135,11 +134,13 @@ public final class TextBubbleView: UIView, MaximumLayoutWidthSpecificable, Backg
guard let style = self.style, viewModel = self.textMessageViewModel else { return }
let font = style.textFont(viewModel: viewModel, isSelected: self.selected)
let textColor = style.textColor(viewModel: viewModel, isSelected: self.selected)
let textInsets = style.textInsets(viewModel: viewModel, isSelected: self.selected)
let bubbleImage = self.style.bubbleImage(viewModel: self.textMessageViewModel, isSelected: self.selected)
let borderImage = self.style.bubbleImageBorder(viewModel: self.textMessageViewModel, isSelected: self.selected)

if self.textView.font != font { self.textView.font = font}
if self.textView.text != viewModel.text {self.textView.text = viewModel.text}
if self.textView.textContainerInset != textInsets { self.textView.textContainerInset = textInsets }
if self.textView.textColor != textColor {
self.textView.textColor = textColor
self.textView.linkTextAttributes = [
Expand Down Expand Up @@ -229,18 +230,36 @@ private final class TextBubbleLayoutModel {
let textSize = self.textSizeThatFitsWidth(maxTextWidth)
let bubbleSize = textSize.bma_outsetBy(dx: textHorizontalInset, dy: self.layoutContext.textInsets.bma_verticalInset)
self.bubbleFrame = CGRect(origin: CGPoint.zero, size: bubbleSize)
self.textFrame = UIEdgeInsetsInsetRect(self.bubbleFrame, self.layoutContext.textInsets)
self.textFrame = self.bubbleFrame
self.size = bubbleSize
}

private func textSizeThatFitsWidth(width: CGFloat) -> CGSize {
let maxSize = CGSize(width: width, height: CGFloat.max)
let options: NSStringDrawingOptions = [.UsesLineFragmentOrigin, .UsesFontLeading]
let attributes = [
let textContainer: NSTextContainer = {
let size = CGSize(width: width, height: .max)
let container = NSTextContainer(size: size)
container.lineFragmentPadding = 0
return container
}()

let textStorage = self.replicateUITextViewNSTextStorage()
let layoutManager: NSLayoutManager = {
let layoutManager = NSLayoutManager()
layoutManager.addTextContainer(textContainer)
textStorage.addLayoutManager(layoutManager)
return layoutManager
}()

let rect = layoutManager.usedRectForTextContainer(textContainer)
return rect.size.bma_round()
}

private func replicateUITextViewNSTextStorage() -> NSTextStorage {
// See https://github.com/badoo/Chatto/issues/129
return NSTextStorage(string: self.layoutContext.text, attributes: [
NSFontAttributeName: self.layoutContext.font,
NSKernAttributeName: 0
]
return self.layoutContext.text.boundingRectWithSize(maxSize, options: options, attributes: attributes, context: nil).size.bma_round()
"NSOriginalFont": self.layoutContext.font,
])
}
}

Expand Down
10 changes: 8 additions & 2 deletions ChattoAdditions/Source/Utils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public extension CGSize {

public extension CGSize {
func bma_round() -> CGSize {
return CGSize(width: ceil(self.width * scale) * (1.0 / scale), height: ceil(self.height * scale) * (1.0 / scale) )
return CGSize(width: self.width.bma_round(), height: self.height.bma_round())
}

func bma_rect(inContainer containerRect: CGRect, xAlignament: HorizontalAlignment, yAlignment: VerticalAlignment, dx: CGFloat, dy: CGFloat) -> CGRect {
Expand Down Expand Up @@ -100,7 +100,7 @@ public extension CGRect {
}

func bma_round() -> CGRect {
let origin = CGPoint(x: ceil(self.origin.x * scale) * (1.0 / scale), y: ceil(self.origin.y * scale) * (1.0 / scale))
let origin = CGPoint(x: self.origin.x.bma_round(), y: self.origin.y.bma_round())
return CGRect(origin: origin, size: self.size.bma_round())
}
}
Expand All @@ -112,6 +112,12 @@ public extension CGPoint {
}
}

public extension CGFloat {
func bma_round() -> CGFloat {
return ceil(self * scale) * (1.0 / scale)
}
}

public extension UIView {
var bma_rect: CGRect {
get {
Expand Down

0 comments on commit 3b62da4

Please sign in to comment.