I have a UILabel whose text I am getting from a server. Some of the text is to be identified as links, and on touching those links some action should be performed. e.g.
NSString *str = #"My phone number is 645-345-2345 and my address is xyz";
This is the complete text for UILabel. I have only one UILabel for displaying this text (Text is dynamic. I just gave an example.). On clicking these links I need to perform actions like navigating to some different screen or make a call.
I know that I can display such text with help of OHAttributedLabel. And the links can be displayed as follows :
[label1 addCustomLink:[NSURL URLWithString:#"http://www.foodreporter.net"] inRange:[txt rangeOfString:someString]];
But I wonder how can I make these text links perform some action like navigation to different screen or making a call.
Let me know if more explanation is required.
You can add custom actions to any of the available UILabel replacements that support links using a fake URL scheme that you'll intercept later:
TTTAttributedLabel *tttLabel = <# create the label here #>;
NSString *labelText = #"Lost? Learn more.";
tttLabel.text = labelText;
NSRange r = [labelText rangeOfString:#"Learn more"];
[tttLabel addLinkToURL:[NSURL URLWithString:#"action://show-help"] withRange:r];
Then, in your TTTAttributedLabelDelegate:
- (void)attributedLabel:(TTTAttributedLabel *)label didSelectLinkWithURL:(NSURL *)url {
if ([[url scheme] hasPrefix:#"action"]) {
if ([[url host] hasPrefix:#"show-help"]) {
/* load help screen */
} else if ([[url host] hasPrefix:#"show-settings"]) {
/* load settings screen */
}
} else {
/* deal with http links here */
}
}
TTTAttributedLabel is a fork of OHAttributedLabel.
If you want a more complex approach, have a look to Nimbus Attributed Label. It support custom links out-of-the-box.
You can use UITextView with Phone numbers and links detection YES, scrolling disabled YES user interaction enabled YES, instead of UILabel.
My project has successfully used OHAttributedLabel for this. Check out the
-(BOOL)attributedLabel:(OHAttributedLabel*)attributedLabel shouldFollowLink:(NSTextCheckingResult*)linkInfo;
method in OHAttributedLabelDelegate (link). It allows you to decide what happens when a link is clicked. If you look at the source for the example from the OHAttributedLabel project, it's used to display an alert. If you returned NO in this case (to keep the default action from happening too), you could just do whatever you wanted like navigation, etc.
Note however that this requires that you can determine the action correctly just from the text. For our project, we used a slightly fancier solution, where the server sent us text with tags in them and a list of commands to perform for each tag.
There a project called FancyLabel that is about what you need. It might need some customization though.
Also, I think Three20 has this functionality, but it might be an overkill if you don't already use it.
There's also a much simpler solution, if all of your links are phones \ addresses \ urls. You can simply use a UITextView instead of a UILabel. It has auto detection of phones, address, etc. (just check the boxes in IB)
You can also have custom actions in response to click events on those links by overriding openURL, as explained here
Is there a specific reason that you must use a UILabel instead of a UITextView?
Note that a lot of the implementations of attributed labels inherit from UIView or don't implement all of UILabel's functionality.
You can use custom button to give a look like of link ..Also you can add gesture on the custom label if you dont want to use button ..
UITapGestureRecognizer* gesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(userTappedOnLink:)];
// if labelView is not set userInteractionEnabled, you must do so
[labelView setUserInteractionEnabled:YES];
[labelView addGestureRecognizer:gesture];
I'm not a fan of being forced to use UITextView or a third party lib when all I need is a lightweight label that renders links (and that tells me when they're tapped!)
Here's my attempt at a lightweight UILabel subclass able to detect link taps. The approach is different from others I've seen in that it gains access to the UILabel's shared NSLayoutManager via a delegate callback added to NSTextStorage via a category extension. The beauty is that UILabel performs its native layout and drawing - other UILabel replacements often augment or replace the native behavior with an additional NSLayoutManager/NSTextContainer.
Probably App Store safe, but somewhat fragile - use at your own risk!
https://github.com/TomSwift/TSLabel
Related
I have this issue with a custom UIView where I have a UIButton subview, I want to set the button's text on initialization based on some condition like this:
- (void)awakeFromNib {
[super awakeFromNib];
//check for some conditions
self.testButton.titleLabel.text=#"Some Title";
}
Nothing happens and the button's text is the same as defined in the nib file, however if I change the implementation to:
- (void)awakeFromNib {
[super awakeFromNib];
//check for some conditions
[self.testButton setTitle:#"Some Title" forState:UIControlStateNormal];
}
It works as expected.
Can somebody please explain to me the difference between the two approaches? and when to use each?
EDIT:
the suggested answer doesn't explain my situation, I tested changing the button's text from another button's action like this:
- (IBAction)otherButtonClicked:(id)sender {
self.testButton.titleLabel.text=#"Some Title";
}
and the button's text changed. I just want to understand that behaviour.
Exact answer is
titleLabel
Do not use the label object to set the text color or the shadow color. Instead, use the setTitleColor:forState: and setTitleShadowColor:forState: methods of this class to make those changes.
The titleLabel property returns a value even if the button has not
been displayed yet. The value of the property is nil for system
buttons.
setTitle
Use this method to set the title for the button. The title you specify
derives its formatting from the button’s associated label object. If
you set both a title and an attributed title for the button, the
button prefers the use of the attributed title over this one.
At a minimum, you should set the value for the normal state. If a
title is not specified for a state, the default behavior is to use the
title associated with the UIControlStateNormal state. If the value for
UIControlStateNormal is not set, then the property defaults to a
system value.
Title label access is given to adjust other properties of the label such as font but setting titleLabel text does not work.
It is because UIButton class has inner implementation to set the text based on different states of the button like selected/highlighted etc which overrides label text.
The accepted answer is correct, I just add this here to elaborate a bit (comments are too short)
There's not much to explain here. The title is simply not meant to set the text at all. My guess is that the internal workings of UIButton make it save the text somewhere else as well (for different states). It uses a normal UILabel to eventually display that, because that's convenient and easy to understand. Setting the text of that does not change the button in all cases, which probably ultimately depends on the drawing cycle. I assume when it's drawn, laid out, or the like it "replaces" the label's text with its other saved variant at some point.
Now you might wonder why Apple did then expose the UILabel and thus seemed to make the text editable then.
Legacy is probably one aspect of this decision (IIRC you could once set the button's title that way). Although old code doesn't result in the desired behavior, it at least didn't crash immediately. Also, a lot of code simply wants to get the text and expects a label, that works perfectly fine as ever.
Second, designing it totally different seems overkill. To avoid that, they would have to use a subclass of UILabel which prevents you from setting the text or something and use that. Or skip it (and thus legacy support) completely and only offer the setTitle:forState: method. That seems like a bit much for a simple text container like a Label.
Ultimately it's a design choice made by Apple. You can't set the title text directly and there's no case in which you should do it any way other than by using setTitle:forState:
I've always been curious how instagram gets it's tags to layout fluidly and wanted to know what goes behind this functionality? To me, it seems like they're using UIButton's and just calculating placement of the buttons line by line? Is that right? Or is there a simpler method of doing it without having to manual calculate the placement of each tag line by line / or side by side given that multiple tag's width's fit together?
Or, are they using NSAttributedStrings?
Any ideas?
Here's an example of the layout I'm referring to.
Well, I'm currently working on NSAttributedString and UITextView to get all this working, and my current code can do it. So I'm going to explain a possible version of doing this.
Here are the tips and big steps, with iOS7:
NSAttributedString, in iOS7 has a new attribute : NSLinkAttributeName. You can add it to your NSAttributedString, and with a detection method (combining: how to make #key and #key clickable in IOS7 and Get word from tap in UITextView) you can manage it. That's for the general way of doing it. For previous version, you'll have to do a little more of work, but keeping this general idea.
But since, it only for hashtags, since you can detect the world behind the tap, you can do this: Detect what word has been tapped (see previous links), detect if this word has an hashtag, and if yes, you can do whatever action you want. You can play with a NSRegularExpression to know where are the hashtags, and know when to "color" them.
Here is a simplified way to do it using UITextView and NSAttributedString:
Use regular expressions to get character ranges for links.
Add link styling to the matched ranges.
Add custom attribute to range that references tap action to execute.
On touch, if index of character is inside a matched range, change the link formatting to highlight it and run the associated tap action.
How to get index of character at location in iOS7:
- (NSUInteger) getCharIndexAt: (CGPoint) location
{
NSLayoutManager *layoutManager = self.layoutManager;
NSUInteger characterIndex = NSNotFound;
characterIndex = [layoutManager characterIndexForPoint:location inTextContainer:self.textContainer fractionOfDistanceBetweenInsertionPoints:NULL];
return characterIndex;
}
Also check out WWDC 2013 intro to TextKit Demo
ios7 text utilities
I have a Tableview and tableview cell is customized to have a UILabel. The text in UILabel is having URLs. Is there a way to detect urls like how UITextView will enable detect URLs so that user interaction should be able to load the urls.
If you just want to identify the URLs, you can use NSDataDetector with the NSTextCheckingTypeLink checking type.
If you want to draw the URLs differently, and you are targeting iOS 6, you can use an NSAttributedString to turn the URLs blue or underline them or whatever. If you're targeting an older version of iOS, you will probably want to look for some free code on the Internet to draw styled text, like OHAttributedLabel.
If you want to actually make the URLs touch-sensitive, you can add a tap gesture recognizer to the label and try to figure out which part of the string was tapped (somewhat complicated), or look for some free code on the Internet that already does it for you (like OHAttributedLabel), or just put a UITextView in the table view cell instead of a label.
as Rob point out how can we achieved the same is awesome.
But, we can use a tact so can save with issue of ios version (possibly), just by using a UILabel and UIButton.
What we need to do is that, either from IB or story-board,just place a UILabel with string as URL(use this as title), say;
"www.myURL.com"
Now, just above it, place a UIButton(button with custom type), and just use "______"(underline) and set this button as overlap your UILabel and also the 'underline' must be beneath your label.
Now, just do in action of button whatever you required as you need on the click of URL and here also you can change the textColor, etc, properties; also load URL and navigate to UIWebView.
How to detect and make link/mention/hashtag clickable in UILabel. Alternatively, is there any open source library that I can utilize (I already looked at Fancy UILabel which doesn't handle multiline tex, TTAttributedLabel which doesn't handle mention/hashtag)?
There is no way to do so with UILabel in the current iOS...
TTTAttributedLabel will let you style up your label, however for clickable (or rather - tappable) links you should rather either use a UIWebView and style it in such a was as to disguise it as a Label, or, you could get geeky and split your labels up and use a UIButton in the mix, but that's very messy - like a puzzle, only... they don't fit together.
Last option you might have is to overlay a UIButton over a link, but this requires that you know where the link is and since the question was about detecting links etc...
You should really look into UIWebView.
You can achieve this using following library:
https://github.com/SebastienThiebaud/STTweetLabel
I wanted to ask a quick question just to make sure I am not missing anything simple before I implement a more difficult method. I need to create a custom keyboard for an iPhone application. This I have already done by creating a view with the buttons, using a custom input view and it displays exactly like it should. Now most of the buttons are standard numbers which need to update a UITextField in the screen that called the keyboard. Does anyone know a simple way to do this? I assume there has to be a built in function that the keyboard uses to send the information but I haven't been able to find any reference to it. Otherwise I will have to go the more difficult route. If anyone has a simple way to do this I would appreciate it. I haven't worked with custom keyboards before.
You won't be able to do it the same way that Apple does it, as their keyboard is basically an input device, globally.
I recommend you just append the data in your button press multiplex method. Here's an example:
NSString *appendThisText = #"subtitle";
self.myTextView.text=[NSString stringWithFormat:#"%#%#", self.myTextView.text, appendThisText];
Custom keyboards are simpler than you realise.
UITextField conforms to the UITextInput protocol. That's a bit of a red-herring because this protocol provides all the really complex stuff like selecting text and so on. But UITextInput itself conforms to UIKeyInput. This is your friend.
The key UIKeyInput methods are:
- (void)insertText:(NSString *)text;
- (void)deleteBackward;
Your keyboard class should have a delegate (which points to the textfield that the keyboard is operating on) and you simply call these methods to insert and delete text.