Created
October 27, 2020 19:53
-
-
Save mrackwitz/91395527a37c4cea1757d76e8e99f826 to your computer and use it in GitHub Desktop.
A UILabel-based SwiftUI view which auto-expands to the width of the container, and only expand to render the full height of the label.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
struct AutoHeightLabelView: View { | |
var attributedString: NSAttributedString | |
var body: some View { | |
HorizontalGeometryReader { width in | |
UILabelView( | |
attributedString: attributedString, | |
preferredMaxLayoutWidth: width | |
) | |
} | |
} | |
} | |
fileprivate struct UILabelView: UIViewRepresentable { | |
var attributedString: NSAttributedString | |
var preferredMaxLayoutWidth: CGFloat = .greatestFiniteMagnitude | |
public func makeUIView(context: UIViewRepresentableContext<UILabelView>) -> UILabel { | |
let label = UILabel(frame: .zero) | |
label.numberOfLines = 0 | |
label.setContentHuggingPriority(.required, for: .vertical) | |
label.setContentCompressionResistancePriority(.required, for: .vertical) | |
label.setContentHuggingPriority(.defaultLow, for: .horizontal) | |
label.setContentCompressionResistancePriority(.defaultLow, for: .horizontal) | |
updateUIView(label, context: context) | |
return label | |
} | |
public func updateUIView(_ label: UILabel, context: UIViewRepresentableContext<UILabelView>) { | |
label.attributedText = attributedString | |
label.preferredMaxLayoutWidth = preferredMaxLayoutWidth | |
} | |
} | |
fileprivate struct HorizontalGeometryReader<Content: View> : View { | |
var content: (CGFloat) -> Content | |
@State private var width: CGFloat = 0 | |
public init(@ViewBuilder content: @escaping (CGFloat) -> Content) { | |
self.content = content | |
} | |
public var body: some View { | |
content(width) | |
.frame(minWidth: 0, maxWidth: .infinity) | |
.background( | |
GeometryReader { geometry in | |
Color.clear | |
.preference(key: WidthPreferenceKey.self, value: geometry.size.width) | |
} | |
) | |
.onPreferenceChange(WidthPreferenceKey.self) { width in | |
self.width = width | |
} | |
} | |
} | |
fileprivate struct WidthPreferenceKey: PreferenceKey, Equatable { | |
static var defaultValue: CGFloat = 0 | |
/// An empty reduce implementation takes the first value | |
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) { | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hey @mrackwitz I found this very useful, thank you!
I was having issues on switching my tab bar and returning and also after changing dynamic type size during runtime, as the height was reset somehow.
I added a unique ID to the geometry reader to fix the issue as follows: