Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Turn some parts of UILabel to act like a UIButton? [duplicate]

I have an attributed string UILabel, I was able to color some parts of the text

let text = "Why did \(event) give \(event2) a 5 stars review? Details here. "
let linkTextWithColor = "Why did"
let range = (text as NSString).rangeOfString(linkTextWithColor)

let attributedString = NSMutableAttributedString(string:text)
attributedString.addAttribute(NSForegroundColorAttributeName, value: UIColor.blackColor() , range: range)

labelEvent.attributedText = attributedString

Now I want to make some parts of the text tappable, like a UIButton, how to do this ?

Example 1

example 1

Example 2

example 2

I need to have blue text to be responding to touch, and to run a specific function, like a UIButton. help is really appreciated, thanks.

like image 912
DeyaEldeen Avatar asked Jun 21 '16 11:06

DeyaEldeen


People also ask

How do I change my UILabel?

To change the font or the size of a UILabel in a Storyboard or . XIB file, open it in the interface builder. Select the label and then open up the Attribute Inspector (CMD + Option + 5). Select the button on the font box and then you can change your text size or font.

How do you add padding to UILabel?

If you have created an UILabel programmatically, replace the UILabel class with the PaddingLabel and add the padding: // Init Label let label = PaddingLabel() label. backgroundColor = . black label.

What is UILabel?

A view that displays one or more lines of informational text.


3 Answers

What you want to do is use an attributed string with a text view to make a link that will act as a button.

let attributedString = NSMutableAttributedString(string: "Some string with link", attributes: [<attributes>])

Then set a part of it as a link, and customize it's appearance using the linkAttributes property of the Text View. Because this is a button and not an actual link we just put a dummy url in for the link so we can handle it in our delegate later.

attributedString.setSubstringAsLink(substring: "link", linkURL: "CUSTOM://WHATEVER")
let linkAttributes: [String : AnyObject] = [NSForegroundColorAttributeName : .redColor(), NSUnderlineColorAttributeName : .redColor(), NSUnderlineStyleAttributeName : NSUnderlineStyle.StyleSingle.rawValue]
textView.linkTextAttributes = linkAttributes
textView.attributedText = attributedString
textView.selectable = true
textView.editable = false
textView.userInteractionEnabled = true

Finally in text view delegate we will check for the scheme and perform some action.

func textView(textView: UITextView, shouldInteractWithURL URL: NSURL, inRange characterRange: NSRange) -> Bool {
    if URL.scheme == "CUSTOM" {
       // Do your button actions here
    }
    return true
}

Extension for setSubstringAsLink:

extension NSMutableAttributedString {
    // Set part of string as URL
    public func setSubstringAsLink(substring substring: String, linkURL: String) -> Bool {
        let range = self.mutableString.rangeOfString(substring)
        if range.location != NSNotFound {
            self.addAttribute(NSLinkAttributeName, value: linkURL, range: range)
            return true
        }
        return false
    }
}
like image 70
Max Avatar answered Oct 19 '22 05:10

Max


Let's say you have a UILabel with text "abc123", and you want "abc" to function as a UIButton.

  • Calculate and store the rectangle that contains "abc".
  • Add a UITapGestureRecognizer to the UILabel.
  • When the UILabelis tapped, check if the tap is within the rectangle.

static func getRect(str: NSAttributedString, range: NSRange, maxWidth: CGFloat) -> CGRect {
    let textStorage = NSTextStorage(attributedString: str)
    let textContainer = NSTextContainer(size: CGSize(width: maxWidth, height: CGFloat.max))
    let layoutManager = NSLayoutManager()       
    layoutManager.addTextContainer(textContainer)
    textStorage.addLayoutManager(layoutManager)     
    textContainer.lineFragmentPadding = 0       
    let pointer = UnsafeMutablePointer<NSRange>.alloc(1)
    layoutManager.characterRangeForGlyphRange(range, actualGlyphRange: pointer)     
    return layoutManager.boundingRectForGlyphRange(pointer.move(), inTextContainer: textContainer)
}

let rect1 = getRect(label.attributedText!, range: NSMakeRange(0, 3), maxWidth: label.frame.width)

label.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(MyClass.tappedLabel(_:))))

func tappedLabel(sender: UITapGestureRecognizer) {
    if rect1.contains(sender.locationInView(sender.view)) {
        // ...
    }
}
like image 11
Code Avatar answered Oct 19 '22 05:10

Code


I recommend you try this library out

https://github.com/null09264/FRHyperLabel

Great library, easy to use and has few built in examples for you to try out. Examples are in both Objective-c and Swift

Example in Swift

 let str = "This is a random bit of text"
        let attributes = [NSForegroundColorAttributeName: UIColor.blackColor(),
                          NSFontAttributeName: UIFont.systemFontOfSize(15)]
        confirmLabel.attributedText = NSAttributedString(string: str, attributes: attributes)

        let handler = {
            (hyperLabel: FRHyperLabel!, substring: String!) -> Void in

            //action here
        }
        //Step 3: Add link substrings
        confirmLabel.setLinksForSubstrings(["random"], withLinkHandler: handler)

Edit:

If you want to get rid of the underline, best way to do this is to follow the advice that DeyaEldeen gave in the comment.

If you go to the .m file of FRHyperLabel, go to this method

- (void)checkInitialization {
    if (!self.handlerDictionary) {
        self.handlerDictionary = [NSMutableDictionary new];
    }

    if (!self.userInteractionEnabled) {
        self.userInteractionEnabled = YES;
    }

    if (!self.linkAttributeDefault) {
        self.linkAttributeDefault = @{NSForegroundColorAttributeName: FRHyperLabelLinkColorDefault,
                                      NSUnderlineStyleAttributeName: @(NSUnderlineStyleSingle)};
    }

    if (!self.linkAttributeHighlight) {
        self.linkAttributeHighlight = @{NSForegroundColorAttributeName: FRHyperLabelLinkColorHighlight,
                                        NSUnderlineStyleAttributeName: @(NSUnderlineStyleSingle)};
    }
}

And you can just remove this

NSUnderlineStyleAttributeName: @(NSUnderlineStyleSingle)

from the attributes

like image 9
AdamM Avatar answered Oct 19 '22 05:10

AdamM