iOS Clickable Words (UILabel or UIbutton's) - iphone

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 :)

Related

Get Width of last line of multiline UILabel

I have a dynamic multi line UILabel and need to know the end of the text (X Coordinate) of the visible text (not the Label) so I can show something after the text.
Is this possible?
thank you
You'll be able to have more control over the text layout with the CoreText framework. Checkout the documentation:
There are also some nice open source things that already do a lot of the hard work for you, like: https://github.com/Cocoanetics/DTCoreText
As far as I know , the best solution for this is to use a UIWebView instead of a UILabel.
You just have to format the HTML for it to load and then add whatever you want to add after.
Example:
[webView loadHTMLString:[NSString stringWithFormat:#"<html><body><font face=\"arial\" size=\"2\">%#</font><font face=\"arial\" size=\"1\"> %#</font></body></html>",text1 , text2] baseURL:nil];
If you want to keep trying with UILabel / UITextView /any UIView for that matter , I only know of a way to figure out the height properly : [myView sizeToFit]; And then get it's frame.
Hope this helps.
Regards,
George

iOS: Creating tip / help popups

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,

UILabel - string as text and links

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

UISwitch - change from on/off to yes/no

does anyone know of a way I can change the text label for on and off to yes and no.
I did it with
((UILabel *)[[[[[[switchControl subviews] lastObject] subviews] objectAtIndex:2] subviews] objectAtIndex:0]).text = #"Yes";
((UILabel *)[[[[[[switchControl subviews] lastObject] subviews] objectAtIndex:2] subviews] objectAtIndex:1]).text = #"No";
However, with the release of iOS 4.2, this is no longer supported (this probably wasn't recommended by Apple anyway)
My client is insisting on yes/no switches. I'd appreciate any advice!
many thanks
Hurrah! From iOS 6, it's possible to specify an image to be used for the on / off states, respectively. So, this can be used to display a YES / NO image (or whatever image representing the text you would prefer to use instead of the previously limited ON / OFF).
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"6.0"))
{
[mySwitch setOnImage: [UIImage imageNamed:#"UISwitch-Yes"]];
[mySwitch setOffImage:[UIImage imageNamed:#"UISwitch-No"]];
}
The images should be 77 px wide, 27 px high, and the text (one image for each state) should be horizontally centred within that 77 px width. I use transparent backgrounds for the text, so I can still make use of the tint for the background, which still works with this.
Of course, it would seem easier to just supply text, rather than having to use an image of text, but I'm certainly grateful for this new option, at least.
You need to implement your custom UISwitch for that. Or use one of already implemented :) (check this SO question and this post)
Vladimir answer is great, but in my humble opinion there is an even better implementation here: https://github.com/domesticcatsoftware/DCRoundSwitch.
Besides setting a custom text, it is easier to change the size and color of the UISwitch and you get a sharper result.
It is released under an MIT license. Have a look!
It turns out that you can create a custom UISwitch with the following items:
A UIScrollView
A UIButton
Two UILabels
A background image
A Boolean value
First you will need to add QuartzCore.framework to your project and #import <QuartzCore/QuartzCore.h> to your view controller.
Next add the UIScrollView to your view using Interface Builder. The ScrollView will be your custom UISwitch.
Next add the button and the two labels to your ScrollView. One label will be for "yes" the other for "no".
Add the image to the button and set its type to custom. This is the image I use:
Position the labels over the blue and white area of the image. Adjust the ScrollView so it is just big enough to show the blue part of the image and the thumb nob.
Add the following line to viewDidLoad:
self.mySwitch.layer.cornerRadius = 13.5;
mySwitch is the name of the ScrollView and 13.5 is half the height of the ScrollView. The above statement changes the ScrollView to have rounded ends like the UISwitch.
To make the custom switch active you will need to tie the buttons "Touch Up Inside" event to an IBAction. Here is the code I use in the event handler:
-(IBAction)mySwitchButton:(id)sender {
self.myValue = !self.myValue;
CGPoint scrollPoint = CGPointMake((self.myValue)? 43.0: 0, 0.0);
[mySwitch setContentOffset:scrollPoint animated:YES];
}
Where myValue is the boolean variable that contains the state of your switch and 43.0 is the number of points you will have to move the image over to put the switch in the off position.
That is all there is to it!
From iOS 6, it's possible to specify an image to be used for the UISwitch on / off states, but NOT the text.
This will lead trouble when internationalization is required because translators
have to provide an image text for each language, not text only.
Moreover, the size of the UISwitch image is fixed, limiting the text length.
Because of the above reasons, I like the JSWilson's answer: simple and flexible.
To relieve developers of the need to manually add the required controls, I coded a custom CRDScrollSwitch class that you can find at my GitHub repository:
https://github.com/corerd/CRDScrollSwitch

iphone UITextView does not support data detectors when the text view is editable

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.