I am attempting to display individual characters in the exact positions that they would appear if displayed as a single string with kerning. The problem is that the characters' bounding boxes seem to be opaque, so that each newly added character covers some of the prior one. Where kerning is greater (e.g., in the combination "ToT"), the problem is obvious:
My setup is something like this: I have an SKView embedded in a container view. In an extension of the SKView's view controller, the following are set within a function in this order:
skView.allowsTransparency = true
scene.backgroundColor = .clear
charAttr – [NSAttributedStringKey.backgroundColor: UIColor.clear]
textView.isOpaque = false
textView.backgroundColor = UIColor.clear
Each UITextView is added successively as a subview to the view (which is an SKView).
I've looked all over my code for some clue as to what could be making the character's bounding boxes seem opaque, but I haven't found anything. The sad thing is that I solved this problem sometime last year, but don't remember what I did and don't have the code anymore.
Any insights or ideas would be appreciated.
After achieving the sought-after effect in a playground, I pasted this simple code into the extension where the original code was. It still worked, so I made it as close to identical to the original as possible, until it also exhibited the problem.
The SKView and extension aspects were irrelevant. The problem lies with how UITextView frames property deals with character widths. Here's the relevant code:
// charInfoArray contains (among other things) an attributed character, its origin,
// its size, and info about whether or not it should be displayed
// For each char, the origin and size info were derived from...
let currentCharRect = layoutManager.boundingRect(forGlyphRange: currentCharRange, in: textContainer)
// To display each (attributed) char of "ToT\n" . . .
for (index, charInfo) in charInfoArray.enumerated() {
guard charInfo.displayed == true else { continue }
let textView = UITextView()
textView.backgroundColor = UIColor.clear
textView.attributedText = charInfo.attrChar
textView.textContainerInset = UIEdgeInsets.zero
// let width = charInfo.size!.width
let width = 30 // arbitrary width
// Using the automatically generated charInfo.size!.width here
// appears to make the text view's background opaque!
textView.frame = CGRect(origin: charInfo.origin!,
size: CGSize(width: width, height: charInfo.size!.height))
textView.frame = textView.frame.offsetBy(dx: 0.0, dy: offsetToCenterY)
textView.textContainer.lineFragmentPadding = CGFloat(0.0)
textView.backgroundColor = UIColor(red: 1, green: 0, blue: 0, alpha: 0.2)
textView.textColor = UIColor.black
view.addSubview(textView)
print(charInfo.size!.width)
}
Setting the width to width = charInfo.size!.width
seems to make the text view's background opaque! This may be caused by the unusually large width assigned to newline char at the end of the sequence. To eliminate the problem, I'll have to deal with newline chars in another way. In any case, I have no idea why this causes the text view's background to turn opaque, but it does. Setting the width to an arbitrary value of, say, 30 eliminates problem.
Here are the results of using automatically generated and manually set widths, respectively:
The translucent red areas (on yellow backgrounds) show the bounding rectangles for each of the characters, including the newline character.