{"id":18538138,"url":"https://github.com/githawkapp/styledtextkit","last_synced_at":"2025-04-08T12:08:14.243Z","repository":{"id":46620393,"uuid":"116085301","full_name":"GitHawkApp/StyledTextKit","owner":"GitHawkApp","description":"Declarative building and fast rendering attributed string library.","archived":false,"fork":false,"pushed_at":"2022-03-03T08:34:46.000Z","size":3326,"stargazers_count":1224,"open_issues_count":19,"forks_count":58,"subscribers_count":22,"default_branch":"master","last_synced_at":"2024-10-29T20:34:00.110Z","etag":null,"topics":["githawk","nsattributedstring","swift","text","textkit"],"latest_commit_sha":null,"homepage":"http://githawk.com","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/GitHawkApp.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-01-03T03:12:23.000Z","updated_at":"2024-10-08T14:05:46.000Z","dependencies_parsed_at":"2022-08-26T08:51:04.522Z","dependency_job_id":null,"html_url":"https://github.com/GitHawkApp/StyledTextKit","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GitHawkApp%2FStyledTextKit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GitHawkApp%2FStyledTextKit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GitHawkApp%2FStyledTextKit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GitHawkApp%2FStyledTextKit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/GitHawkApp","download_url":"https://codeload.github.com/GitHawkApp/StyledTextKit/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247838444,"owners_count":21004580,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["githawk","nsattributedstring","swift","text","textkit"],"created_at":"2024-11-06T19:42:30.385Z","updated_at":"2025-04-08T12:08:14.226Z","avatar_url":"https://github.com/GitHawkApp.png","language":"Swift","readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"/images/banner.png\" /\u003e\n\u003c/p\u003e\n\n`StyledTextKit` is a declarative attributed string library for fast rendering and easy string building. It serves as a simple replacement to `NSAttributedString` and `UILabel` for background-thread sizing and bitmap caching.\n\n## Features\n\n- Declarative attributed string building API\n- Find text sizes on a background thread without sanitizer warnings\n- Cache rendered text bitmaps for improved performance\n- Custom attribute interaction handling (link taps, etc)\n\n## Installation\n\nJust add `StyledTextKit` to your Podfile and install. Done!\n\n```ruby\npod 'StyledTextKit'\n```\n\n## Usage\n\n### Building `NSAttributedString`s\n\n`StyledTextKit` lets you build complex `NSAttributedString`s:\n\n- Append `NSAttributedString`s or `String`s while re-using the string's current attributes, saving you from repetitive `.font` and `.foregroundColor` styling.\n- Intermix complex font traits like **bold** and _italics_ to get _**bold italics**_.\n- Handle dynamic text size at string render time. Lets you build the string once and re-render it on device text-size changes.\n- Call `save()` and `restore()` to push/pop style settings, letting you build complex text styles without complex code.\n\n```swift\nlet attributedString = StyledTextBuilder(text: \"Foo \")\n  .save()\n  .add(text: \"bar\", traits: [.traitBold])\n  .restore()\n  .add(text: \" baz!\")\n  .build()\n  .render(contentSizeCategory: .large)\n```\n\n\u003e Foo **bar** baz!\n\nThe basic steps are:\n\n- Create a `StyledTextBuilder`\n- Add `StyledText` objects\n- Call `build()` when finished to generate a `StyledTextString` object\n- Call `render(contentSizeCategory:)` to create an `NSAttributedString`\n\n### Rendering Text Bitmaps\n\nCreate a `StyledTextRenderer` for sizing and rendering text by initializing it with a `StyledTextString` and a `UIContentSizeCategory`.\n\n```swift\nlet renderer = StyledTextRenderer(\n  string: string,\n  contentSizeCategory: .large\n)\n```\n\nOnce created, you can easily get the size of the text constrained to a width:\n\n```swift\nlet size = renderer.size(in: 320)\n```\n\nYou can also get a bitmap of the text:\n\n```swift\nlet result = renderer.render(for: 320)\nview.layer.contents = result.image\n```\n\n### StyledTextView\n\nTo make rendering and layout of text in a `UIView` simpler, use `StyledTextView` to manage display as well as interactions. All you need is a `StyledTextRenderer` and a width and you're set!\n\n```swift\nlet view = StyledTextView()\nview.configure(with: renderer, width: 320)\n```\n\nSet a delegate on the view to handle tap and long presses:\n\n```swift\nview.delegate = self\n\n// StyledTextViewDelegate\nfunc didTap(view: StyledTextView, attributes: [NSAttributedStringKey: Any], point: CGPoint) {\n  guard let link = attributes[.link] else { return }\n  show(SFSafariViewController(url: link))\n}\n```\n\n## Background Rendering\n\n`StyledTextKit` exists to do background sizing and rendering of text content so that scrolling large amounts of text is buttery smooth. The typical pipeline to do this is:\n\n1. Get the current width and `UIContentSizeCategory`\n2. Go to a background queue\n3. Build text\n4. Warm caches\n5. Return to the main queue\n6. Configure your views\n\n```swift\n// ViewController.swift\n\nlet width = view.bounds.width\nlet contentSizeCategory = UIApplication.shared.preferredContentSizeCategory\n\nDispatchQueue.global().async {\n  let builder = StyledTextBuilder(...)\n  let renderer = StyledTextRenderer(string: builder.build(), contentSizeCategory: contentSizeCategory)\n    .warm(width: width) // warms the size cache\n\n  DispatchQueue.main.async {\n    self.textView.configure(with: renderer, width: width)\n  }\n}\n```\n\n## FAQ\n\n\u003e Why not use `UITextView`?\n\nPrior to iOS 7, `UITextView` just used WebKit under the hood and was terribly slow. Now that it uses TextKit, it's significantly faster but still requires all sizing and rendering be done on the main thread.\n\nFor apps with lots of text embedded in `UITableViewCell`s or `UICollectionViewCell`s, `UITextView` bring scrolling to a grinding halt.\n\n## Acknowledgements\n\n- [@ocrickard](https://github.com/ocrickard) who built [ComponentTextKit](https://github.com/facebook/componentkit/tree/master/ComponentTextKit) and taught me the basics.\n- Created with ❤️ by [Ryan Nystrom](https://twitter.com/_ryannystrom)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgithawkapp%2Fstyledtextkit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgithawkapp%2Fstyledtextkit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgithawkapp%2Fstyledtextkit/lists"}