Last active
October 31, 2022 21:47
-
-
Save carlynorama/a4b2ff2c0a9f941056b646268b40a357 to your computer and use it in GitHub Desktop.
Rendering HTML as AttributedString in a scroll view without crahsing.
This file contains hidden or 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
| // | |
| // ContentView.swift | |
| // HTMLTests | |
| // | |
| // Created by Carlyn Maw on 10/30/22. | |
| // | |
| //https://www.hackingwithswift.com/example-code/uikit/how-to-load-a-html-string-into-a-wkwebview-or-uiwebview-loadhtmlstring | |
| //https://developer.apple.com/forums/thread/682431 | |
| //https://developer.apple.com/documentation/foundation/attributedstring | |
| //https://wwdcbysundell.com/2021/a-first-look-at-attributed-string/ | |
| //https://www.kodeco.com/29501177-attributedstring-tutorial-for-swift-getting-started | |
| //https://www.hackingwithswift.com/quick-start/swiftui/how-to-open-web-links-in-safari | |
| import SwiftUI | |
| extension String { | |
| //Usage | |
| //List(ExampleText.harderHTMLTests, id:\.self) { item in | |
| // Text(item.listCrasher() ?? "Nothing to see").id(UUID()) <- Will need id() somewhere if view scrolls | |
| //} | |
| func htmlToOptionalAttributedString() -> AttributedString? { | |
| let data = Data(self.utf8) | |
| return try? AttributedString(NSAttributedString(data: data, options: [.documentType: NSAttributedString.DocumentType.html], documentAttributes: nil)) | |
| } | |
| //Usage | |
| //List(ExampleText.harderHTMLTests, id:\.self) { item in | |
| // Text(item.htmlToAttributedString()).id(UUID()) <-Will need id() somewhere if view scrolls | |
| //} | |
| func htmlToAttributedString() -> AttributedString { | |
| do { | |
| let data = Data(self.utf8) | |
| let result = try AttributedString(NSAttributedString(data: data, options: [.documentType: NSAttributedString.DocumentType.html], documentAttributes: nil)) | |
| return result | |
| } catch { | |
| return AttributedString("Error parsing HTML: \(error)") | |
| } | |
| } | |
| func markdownToOptionalAttributedString() -> AttributedString? { | |
| return try? AttributedString(markdown: self) | |
| } | |
| func markdownToAttributedString() -> AttributedString { | |
| do { | |
| return try AttributedString(markdown: self) | |
| } catch { | |
| return AttributedString("Error parsing HTML: \(error)") | |
| } | |
| } | |
| } | |
| struct ContentView: View { | |
| let displayItems:[DisplayItem] | |
| init() { | |
| displayItems = ExampleText.htmlTests.map { DisplayItem(value: $0) } | |
| } | |
| var body: some View { | |
| VStack { | |
| //Works fine when not in a list and not scrolling. | |
| Group { | |
| Text(ExampleText.htmlTests[0].listCrasher() ?? "Nothing to see") | |
| Text(ExampleText.htmlTests[1].listCrasher() ?? "Nothing to see") | |
| Text(ExampleText.htmlTests[2].listCrasher() ?? "Nothing to see") | |
| Text(ExampleText.htmlTests[3].listCrasher() ?? "Nothing to see") | |
| } | |
| List(displayItems) { item in | |
| // Fixed height does not fix the problem. | |
| //https://stackoverflow.com/questions/59889020/how-to-use-an-nsattributedstring-with-a-scrollview-in-swiftui | |
| //Text(item.listCrasher() ?? "Nothing to see").frame(height: 100) | |
| Text(item.value.htmlToAttributedString()).id(UUID()) //<------ MUST HAVE ID! THIS NOW WORKS!! | |
| } | |
| //This also works fine. | |
| // List(ExampleText.markdownTests, id:\.self) { item in | |
| // Text(item.markdownToOptionalAttributedString() ?? "Nothing to see") | |
| // } | |
| } | |
| } | |
| } | |
| struct ContentView_Previews: PreviewProvider { | |
| static var previews: some View { | |
| ContentView() | |
| } | |
| } | |
| struct DisplayItem:Identifiable { | |
| let id = UUID() | |
| let value:String | |
| } | |
| enum ExampleText { | |
| static let htmlTests = [#"<p>test me</p>"#, | |
| #"Hello <b>World</b>"#, | |
| #"<p>Hello <a href="http://www.apple.com">World</a></p>"#, | |
| #"<i>what is</i><h3>Happening??</h3>"#, | |
| #"Something long so scrolling is required. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce at urna vitae leo viverra fermentum. Maecenas nec porttitor massa, non feugiat turpis. Donec pretium, enim quis porttitor feugiat, nunc erat pulvinar urna, vel posuere nunc turpis at diam. Nam vehicula lectus nisi, a lacinia lacus euismod id. Curabitur rutrum nunc in purus rutrum elementum. Curabitur ac maximus enim, eget sodales ex. Maecenas at sem eget leo commodo suscipit. Praesent non aliquet sem. Cras et erat dapibus, semper turpis at, dictum ligula. Cras faucibus fringilla nunc, nec molestie risus finibus sed. Aliquam a cursus elit. Aenean convallis dui vitae eros elementum pretium. Aenean dolor sapien, laoreet id urna vel, finibus imperdiet ex. Pellentesque suscipit justo eu augue commodo tempor. Ut id facilisis massa. "#, | |
| #"Is this long enough?"#, | |
| #"How about now?"#, | |
| #"Something long so scrolling is required. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce at urna vitae leo viverra fermentum. Maecenas nec porttitor massa, non feugiat turpis. Donec pretium, enim quis porttitor feugiat, diam. Nam vehicula lectus nisi, a lacinia lacus euismod id. Curabitur rutrum nunc in purus rutrum elementum. Curabitur ac maximus enim, eget sodales ex. Maecenas at sem eget leo commodo suscipit. Praesent non aliquet sem. Cras et erat dapibus, semper turpis at, dictum ligula. Cras faucibus fringilla nunc, nec molestie risus finibus sed. Aliquam a cursus elit. Aenean convallis dui vitae eros elementum pretium. Aenean dolor sapien, laoreet id urna vel, finibus imperdiet ex. Pellentesque suscipit justo eu augue commodo tempor. Ut id facilisis massa. "#, | |
| #"Something long required. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce at urna vitae leo viverra fermentum. Maecenas nec porttitor massa, non feugiat turpis. Donec pretium, enim quis porttitor feugiat, nunc erat pulvinar urna, vel posuere nunc turpis at diam. Nam vehicula lectus nisi, a lacinia lacus euismod id. Curabitur rutrum nunc in purus rutrum elementum. Curabitur ac maximus enim, eget sodales ex. Maecenas at sem eget leo commodo suscipit. Praesent non aliquet sem. Cras et erat dapibus, semper turpis at, dictum ligula. Cras faucibus fringilla nunc, nec molestie risus finibus sed. Aliquam a cursus elit. Aenean convallis dui vitae eros elementum pretium. Aenean dolor sapien, laoreet id urna vel, finibus imperdiet ex. Pellentesque suscipit justo eu augue commodo tempor. Ut id facilisis massa. "# | |
| ] | |
| static let markdownTests = [#"***[They](https://apple.com) ~are~ `combinable`***"#, | |
| #"*Italics*"#, | |
| #"**Bold**"#, | |
| #"~Strikethrough~"#, | |
| #"`Code`"#, | |
| #"[Link](https://apple.com)"#, | |
| #""" | |
| Something long so scrolling is required. Lorem ipsum dolor sit amet, consectetur adipiscing elit. | |
| ### Can't do headings, numbered lists or images yet. | |
| Curabitur ac maximus enim, eget sodales ex. Maecenas at sem eget leo commodo suscipit. Praesent non aliquet sem. Cras et erat dapibus, semper turpis at, dictum ligula. Cras faucibus fringilla nunc, nec molestie risus finibus sed. Aliquam a cursus elit. Aenean convallis dui vitae eros elementum pretium. Aenean dolor sapien, laoreet id urna vel, finibus imperdiet ex. Pellentesque suscipit justo eu augue commodo tempor. Ut id facilisis massa. | |
| """#, | |
| #"Is this long enough?"#, | |
| #"How about now?"#, | |
| #"Something long so scrolling is required. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce at urna vitae leo viverra fermentum. Maecenas nec porttitor massa, non feugiat turpis. Donec pretium, enim quis porttitor feugiat, diam. Nam vehicula lectus nisi, a lacinia lacus euismod id. Curabitur rutrum nunc in purus rutrum elementum. Curabitur ac maximus enim, eget sodales ex. Maecenas at sem eget leo commodo suscipit. Praesent non aliquet sem. Cras et erat dapibus, semper turpis at, dictum ligula. Cras faucibus fringilla nunc, nec molestie risus finibus sed. Aliquam a cursus elit. Aenean convallis dui vitae eros elementum pretium. Aenean dolor sapien, laoreet id urna vel, finibus imperdiet ex. Pellentesque suscipit justo eu augue commodo tempor. Ut id facilisis massa. "#, | |
| #"Is thiiiiiis long enough?"#, | |
| #"Really How about now?"#, | |
| #"Something long so scrolling is required. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce at urna vitae leo viverra fermentum. Maecenas nec porttitor massa, non feugiat turpis. Donec pretium, enim quis porttitor feugiat, diam. Nam vehicula lectus nisi, a lacinia lacus euismod id. Curabitur rutrum nunc in purus rutrumlla nunc, nec molestie risus finibus sed. Aliquam a cursus elit. Aenean convallis dui vitae eros elementum pretium. Aenean dolor sapien, laoreet id urna vel, finibus imperdiet ex. Pellentesque suscipit justo eu augue commodo tempor. Ut id facilisis massa. "#, | |
| ] | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment