0

I'm making a UITableViewCell for some activity feed objects, to give you an idea they're going to be like the Facebook posts where you have multiple links in one post.

In my case there are going to be two links to other UIViewController for each post and one plain UILabel that connects the two and explains the connection (such as "X has commented on Y's post") where you could tap both X and Y for some actions to happen.

As right now, I just made 3 separate UILabels. The problem with that is that I'm not sure how to handle names that are too long in multiple lines.

Meaning if for example instead of X, the post was "XXXXXXXXXXXXXXXXX has commented on Y's post", then "has commented on Y's post" would need to go on another line.

As right now I just link the 3 UILabels with constraints such that they're next to each other but that wouldn't work when they're too long.

If you have any idea on how could I approach this issue, it would be really appreciated if you could let me know.

Thanks in advance.

Mahendra
  • 8,448
  • 3
  • 33
  • 56
Giulio Colleluori
  • 1,261
  • 2
  • 10
  • 16

2 Answers2

1

There are too many labels, I think you can use this extension:

extension NSMutableAttributedString {

   public func setAsLink(textToFind:String, linkURL:String) -> Bool {

       let foundRange = self.mutableString.rangeOfString(textToFind)
       if foundRange.location != NSNotFound {
           self.addAttribute(NSLinkAttributeName, value: linkURL, range: foundRange)
           return true
       }
       return false
   }
}

Then you can do:

let labelFont = UIFont(name: "HelveticaNeue-Bold", size: 18)
let attributes :[String:AnyObject] = [NSFontAttributeName : labelFont!]
let attrString = NSAttributedString(string:"foo www.google.com", attributes: attributes)
let urlPath: String = "http://www.google.com"
let url: NSURL = NSURL(string: urlPath)!
attrString.setAsLink("www.google.com", linkURL:url) 
myLabel.attributedText = attrString

UPDATE: (after your comments)

If you need to intercept urllink you can transform your label to textView (UITextView), set it the delegate and handle the shouldInteractWithURL method:

class ViewController: UIViewController, UITextViewDelegate { 
... // on your code do:
    myTextView.delegate = self
...
func textView(textView: UITextView!, shouldInteractWithURL URL: NSURL!, inRange characterRange: NSRange) -> Bool {

   if URL.scheme == "http://www.google.com" {
      //do whatever you want
      launchMyMethodForThisUrl()
   }

}
Alessandro Ornano
  • 34,887
  • 11
  • 106
  • 133
  • Thanks for the answer. For link, I just meant link to an action or method such as `showFirstObject()` . Sorry about the confusion. Could I still use your implementation you think? Can I add a tap action on just some partial text of a `UILabel`? – Giulio Colleluori Apr 30 '16 at 10:11
  • Grazie mille! However as I was saying on the other answer I'm actually not interacting at all with URLs. I just need a Label such as "A something B" where I could tap on A and a detailed ViewController for A would be presented, tap on B and anther ViewController for the B object would be presented. So basically I just need to add two different tap actions to parts of the UILabel text. I also need to make "tappable" words in bold to show that you can tap on them. Does that make sense? – Giulio Colleluori Apr 30 '16 at 10:35
  • Remember you can use UITapGestureRecognizer to make a label tappable, sincerely it's not a good attitude if you dont know the exact contents of that label. If you want to make "clickable" only part of your contents, you just need the hyperlinks available only in attributedstrings. Choose your destiny, I think in this case the better solution is UITextView. "Figurati non c'e' di che" – Alessandro Ornano Apr 30 '16 at 10:42
  • Right now that's actually what I'm using : `UITapGestureRecognizer ` , but I had to make 3 different labels to have different actions for different taps on different labels. I'm not sure I know what you mean by using hyperlinks available in attributedstrings but I'll definitely look into it. Thanks again. – Giulio Colleluori Apr 30 '16 at 16:12
  • I dont know how to activate the chat to explain to you this point, do you know how enable chat line here? – Alessandro Ornano Apr 30 '16 at 16:14
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/110726/discussion-between-alessandro-ornano-and-giulio-colleluori). – Alessandro Ornano Apr 30 '16 at 16:15
0

Set number of line of label to zero like,

 label.numberOfLines = 0     // it will increase line when needed

And use attribute string to for different fonts and size or links etc.

and then set that string to label as,

    label.attributedText = attributedString

Update :

If you want some action event on particular text then you should use UITextview instead of label. it will be more easier by implementing shouldInteractWithURL delegate of it.

Another good solution is use thirdparty library like TTTAttributedLabel. It is exact what you want i think. have a look once.

Update 2 :

refer this link or this link for your desired output

Hope this will help :)

Community
  • 1
  • 1
Ketan Parmar
  • 27,092
  • 9
  • 50
  • 75
  • Thanks for answer! I think I'm using the term "link" wrongly. I meant to link the ViewController to another ViewController! In the example I made in my question there would be a string such as "A something B" — A and B would be for example bold font and tapping on A would present a ViewController for the object A and tapping on B for the object B. Does that make sense? Should I still use TextView or was that just better for URLs? – Giulio Colleluori Apr 30 '16 at 10:28
  • 2
    Guys stay away from TTTAttributedLabel, it crash in social network like projects using special chars, there are more than 60 open issue.. – Alessandro Ornano Apr 30 '16 at 10:33
  • @GiulioColleluori, Check my update in answer i have shared two link. hope it will help :) – Ketan Parmar Apr 30 '16 at 10:37
  • @AlessandroOrnano, Good imformation man. It is helping if is that so. +1 – Ketan Parmar Apr 30 '16 at 10:37