Fix UITextView line height adjustment for DynamicType, always use the max width for the view (#2916)

* fix text being cut off

* adjust line height for dynamictype
zio/stable
Hailey 2024-02-21 10:11:42 -08:00 committed by GitHub
parent 43206d9f57
commit d2e5f83cd2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 24 additions and 19 deletions

View File

@ -40,19 +40,19 @@ class RNUITextViewShadow: RCTShadowView {
self.setAttributedText()
}
// Tell yoga not to use flexbox
// Returning true here will tell Yoga to not use flexbox and instead use our custom measure func.
override func isYogaLeafNode() -> Bool {
return true
}
// We only need to insert text children
// We should only insert children that are UITextView shadows
override func insertReactSubview(_ subview: RCTShadowView!, at atIndex: Int) {
if subview.isKind(of: RNUITextViewChildShadow.self) {
super.insertReactSubview(subview, at: atIndex)
}
}
// Whenever the subvies update, set the text
// Every time the subviews change, we need to reformat and render the text.
override func didUpdateReactSubviews() {
self.setAttributedText()
}
@ -64,7 +64,7 @@ class RNUITextViewShadow: RCTShadowView {
return
}
// Update the text
// Since we are inside the shadow view here, we have to find the real view and update the text.
self.bridge.uiManager.addUIBlock { uiManager, viewRegistry in
guard let textView = viewRegistry?[self.reactTag] as? RNUITextView else {
return
@ -100,18 +100,25 @@ class RNUITextViewShadow: RCTShadowView {
// Create the attributed string with the generic attributes
let string = NSMutableAttributedString(string: child.text, attributes: attributes)
// Set the paragraph style attributes if necessary
// Set the paragraph style attributes if necessary. We can check this by seeing if the provided
// line height is not 0.0.
let paragraphStyle = NSMutableParagraphStyle()
if child.lineHeight != 0.0 {
paragraphStyle.minimumLineHeight = child.lineHeight
paragraphStyle.maximumLineHeight = child.lineHeight
// Whenever we change the line height for the text, we are also removing the DynamicType
// adjustment for line height. We need to get the multiplier and apply that to the
// line height.
let scaleMultiplier = scaledFontSize / child.fontSize
paragraphStyle.minimumLineHeight = child.lineHeight * scaleMultiplier
paragraphStyle.maximumLineHeight = child.lineHeight * scaleMultiplier
string.addAttribute(
NSAttributedString.Key.paragraphStyle,
value: paragraphStyle,
range: NSMakeRange(0, string.length)
)
// Store that height
// To calcualte the size of the text without creating a new UILabel or UITextView, we have
// to store this line height for later.
self.lineHeight = child.lineHeight
} else {
self.lineHeight = font.lineHeight
@ -124,24 +131,22 @@ class RNUITextViewShadow: RCTShadowView {
self.dirtyLayout()
}
// Create a YGSize based on the max width
// To create the needed size we need to:
// 1. Get the max size that we can use for the view
// 2. Calculate the height of the text based on that max size
// 3. Determine how many lines the text is, and limit that number if it exceeds the max
// 4. Set the frame size and return the YGSize. YGSize requires Float values while CGSize needs CGFloat
func getNeededSize(maxWidth: Float) -> YGSize {
// Create the max size and figure out the size of the entire text
let maxSize = CGSize(width: CGFloat(maxWidth), height: CGFloat(MAXFLOAT))
let textSize = self.attributedText.boundingRect(with: maxSize, options: .usesLineFragmentOrigin, context: nil)
// Figure out how many total lines there are
let totalLines = Int(ceil(textSize.height / self.lineHeight))
var totalLines = Int(ceil(textSize.height / self.lineHeight))
// Default to the text size
var neededSize: CGSize = textSize.size
// If the total lines > max number, return size with the max
if self.numberOfLines != 0, totalLines > self.numberOfLines {
neededSize = CGSize(width: CGFloat(maxWidth), height: CGFloat(CGFloat(self.numberOfLines) * self.lineHeight))
totalLines = self.numberOfLines
}
self.frameSize = neededSize
return YGSize(width: Float(neededSize.width), height: Float(neededSize.height))
self.frameSize = CGSize(width: CGFloat(maxWidth), height: CGFloat(CGFloat(totalLines) * self.lineHeight))
return YGSize(width: Float(self.frameSize.width), height: Float(self.frameSize.height))
}
}