I have a UITextView that has a text of say www.foo.com
when the user clicks on it I want to visit www.foo.com/bar/cow/index.html instead of what appears in the text property of the UITextView
What is the easiest way to do this?
Have your class conform to the UITextViewDelegate protocol. Then implement - (void)textViewDidBeginEditing:(UITextView *)textView in a similar way:
- (void)textViewDidBeginEditing:(UITextView *)textView{
NSString *url = [NSString stringWithFormat:#"%#<additionalTextHere>", textView.text];
//do whetever with url
}
Related
Needing to present user a multiline text field for comment entry, I am using a UITextView instead of a UITextField. I would like to use textFieldShouldReturn on my UITextView to send the data to server. How might I do that? Based on my readings so far, the method is only applicable to UITextField. So what is the equivalent for UITextView?
By adding the UITextViewDelegate to your viewControllerHeader
#interface ViewController : UIViewController<UITextViewDelegate>
This'll allow you access to the UITextViewDelegate methods of which there are a couple of which should allow you to know when the user has either pressed return or let you know when they have finished editing, for example
- (void)textViewDidEndEditing:(UITextView *)textView{
//From here you can action your methods to send the data to your server as required etc.
}
There's also this method
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text{
//Which you can use to listen for the #"\" return action if you prefer.
}
I hope this helps
I have a UITextView. I have the delegate for myTextView set to self and, when I do normal editing, this method calls just fine:
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
NSLog(#"Called");
}
In my app, I call in my code: [myTextView insertText:#"Hello World"];. When I do, I need to call textView:shouldChangeTextInRange:replacementText: after the text is inserted. How do I do this?
Call it explicitly. Call it before editing and only perform the edit if it returns YES. To call it explicitly you need to know the selected range (get the selected range with selectedTextRange), that's it. You already have the text to add and the text view.
Thanks for the answer, #Wain!
Here's what worked:
- (void)insertText
{
NSString *stringToAdd = #"Hello World";
NSString *replacementText = [myTextView.text stringByAppendingString:stringToAdd];
[napkinTextView insertText:stringToAdd];
[self textView:myTextView shouldChangeTextInRange:NSMakeRange(0, stringToAdd.length) replacementText:replacementText];
}
I have a UITextView in my app which is used to display some string with numbers. These numbers can be phone numbers or other numbers specific to the app. If user taps the phone number they should be asked if they want to make a call (This is done by default). However, if the user taps on the other number which is not a phone number but is specific to the app, the action should be custom e.g. it should call a method in the view controller with the number as an argument.
I had a quick search but couldn't find any easy solution.
Any idea how this could be done? Any help would be appreciated.
I was able to solve this by implementing 'UITextViewDelegate'.
- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange
{
DLog(#"URL is %#", URL.absoluteString)
NSString *host = [URL host];
NSNumber *adIdInLink = nil;
NSRange range = NSMakeRange(0, 3);
NSString *subString = [URL.absoluteString substringWithRange:range];
if ([subString isEqualToString:#"tel"] && !host) {
// this is a number - do whatever you want
NSString *stringWithAdId = [URL.absoluteString substringFromIndex:4];
if ([HJUtilities isValidAdId:stringWithAdId]) {
// this is the ad Id a custom number used in my app
adIdInLink = [NSNumber numberWithInteger:[stringWithAdId integerValue]];
}
else {
// this was a phone number - let the default behaviour
return YES;
}
}
}
Add a UITapGestureRecognizer to the UITextView with its delegate set to the parent UIViewController:
UITapGestureRecognizer *recognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(handleTap:)];
[myTextView addGestureRecognizer:recognizer];
The add a handler method to your UIViewController:
- (void)handleTap:(UITapGestureRecognizer *)sender{
UITextView *textView = (UITextView*)sender;
NSString *number = textView.text;
}
eta: You need to add UIGestureRecognizerDelegate as a protocol to your UIViewController too:
#interface MyViewController : UIViewController <UIGestureRecognizerDelegate>
update:
How about using the UITextViewDelegate method textViewDidChangeSelection instead?
Inspect the selectedRange property of the textview to check its contents.
I have implemented UITextViewDelegate in my ViewController,
After setting delegate to my TextView as
self.addressTextView.delegate=self;
Now i can only set the text as,
[self.addressTextView setText:#"Tamil Nadu, India"];
I am unable to edit the text using keybord. After Implementing shouldChangeTextInRange method only i am able to edit the content in UITextView.
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
return YES;
}
I dont know why?? is shouldChangeTextInRange compulsory if we implementing UITextViewDelegate
NO. Its not compulsary. You can set text like that
textView.text = #"Hello";
This method will be call when you are try to write somthing in your text view.
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
Its not compulsory in the protocol definition, so more than probably something else is going on. From reading that implementing the delegate method mentioned fixes this, its quite possible that your controller's superclass implements the method and only allows the text you've got above. If that's the case, the workaround you've implemented is in fact the easiest way to fix this.
For your information, everything that must be implemented when you declare that a class follows a protocol will be indicated by the compiler : you will get an error when you build if a method or a property is missing.
Right now, our code is set to grab the text from the UITextField as setInitialText for Facebook/Twitter posts.
What we want to do is: add an additional permanent message or URL to the Facebook/Twitter posts.
How can we do this? Here's our current code:
[slComposeThirdViewController setInitialText:[[self QText]text]];
[self presentViewController:slComposeThirdViewController animated:YES completion:nil];
It's a little involved, so bear with me here... and this only works for SLServiceTypeTwitter
For anyone reading this that is interested in using this, I've put a sample project on Github: https://github.com/NSPostWhenIdle/Immutable-SLComposeViewController
The first thing you'll want to do is make sure that your view controller conforms to UITextViewDelegate. You'll also want to create an iVar for a UITextView. You won't actually be creating a text view, but you'll want to have a pointer to assign directly to the text view inside the SLComposeViewController. While you're here make a iVar for the permanent string as well.
#interface ViewController : UIViewController <UITextViewDelegate> //very important!
{
UITextView *sharingTextView;
NSString *permanentText;
}
Then in viewDidLoad you can set up what you want the permanent text to be:
- (void)viewDidLoad
{
[super viewDidLoad];
permanentText = #"http://www.stackoverflow.com/";
}
The code below is a pretty basic IBAction to present the composer with a couple of slight tweaks. First, you'll notice that setInitialText uses a formatted string the append the permanent text to the end of the contents of the text field with a space added in between.
Then comes the important part! I've added a loop to presentViewController:'s completion handler to cycle through some subviews of subviews of subviews in order to identify the UITextView in the composer that contains the sharing text. This needs to be done so you can set that text view's delegate in order to access the UITextViewDelegate method shouldChangeTextInRange.
- (IBAction)exampleUsingFacebook:(UIButton *)sender {
if([SLComposeViewController isAvailableForServiceType:SLServiceTypeTwitter])
{
SLComposeViewController *sharingComposer = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeTwitter];
SLComposeViewControllerCompletionHandler __block completionHandler=^(SLComposeViewControllerResult result){
[sharingComposer dismissViewControllerAnimated:YES completion:nil];
};
[sharingComposer setCompletionHandler:completionHandler];
[sharingComposer setInitialText:[NSString stringWithFormat:#"%# %#",[[self QText]text],permanentText]];
[self presentViewController:sharingComposer animated:YES completion:^{
for (UIView *viewLayer1 in sharingComposer.view.subviews) {
for (UIView *viewLayer2 in viewLayer1.subviews) {
if ([viewLayer2 isKindOfClass:[UIView class]]) {
for (UIView *viewLayer3 in viewLayer2.subviews) {
if ([viewLayer3 isKindOfClass:[UITextView class]]) {
[(UITextView *)viewLayer3 setDelegate:self];
sharingTextView = (UITextView *)viewLayer3;
}
}
}
}
}
}];
}
}
Important: Please note that the above will only work if placed in the completion handler.
Below is an example of how to set up shouldChangeTextInRange to compare the range that the user is attempting to edit to the range that contains your permanent text. By doing so, the user will be able to make changes to any part of the text that they want... except for the part that contains your permanent text. You'll also notice that inside this method I've compared textView to shareingTextView, the pointer we assigned to the text view inside the composer. Doing so will allow you to use other text views within this controller without them following the same rules I've configured for the text view inside the composer.
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
if (textView == sharingTextView) {
NSRange substringRange = [textView.text rangeOfString:permanentText];
if (range.location >= substringRange.location && range.location <= substringRange.location + substringRange.length) {
return NO;
}
}
return YES;
}
Hope this helps!
You can roll your own composer, append your text and then use SLRequest to actually submit it to the service.
How about capturing the user entered text from the UITextField and then constructing a final string which appends the permanent message you want from it?
UITextField *textField;
NSString *enteredText = [textField text];
NSString *finalPost = [NSString stringWithFormat:#"%# Your permanent text/URL", enteredText];
Now post the "finalPost" string to Facebook or Twitter.
If you want to append the text with URL, just use the addURL: method. It won't display any text in the SLComposeViewController's view. But will add the URL at the end after publishing users tweet.
SLComposeViewController *slComposeThirdViewController = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeTwitter];
[slComposeThirdViewController setInitialText:#"initial Text"];
[slComposeThirdViewController addURL:[NSURL URLWithString:#"http://stackoverflow.com/"]];