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'm trying to initiate a MFMessageComposeViewController with a semi transparent keyboard. I would like to make it as transparent as I want, but I don't think we are allowed to do that from the reading that I've done.
How would you set the property of the UIKeyboard when you create the MFMessageComposeViewController?
Many Thanks!
You do not. From the documentation:
Important The message composition interface itself is not customizable and must not be modified by your application. In addition, after presenting the interface, your application is unable to make further changes to the SMS content. The user can edit the content using the interface, but programmatic changes are ignored. Thus, you must set the values of content fields, if desired, before presenting the interface.
You are not supposed to change this interface, since UIKeyboard is private and the textfields on this view are not accessible by you. Attempting to access and modify this textfield via the view hierarchy might get your app rejected in the app store.
Setting the keyboardAppearance property of your text field or text view to UIKeyboardAppearanceAlert will change the keyboard to the transparent keyboard.
I heard that there's only two styles available in the public API:
[textView setKeyboardAppearance:UIKeyboardAppearanceAlert];
[textView setKeyboardAppearance:UIKeyboardAppearanceDefault];
But you can use private API methods to retrieve the keyboard implementation:
id keyboardImpl = [objc_getClass("UIKeyboardImpl") sharedInstance];
And Make it less opaque,
[keyboardImpl setAlpha:0.8f];
Tint it,
UIView *tint = [[UIView alloc] initWithFrame:[keyboardImpl frame]];
[tint setBackgroundColor:[UIColor colorWithRed:0.0f green:0.0f blue:1.0f alpha:0.3f]];
[tint setUserInteractionEnabled:NO];
[[keyboardImpl superview] insertSubview:tint aboveSubview:keyboardImpl];
[tint release];
Or even flip it:
[[keyboardImpl window] setTransform:CGAffineTransformMakeScale(-1.0f, 1.0f)];
Hope it was the solution for your problem.
Are there any built in, open source, or tutorials for creating a reusable easy to use popup for use with in game-help.
Essentially I would like to, on first run of a game, show popup tips / help that "point to" various on screen objects to help a user orient themselves with the game.
Update: Here is an example of how I ultimately want it to look / behave although I don't need it that generic but as close as possible would be good
I like those: https://github.com/chrismiles/CMPopTipView.
Nice and easy to set up.
Essentially what you need is a custom view.
You cannot use Apple's UIAlertView since its purpose is very different from what you are looking for.
I don't know what are your specific needs, but you may use a simple UILabel:
CGRect ref = objectToAddress.frame;
UILabel *tip = [[UILabel alloc] initWithFrame:CGRectMake(ref.x+ref.width,
ref.y+ref.height,
width,
height)];
[tip setText:messageToShow];
[self.view addSubview:tip];
[tip release];
where width and height are the dimensions of the tip you want to show and messageToShow is the message you want to display.
You can, of course, customize your UILabel as you like, changing font or background color. Check the reference for additional informations.
EDIT:
You may take a look at a possible popover implementation for iPhone: WEPopover. On the iPad you can use directly Apple's UIPopoverController
What I've done is to create two functions
- (void) showOverlay: (BOOL) show withMessage: (NSString*) message
{
if(show)
{
// I create or load a UIView with labels, etc, and with an alpha of 0.6/07
// give it a tag for later dismissal
overlay.tag = tag; // any arbitrary value
// add as subview
[self.view addSubview: overlay];
}
else
{
// hide the view
UIView *overlay = [self.view viewWithTag: tag];
[overlay removeFromSuperview];
}
}
Then I have a hide overlay function
- (void) hideOverlayInSecs: (NSInterval) time
{
[self performSelector: #selector(hideOverlay) withObject: nil afterDelay: time];
}
Then you can write a wrapper function to show / dismiss it for varying durations
[self showOverlay: YES withMessage: #"help tip"];
[self hideOverlayInSecs: 2];
In my App, the tips were fairly static, so I created an tip image using my favorite image editor, and then simply created a UIImageView with the tip image, and then added that as a subview to the current view, making sure to place it on top of other views.
It worked out pretty nicely, but again, my tips are fairly static.
If you want to display them only on the first run through, you'll need to create a BOOL that is saved in NSUserDefaults or something.
How about this?
I wrote this myself. It's pretty simple and probably what you are looking for.
Popup any UIView instance on top or bottom then disappear after a few seconds.
https://github.com/SaKKo/SKTipAlertView
Hope you find it useful. cheers,
I'm wanting to create a read only text area in my app which allows the user to click on any word and the app reads it out. I am however a little confused on which method would be the best. I see two options, use a UILabel and create some method to detect the region clicked then match it to the word in that region but it sounds hard to implement. On the other hand I could use an array of words to create a list of UIbutton's. Any advice and/or sample code to help me would be much appreciated, thanks Jason.
Note: Each view has about 30 words on it.
The solution below works well. For anyone else wanting to use this, these four lines will set your UIWebView to have a clear background and disable any scrolling or bounce.
[[myWebView.subviews objectAtIndex:0] setScrollEnabled:NO];
[[myWebView.subviews objectAtIndex:0] setBounces:NO];
[myWebView setBackgroundColor:[UIColor clearColor]];
[myWebView setOpaque:NO];
And some handy css to stop the open popup when a user presses and holds a link.
*{-webkit-touch-callout:none; -webkit-user-select: none;}
How big is your text area? If it's big then creating a UIButton for each work sounds like sa bit of effor to get the text to layout correctly.
I would use a UIWebView - make each word like this :
WORD1 WORD2 WORD3
and attach your view controller as the webView's UIWebViewDelegate delegate.
Then, you can intercept presses on each word using the webView:shouldStartLoadWithRequest:navigationType: delegate method :)
My app will display some text, and I want to make the hyper-link be able to be clicked. I have some questions about this feature.
How do I parse the text to be aware this is a link?
Once a user click the link, I don't want the OS to switch to Safari and open the link, this is very bad because the user can not go back to my application. So I want to open the link within my application. As soon as the user click the link, my app will present a view modally to display the web content. Any advice would be appreciated.
You probably want to subclass UILabel. When you change the text, have it try to see if the text is a hyperlink, if it is, set it to enable user interaction and change the text color to blue. When the user taps on the link, send a message to the main view controller (Possibly through delegation) to open the link.
to display web content in your app, look into UIWebView.
If your text can be formatted as html with hyperlinks (<a> tags), you could use a UIWebView to display it.
The UIWebViewDelegate's webView:shouldStartLoadWithRequest:navigationType: method is called when a user taps a link. Usually you would make your controller implement this method, and set the UIWebView's delegate to the controller.
You're going to want to check out a Github project called LRLinkableLabel.
It will auto-detect any URLs that are inside the .text property.
You can use it like so:
LRLinkableLabel *label = [[LRLinkableLabel alloc] initWithFrame:CGRectMake(0.0, 0.0, 100.0, 20.0)];
label.delegate = self;
label.text = #"Check out http://dundermifflin.com to find some great paper deals!";
Then just make sure self implements this method:
- (void) linkableLabel:(LRLinkableLabel *)label clickedButton:(UIButton *)button forURL:(NSURL *)url {
[[UIApplication sharedApplication] openURL:url];
}
You can also use the linkColor and textColor properties to configure the appearance of the label. From this point you can use it just like any other UILabel.
Remember to set the delegate to nil when you're all done to make sure everything is all cleaned up.
Hope this helps.
I am getting an interesting warning at build time (iPhone simulator) that gives the following:
EditView.xib:35:0 UITextView does not support data detectors when the text view is editable.
This is basically non existent on google and I would like to remove it.
My editview.xib has a textview where I write notes into it. Is there any more info that is needed?
I have four different Xibs with similar TextViews that are used for notes as well. I was getting the same warnings. The suggestion to disable the "Detects Phone Numbers" and "Detects Links" does removes the warnings. However, I wanted my users to still have the ability to use the detectors in my notes.
This is how I solved the issue in my app:
In IB: I deselected the two properties for the TextView. -(which does stop the build warnings).
In my - (void)viewDidLoad { I set the properties of the textView to the following:
myTextView.dataDetectorTypes = UIDataDetectorTypeAll; which enables the data detectors of all types (phone numbers and url addresses).
In my View Controller's: -(void)textViewDidBeginEditing:(UITextView *)sender {
method, I turned the data detectors back OFF using: myTextView.dataDetectorTypes = UIDataDetectorTypeNone
Then taking advantage of the -(void)textViewDidEndEditing:(UITextView *)sender {
method, I turned them back ON using: myTextView.dataDetectorTypes = UIDataDetectorTypeAll;
This method disables the data detectors when the user is editing the UITextView and turns the data detectors back ON when the user is finished editing. This Fix allowed for selection of the phone numbers and URL from within the textView, so that I did not loose the function.
I found the following in the Apple Docs on the DataDetectors for UITextView: after playing around with the UITextView for a while, hope it helps.
UIDataDetectorTypes:
Defines the types of information that can be detected in text-based content.
Types:
UIDataDetectorTypePhoneNumber;
UIDataDetectorTypeLink;
UIDataDetectorTypeNone;
UIDataDetectorTypeAll;
Update: 11-5-2010;
Extra Note:
Data detectors are not permitted if UITextView is "Editable", because there would be too many variables to track users changes to text as well as touches with trying to execute phone call or links.
Solution:
Load the TextView with self.textView.editable = NO; and set you UIDataDetector's based on the types I listed above. This way if the user wants to "select" web address or phone number etc, the delegate can handle. When you need your user to edit the textView, then turn ON the self.textView.editing = YES; & remove your UIDataDetectors accordingly. This should assure no errors or warnings during compiling.
Special Consideration:
Be sure to first remove the datadectors when re-enabling, then enable "editing = YES;"...The order is important no to enable editing if UIdatadetectors are still assigned.
Therefore, the sequence order should be something like this...
To Edit textView: 1. remove data detectors, 2. then enable editing = YES.
To Use DataDetectors: 1. Disable Editing = NO; 2. then add data detectors.
I was seeing this warning as well. Here's how I fixed it:
In the xib file in Interface Builder, select your text view, and bring up the attributes inspector. Make sure that "Detects Phone numbers" and "Detects Links" are both UNCHECKED.
I had "Detects Links" checked, and turns out that's what was causing the warning. Basically, if the textview is editable, you don't want these auto-detect features turned on.
So Wordy!
textView.editable = NO;
textView.dataDetectorTypes = UIDataDetectorTypeAll;
the URL address must start with "http://", otherwise the textview cannot detect it.
I thought about trying to use a Tap-Gesture-Recognizer with "delaysTouchesBegan = YES" and "cancelsTouchesInView = NO"
It is still quite easy to solve!
Load view with editable disabled as well as UIDataDetectorTypeAll or the types of links you want to detect. Then add a GestureRecognizer:
UITapGestureRecognizer *recognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(editTextRecognizerTabbed:)];
recognizer.delegate = self;
recognizer.numberOfTapsRequired = 1;
[self.textViewNotes addGestureRecognizer:recognizer];
So you can change settings within this method:
- (void) editTextRecognizerTabbed:(UITapGestureRecognizer *) aRecognizer;
{
self.textViewNotes.dataDetectorTypes = UIDataDetectorTypeNone;
self.textViewNotes.editable = YES;
[self.textViewNotes becomeFirstResponder];
}
And at least you have to change the edit and detections settings back after user has finished the text input:
- (void)textViewDidEndEditing:(UITextView *)textView;
{
self.textViewNotes.editable = YES;
self.textViewNotes.dataDetectorTypes = UIDataDetectorTypeAll;
}
works lika a charm!
Data detectors for the UITextView would be for copy and paste. Since you are setting it as editable, copy/paste shouldn't be allowed where you think paste should, but copy shouldn't.
Simplenote somehow does this on iOS 4. (There's a free/lite version in case you wanna try.)
It acts a little bit different:
When tapping on one of the highlighted parts, it still starts the editing, and won't follow the link.
But when you tap-and-hold on a detected dataTpye, it shows yout the menu for calling, open the link or whatever.
Also, when tapping inside the text the editing really starts at the place you tapped.
So they somehow remove the dataDectectors, enable editing AND get the touches forwarded to the editable UITextview AFTER the tap is recognized.
Any ideas how to do that?
I thought about trying to use a Tap-Gesture-Recognizer with "delaysTouchesBegan = YES" and "cancelsTouchesInView = NO"
So I can remove the dataConnectorTypes and set it editable on the action method of the recognizer,
and hopefully the touches to the UITextview are delivered AFTER that.
But haven't had time to test it so far.