Convert text with HTML tags, links, hashtags, mentions into NSAttributedString. Make them clickable with UILabel drop-in replacement.

Overview


Language: Swift CocoaPods Carthage

Atributika is an easy and painless way to build NSAttributedString. It is able to detect HTML-like tags, links, phone numbers, hashtags, any regex or even standard ios data detectors and style them with various attributes like font, color, etc. Atributika comes with drop-in label replacement AttributedLabel which is able to make any detection clickable

Intro

NSAttributedString is really powerful but still a low level API which requires a lot of work to setup things. It is especially painful if string is template and real content is known only in runtime. If you are dealing with localizations, it is also not easy to build NSAttributedString.

Oh wait, but you can use Atributika!

let b = Style("b").font(.boldSystemFont(ofSize: 20)).foregroundColor(.red)
        
label.attributedText = "Hello <b>World</b>!!!".style(tags: b).attributedString

Yeah, that's much better. Atributika is easy, declarative, flexible and covers all the raw edges for you.

Features

  • NEW! AttributedLabel is a drop-in label replacement which makes detections clickable and style them dynamically for normal/highlighted/disabled states.
  • detect and style HTML-like tags using custom speedy parser
  • detect and style hashtags and mentions (i.e. #something and @someone)
  • detect and style links and phone numbers
  • detect and style regex and NSDataDetector patterns
  • style whole string or just particular ranges
  • ... and you can chain all above to parse some uber strings!
  • clean and expressive api to build styles
  • separate set of detection utils, in case you want to use just them
  • + operator to concatenate NSAttributedString with other attributed or regular strings
  • works on iOS, tvOS, watchOS, macOS

Examples

Detect and style tags, provide base style for the rest of string, don't forget about special html symbols

let redColor = UIColor(red:(0xD0 / 255.0), green: (0x02 / 255.0), blue:(0x1B / 255.0), alpha:1.0)
let a = Style("a").foregroundColor(redColor)

let font = UIFont(name: "AvenirNext-Regular", size: 24)!
let grayColor = UIColor(white: 0x66 / 255.0, alpha: 1)
let all = Style.font(font).foregroundColor(grayColor)

let str = "<a>&lt;a&gt;</a>tributik<a>&lt;/a&gt;</a>"
    .style(tags: a)
    .styleAll(all)
    .attributedString

Detect and style hashtags and mentions

let str = "#Hello @World!!!"
    .styleHashtags(Style.font(.boldSystemFont(ofSize: 45)))
    .styleMentions(Style.foregroundColor(.red))
    .attributedString

Detect and style links

let str = "Check this website http://google.com"
    .styleLinks(Style.foregroundColor(.blue))
    .attributedString

Detect and style phone numbers

let str = "Call me (888)555-5512"
    .stylePhoneNumbers(Style.foregroundColor(.red))
    .attributedString

Uber String

    let links = Style.foregroundColor(.blue)
    let phoneNumbers = Style.backgroundColor(.yellow)
    let mentions = Style.font(.italicSystemFont(ofSize: 12)).foregroundColor(.black)
    let b = Style("b").font(.boldSystemFont(ofSize: 12))
    let u = Style("u").underlineStyle(.styleSingle)
    let all = Style.font(.systemFont(ofSize: 12)).foregroundColor(.gray)
    
    let str = "@all I found <u>really</u> nice framework to manage attributed strings. It is called <b>Atributika</b>. Call me if you want to know more (123)456-7890 #swift #nsattributedstring https://github.com/psharanda/Atributika"
        .style(tags: u, b)
        .styleMentions(mentions)
        .styleHashtags(links)
        .styleLinks(links)
        .stylePhoneNumbers(phoneNumbers)
        .styleAll(all)
        .attributedString

AttributedText

Atributika APIs styleXXX produce AttributedText which can be converted into NSAttributedString. Basically AttributedText just contains string, base style and all the detections.

AttributedLabel

AttributedLabel is able to display AttributedText and makes detections clickable if style contains any attributes for .highlighted

let tweetLabel = AttributedLabel()

tweetLabel.numberOfLines = 0

let all = Style.font(.systemFont(ofSize: 20))
let link = Style("a")
    .foregroundColor(.blue, .normal)
    .foregroundColor(.brown, .highlighted) // <-- detections with this style will be clickable now

tweetLabel.attributedText = "@e2F If only Bradley's arm was longer. Best photo ever.😊 #oscars https://pic.twitter.com/C9U5NOtGap<br>Check this <a href=\"https://github.com/psharanda/Atributika\">link</a>"
    .style(tags: link)
    .styleHashtags(link)
    .styleMentions(link)
    .styleLinks(link)
    .styleAll(all)

tweetLabel.onClick = { label, detection in
            switch detection.type {
            case .hashtag(let tag):
                if let url = URL(string: "https://twitter.com/hashtag/\(tag)") {
                    UIApplication.shared.openURL(url)
                }
            case .mention(let name):
                if let url = URL(string: "https://twitter.com/\(name)") {
                    UIApplication.shared.openURL(url)
                }
            case .link(let url):
                UIApplication.shared.openURL(url)
            case .tag(let tag):
                if tag.name == "a", let href = tag.attributes["href"], let url = URL(string: href) {
                    UIApplication.shared.openURL(url)
                }
            default:
                break
            }
        }

view.addSubview(tweetLabel)

Requirements

Current version is compatible with:

  • Swift 4.0+ (for Swift 3.2 use swift-3.2 branch)
  • iOS 8.0 or later
  • tvOS 9.0 or later
  • watchOS 2.0 or later
  • macOS 10.10 or later

Note: AttributedLabel works only on iOS

Why does Atributika have one 't' in its name?

Because in Belarusian/Russian we have one letter 't' (атрыбутыка/атрибутика). So basically it is transcription, not real word.

Integration

Carthage

Add github "psharanda/Atributika" to your Cartfile

CocoaPods

Atributika is available through CocoaPods. To install it, simply add the following line to your Podfile:

pod "Atributika"

Manual

  1. Add Atributika to you project as a submodule using git submodule add https://github.com/psharanda/Atributika.git
  2. Open the Atributika folder & drag Atributika.xcodeproj into your project tree
  3. Add Atributika.framework to your target's Link Binary with Libraries Build Phase
  4. Import Atributika with import Atributika and you're ready to go

License

Atributika is available under the MIT license. See the LICENSE file for more info.

Comments
  • 4.4.0 And missing Symbols

    4.4.0 And missing Symbols

    Just pod install'd 4.4.0 and am getting the following:

    Undefined symbols for architecture arm64:
      "protocol witness table for __C.NSAttributedStringKey : Swift.Hashable in Foundation", referenced from:
          function signature specialization <Arg[0] = Owned To Guaranteed, Arg[1] = Dead> of generic specialization <preserving fragile attribute, Atributika.StyleType, [__C.NSAttributedStringKey : Any]> of static (extension in Swift):Swift._NativeDictionaryBuffer< where A: Swift.Hashable>.fromArray([(A, B)]) -> Swift._NativeDictionaryBuffer<A, B> in RegulationDetailController.o
    ld: symbol(s) not found for architecture arm64
    clang: error: linker command failed with exit code 1 (use -v to see invocation)
    

    I'm not sure this is actually Atributika's problem yet but it's in the error so I thought I"d put it here while I try to track down what is going on. Anyone else see this?

    opened by rblalock 17
  • Detection Button frame issue when using custom font

    Detection Button frame issue when using custom font

    I have integrated this in tableview cells with automatic layout. Text is displayed properly, however button frame for touch detection appears to be incorrect. PFA the log and the xcode view debugger image. You can check 3 butons frame's. Frame for the 5 points is completely off the track.

    button issue

    points1.txt

    bug 
    opened by Ankish 11
  • A-Tags

    A-Tags

    Hey! I'm trying to figure out how to convert <a> Tags into clickable links. I tried .style(links:) but that wouldn't work. Do I miss something very obvious?

    opened by 343max 10
  • Style.swift Crash

    Style.swift Crash

    Hi , Style.Swift line 84 and AttributedText.swift line 99 crash , swift 4.1 , Xcode 9 latest version , ios 11 , just copy pasted your "link" and "all" code and crashesh without doing anything else here's the code : `let tweetLabel = AttributedLabel()

        let all = Style.font(.systemFont(ofSize: 20))
        let link = Style
            .foregroundColor(.blue, .normal)
    
    
        tweetLabel.attributedText = "@Hey"
            .styleHashtags(link)
            .styleMentions(link)
            .styleLinks(link)
            .styleAll(all)`
    

    adding .foregroundColor(.brown, .highlighted) to link will result. style.swift to crash o.w AttributeText.swift does

    opened by Mahan3340 10
  • styleMentions returning wrong array detection when used with Korean tags

    styleMentions returning wrong array detection when used with Korean tags

    I have used Atributika Pod in achieving one of the task in my project. I have attributed textview in which mentions, links, hashtags are used. While resetting the attributes of the textview and sending it over the web service I need to extract all the attributed text of the textview which I do using styleMentions(which returns detections array) of Atributika. When mentions are in english it returns one detection for one mention but when Korean mentions are there it returns multiple detections sometimes. Please find textfile attached of the array detections. If you search for the key "mention" you will get 5 results whereas I should have only two one for each mention.

    I have used these two lines of code to extract the detections: let attArray = self.textviewEditMode?.attributedText.styleMentions(.backgroundColor(Fp_s29.color)) let detections = attArray?.detections whereas, textviewEditMode- is my UITextview Fp_s29.color- is my predefined color

    Please let me know if something needs to be done. Thank you!

    mentionsDetection.zip

    opened by manisingh41 9
  • Handling unavailable fonts/font trait combinations (styles)

    Handling unavailable fonts/font trait combinations (styles)

    Hi there!

    I've been trying out Atributika to see if it could be a fit for my project to replace the current (and slow) implementation with plain NSAttributedString (from HTML).

    I've got it working ~90%. An issue I have been facing since implementing this feature, even with the NSAttributedString implementation, is that I (currently) do not own the font we use in all different combinations of bold, italic, underlined, etc. Though the one we are currently mostly facing is bold + italic.

    In our current implementation we used the following code snippet to basically fall back to a similarly looking free font in such cases:

    extension NSMutableAttributedString {
        func setBaseFont(baseFont: UIFont, preserveFontSizes: Bool = false) {
            let baseDescriptor = baseFont.fontDescriptor
            let wholeRange = NSRange(location: 0, length: length)
            let fallbackFont = UIFont(name: "HelveticaNeue-Light", size: 15)!
    
            beginEditing()
            enumerateAttribute(.font, in: wholeRange, options: []) { object, range, _ in
                guard let font = object as? UIFont else { return }
                var descriptor: UIFontDescriptor
                var newSize: CGFloat
                let traits = font.fontDescriptor.symbolicTraits
    
                if traits.contains(.traitItalic) {
                    descriptor = fallbackFont.fontDescriptor.withSymbolicTraits(traits)!
                    newSize = descriptor.pointSize
                } else if traits.contains(.traitBold) {
                    descriptor = baseDescriptor.withSymbolicTraits(traits)!
                    newSize = preserveFontSizes ? descriptor.pointSize : baseDescriptor.pointSize
                } else {
                    descriptor = baseDescriptor
                    newSize = preserveFontSizes ? descriptor.pointSize : baseDescriptor.pointSize
                }
    
                let newFont = UIFont(descriptor: descriptor, size: newSize)
                self.removeAttribute(.font, range: range)
                self.addAttribute(.font, value: newFont, range: range)
            }
            endEditing()
        }
    }
    

    Is there something similar to achieve this in Atributika? I know that the easiest way would be to buy the missing combos, but I currently do not have the budget for that.

    Could this be done using the tuner: variant of .style(...)?

    I hope you could help me out with this.

    Happy holidays!

    enhancement 
    opened by philhinco 7
  • Index out of bounds on Add Detection button for strings with emoji and link

    Index out of bounds on Add Detection button for strings with emoji and link

    I don't know if it's only me. But text with emoji causes a crash on addDetectionAreaButton:

    Here's how a similar one was solved 😄 \nhttps://medium.com/@narcelio/solving-decred-mockingbird-puzzle-5366efeaeed7\n
    
    opened by denniskeithgaso 7
  • Tags at start of text apply throughout text.

    Tags at start of text apply throughout text.

    Starting text with a tag applies that tag throughout, even though there is a matching end tag.

    "Save $1.00 on any order!" comes out all bold.

    "Save $1.00 on any order!" correctly bolds only the two sections.

    With this call:

                let desc = Atributika(text: text,
                                      styles: [
                                        "b" : [.font( UIFont.boldSystemFont(ofSize: 14))]
                    ],
                                      baseStyle: [
                                        .font( UIFont.systemFont(ofSize: 14)), .foregroundColor(UIColor.red)
                    ])
                    .buildAttributedString()
    
    opened by graham-perks-snap 6
  • Emoji Support

    Emoji Support

    I'm currently working with Atributika and my use-case specifically applies to the hashtag functionality. I have noticed that the parser doesn't seem to include emojis in the tag and I was wondering if any of you have a fix/workaround for this?

    To just give you all an example, let's say the hashtag I'm working with is #Atributika❤️, but the parser will only parse up to #Atributika and ignores the emoji.

    let font = Style.font(UIFont.init(name: "OpenSans", size: 12)!).foregroundColor(UIColor.lightGray)
    
    let contentStyling = Style("a")
        .foregroundColor(UIColor.lightGray, .normal)
        .foregroundColor(UIColor.white, .highlighted)
    
    label.lineBreakMode = .byWordWrapping
    label.numberOfLines = 0
    label.attributedText = #Atributika❤️
        .style(tags: contentStyling)
        .styleHashtags(contentStyling)
        .styleMentions(contentStyling)
        .styleLinks(contentStyling)
        .styleAll(font)
    
    label.frame = CGRect(x: 185, y: 140, width: 165, height: 90)
    
    label.onClick = { label, detection in
                switch detection.type {
                case .hashtag(let tag):
                    var passTag = ["tag":"#\(tag)"]
                    self.tapTag = true
                    self.dismiss(animated: true, completion: nil)
                    SVProgressHUD.show(withStatus: "Loading projects")
                    NotificationCenter.default.post(name: NSNotification.Name(rawValue: "NotificationID"), object: nil, userInfo: passTag as [AnyHashable : Any])
    
                case .mention( _): break
                case .link( _): break
                case .tag( _): break
                default: break
                }
            }
    
    view.addSubview(label)
    
    
    opened by qxtaiba 5
  • Paragraph tag (<p>) doesn't start from new line

    Paragraph tag (

    ) doesn't start from new line

    The below text with paragraph tags doesn't start from new line on every

    tag.

    <p> The first line of the text.</p><p>This second line should start a new paragraph. but it doesn't</p>

    How can I get it working?

    opened by tarun-personatech 5
  • Missing libSwiftCoreGraphics.tbd in project's

    Missing libSwiftCoreGraphics.tbd in project's

    When I upgrade my Xcode to 14, my app crashed and Get an error message: dyld: Library not loaded: /usr/lib/swift/libswiftCoreGraphics.dylib

    It's only happen on devices with iOS version below 13,like iOS 12/11.

    opened by zoloyy 0
  • Fix infinite loop when using `<` or `&` characters with diacritic

    Fix infinite loop when using `<` or `&` characters with diacritic

    The infinite loop problem is caused by different diacritic handling policies. NSScanner.scanUpToCharacters(from:) is not diacritic sensitive but `NSScanner.scanString(_:) is diacritic sensitive.

    opened by wplong11 0
  • Not support SwiftUI

    Not support SwiftUI

    I used Atributika and it is not supported SwiftUI and text is not showing.

    func makeUIView(context: UIViewRepresentableContext) -> UIView { let view = UIView(frame: .zero) view.backgroundColor = .yellow let label = AttributedLabel() label.numberOfLines = 0 label.backgroundColor = .red label.lineBreakMode = .byWordWrapping label.font = type.font label.attributedText = text .attributedText(for: type, alignment: alignment, textColor: textColor, linkColor: linkColor) label.clipsToBounds = true label.sizeToFit() view.addSubview(label)
    label.translatesAutoresizingMaskIntoConstraints = false label.heightAnchor.constraint(equalTo: view.heightAnchor).isActive = true label.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true return view }

    func updateUIView(_ label: UIView, context: UIViewRepresentableContext<AtributikaView>) {
    
    }
    
    opened by sharvanksapient 0
  • tag a has problem when set title tag a like url

    tag a has problem when set title tag a like url

    when string tag a is <a href="https://food.trueid.net/detail/WeX36y1rkg7J">www.food.trueid.net Atributika detect title not url in href

    opened by sk-chanch 1
Releases(4.10.1)
Owner
Pavel Sharanda
iOS Developer
Pavel Sharanda
LDOMarkdownParser - Parse (some) markdown attributes into an NSAttributedString

LDOMarkdownParser Description Convert markdown text styling into an NSAttributed

Lurado 1 Feb 4, 2022
An easy way to add mentions to uitextview like Facebook and Instagram

OEMentions An easy way to add mentions to uitextview like Facebook and Instagram. It also include a tableview to show the users list to choose from. T

Omar Alessa 48 Oct 23, 2022
SZMentionsSwift is a lightweight mentions library for iOS.

SZMentionsSwift is a lightweight mentions library for iOS. This library was built to assist with the adding, removing and editing of a mention within a textview.

Steven Zweier 122 Dec 12, 2022
An iOS app to turn typed text into images of handwritten text in your own handwriting style.

Text-to-Handwritting © 2021 by Daniel Christopher Long An iOS app to turn typed text into images of handwritten text in your own handwriting style. ht

Daniel Long 11 Dec 29, 2022
Leverages Apple's Swift-based Markdown parser to output NSAttributedString.

Markdownosaur ?? Markdownosaur uses Apple's excellent and relatively new Swift Markdown library to analyze a Markdown source, and then takes that anal

Christian Selig 232 Dec 20, 2022
Programmatic creation of NSAttributedString doesn't have to be a pain

Tribute let string = NSMutableAttributedString().add("Hello ") { $0.font = .systemFontOfSize(20) $0.color = .redColor() $0.underline = .St

Sash Zats 63 Sep 24, 2022
Type strict builder class for NSAttributedString.

StringStylizer Type strict builder class for NSAttributedString. What's this? StringStylizer makes NSAttributedString more intuitive with Method chain

Kazuhiro Hayashi 75 Nov 11, 2022
AttributedText is a Swift µpackage that provides NSAttributedString rendering in SwiftUI by wrapping either an NSTextView or a UITextView depending on the platform.

AttributedText AttributedText is a Swift µpackage that provides NSAttributedString rendering in SwiftUI by wrapping either an NSTextView or a UITextVi

null 1 Jul 18, 2022
🌍⏩📄 Convert ISO8859 1-16 Encoded Text to String in Swift. Supports iOS, tvOS, watchOS and macOS.

ISO8859 Convert ISO8859 1-16 Encoded Text to String in Swift. Usage let encoding = ISO8859.part1 let string = String([...], iso8859Encoding: encoding)

Devran Cosmo Uenal 18 Jan 2, 2023
RichEditorView is a simple, modular, drop-in UIView subclass for Rich Text Editing.

RichEditorView RichEditorView is a simple, modular, drop-in UIView subclass for Rich Text Editing. Written in Swift 4 Supports iOS 8+ through Cocoapod

Caesar Wirth 1.8k Dec 24, 2022
Get any text on your screen into your clipboard.

macOCR macOCR is a command line app that enables you to turn any text on your screen into text on your clipboard. When you envoke the ocr command, a "

Marcus S 1.9k Dec 29, 2022
Easily show RichText(html) in SwiftUI

RichText LightMode DarkMode Code import SwiftUI

null 82 Jan 7, 2023
An Objective-C framework for converting Markdown to HTML.

MMMarkdown MMMarkdown is an Objective-C framework for converting Markdown to HTML. It is compatible with OS X 10.7+, iOS 8.0+, tvOS, and watchOS. Unli

Matt Diephouse 1.2k Dec 14, 2022
Methods to allow using HTML code with CoreText

DTCoreText This project aims to duplicate the methods present on Mac OSX which allow creation of NSAttributedString from HTML code on iOS. The project

Cocoanetics 6.2k Jan 6, 2023
Twitter Text Libraries. This code is used at Twitter to tokenize and parse text to meet the expectations for what can be used on the platform.

twitter-text This repository is a collection of libraries and conformance tests to standardize parsing of Tweet text. It synchronizes development, tes

Twitter 2.9k Dec 27, 2022
Powerful text framework for iOS to display and edit rich text.

YYText Powerful text framework for iOS to display and edit rich text. (It's a component of YYKit) Features UILabel and UITextView API compatible High

null 8.8k Jan 4, 2023
A quick helper for setting attributed texts to UILabel.

UILabelAttributedTextHelper A quick helper for setting attributed texts to UILabel. Sample usage: label.setAttributedText( leadingText: "H

Glenn Posadas 5 Aug 24, 2022
A category on NSString to convert Emoji Cheat Sheet codes to their equivalent Unicode characters

NSString+Emojize A category on NSString to turn codes from Emoji Cheat Sheet into Unicode emoji characters. Getting Started In order to use NSString+E

DIY.org 643 Sep 8, 2022
Marky Mark is a parser written in Swift that converts markdown into native views.

Marky Mark is a parser written in Swift that converts markdown into native views. The way it looks it highly customizable and the supported markdown syntax is easy to extend.

M2mobi 287 Nov 29, 2022