1
Fork 0

Use system font and wrapped text height for wrapped content

This commit is contained in:
redstrate 2020-06-04 09:42:42 -04:00
parent c76c6fd0f1
commit c2c995e63c
3 changed files with 72 additions and 19 deletions

View file

@ -56,7 +56,7 @@ struct Post: Decodable, Identifiable {
struct ParsedPostContainer { struct ParsedPostContainer {
let post: Post let post: Post
let contentAttributed: NSAttributedString let contentAttributed: NSMutableAttributedString
} }
let mediaURL = "https://homepages.cae.wisc.edu/~ece533/images/airplane.png" let mediaURL = "https://homepages.cae.wisc.edu/~ece533/images/airplane.png"

View file

@ -8,9 +8,9 @@ extension String {
} }
final class AttributedTextComponent: UIViewRepresentable { final class AttributedTextComponent: UIViewRepresentable {
let string: NSAttributedString let string: NSMutableAttributedString
init(_ string: NSAttributedString) { init(_ string: NSMutableAttributedString) {
self.string = string self.string = string
} }
@ -27,30 +27,56 @@ final class AttributedTextComponent: UIViewRepresentable {
} }
} }
struct SizeKey: PreferenceKey {
static var defaultValue: CGSize = .zero
static func reduce(value: inout CGSize, nextValue: () -> CGSize) {
value = nextValue()
}
}
struct AttributedText: View { struct AttributedText: View {
let html: NSAttributedString let html: NSMutableAttributedString
let component: AttributedTextComponent let component: AttributedTextComponent
@State var height: CGFloat = 0.0 @State var height: CGFloat = 0.0
@State var lastSize: CGSize = .zero
init(_ html: NSAttributedString) {
init(_ html: NSMutableAttributedString) {
self.html = html self.html = html
self.component = AttributedTextComponent(html) self.component = AttributedTextComponent(html)
} }
func calculateHeight(size: CGSize) {
let label = UILabel(frame: CGRect(x: 0, y: 0, width: size.width, height: .greatestFiniteMagnitude))
label.numberOfLines = 0
label.lineBreakMode = .byWordWrapping
label.attributedText = self.html
label.sizeToFit()
self.height = label.frame.height
self.lastSize = size
}
var body: some View { var body: some View {
component.onAppear { ZStack {
let label = UILabel() GeometryReader { geometry in
Rectangle().fill(Color.clear).preference(key: SizeKey.self, value: geometry.size)
}.onPreferenceChange(SizeKey.self, perform: { size in
self.calculateHeight(size: size)
})
label.numberOfLines = 0 component
label.lineBreakMode = .byWordWrapping }
label.setContentCompressionResistancePriority(.defaultLow, for: .horizontal) .frame(minWidth: 0.0, maxWidth: .infinity, minHeight: self.height, maxHeight: self.height)
.onAppear {
label.attributedText = self.html if self.lastSize != .zero {
label.sizeToFit() self.calculateHeight(size: self.lastSize)
}
self.height = label.frame.height + 15.0 // for padding }
}.frame(minWidth: 0.0, maxWidth: .infinity, minHeight: 0.0, maxHeight: height)
} }
} }
@ -108,6 +134,6 @@ struct PostView: View {
struct PostView_Previews: PreviewProvider { struct PostView_Previews: PreviewProvider {
static var previews: some View { static var previews: some View {
return PostView(post: ParsedPostContainer(post: fooPost, contentAttributed: NSAttributedString())) return PostView(post: ParsedPostContainer(post: fooPost, contentAttributed: NSMutableAttributedString()))
} }
} }

View file

@ -1,5 +1,32 @@
import SwiftUI import SwiftUI
extension NSMutableAttributedString {
func with(font: UIFont) -> NSMutableAttributedString {
enumerateAttribute(NSAttributedString.Key.font, in: NSMakeRange(0, length), options: .longestEffectiveRangeNotRequired, using: { (value, range, stop) in
if let originalFont = value as? UIFont, let newFont = applyTraitsFromFont(originalFont, to: font) {
addAttribute(NSAttributedString.Key.font, value: newFont, range: range)
}
})
return self
}
func applyTraitsFromFont(_ originalFont: UIFont, to newFont: UIFont) -> UIFont? {
let originalTrait = originalFont.fontDescriptor.symbolicTraits
if originalTrait.contains(.traitBold) {
var traits = newFont.fontDescriptor.symbolicTraits
traits.insert(.traitBold)
if let fontDescriptor = newFont.fontDescriptor.withSymbolicTraits(traits) {
return UIFont.init(descriptor: fontDescriptor, size: 0)
}
}
return newFont
}
}
struct ProfileView: View { struct ProfileView: View {
let username: String let username: String
@ -28,7 +55,7 @@ struct ProfileView: View {
var postArray = [ParsedPostContainer]() var postArray = [ParsedPostContainer]()
for post in decodedPosts.posts { for post in decodedPosts.posts {
let container = ParsedPostContainer(post: post, contentAttributed: (try? NSAttributedString(data: post.getContent().data(using: .utf8)!, options: [.documentType: NSAttributedString.DocumentType.html], documentAttributes: nil))!) let container = ParsedPostContainer(post: post, contentAttributed: (try? NSMutableAttributedString(data: post.getContent().data(using: .utf8)!, options: [.documentType: NSAttributedString.DocumentType.html], documentAttributes: nil))!.with(font: UIFont.preferredFont(forTextStyle: .body)))
postArray.append(container) postArray.append(container)
} }