diff options
author | Hailey <me@haileyok.com> | 2024-02-21 10:11:42 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-02-21 10:11:42 -0800 |
commit | d2e5f83cd2dc08f17a63aa600245639143afe2e9 (patch) | |
tree | 13746c583dee0c4658200b5eef3258c55563ee04 /modules/react-native-ui-text-view/ios/RNUITextViewShadow.swift | |
parent | 43206d9f57e75a2052775253b30d6126ddc65481 (diff) | |
download | voidsky-d2e5f83cd2dc08f17a63aa600245639143afe2e9.tar.zst |
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
Diffstat (limited to 'modules/react-native-ui-text-view/ios/RNUITextViewShadow.swift')
-rw-r--r-- | modules/react-native-ui-text-view/ios/RNUITextViewShadow.swift | 43 |
1 files changed, 24 insertions, 19 deletions
diff --git a/modules/react-native-ui-text-view/ios/RNUITextViewShadow.swift b/modules/react-native-ui-text-view/ios/RNUITextViewShadow.swift index 4f3eda43c..5a462f6b6 100644 --- a/modules/react-native-ui-text-view/ios/RNUITextViewShadow.swift +++ b/modules/react-native-ui-text-view/ios/RNUITextViewShadow.swift @@ -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)) - - // Default to the text size - var neededSize: CGSize = textSize.size + var totalLines = Int(ceil(textSize.height / self.lineHeight)) - // 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)) } } |