I have a URL in my textview and when we click on this url it opens this url in default safari. and I want to detect this event. I also tried this
but its not working for me. can any one suggest me how i do this. Provide me a sample for this.
My application deligate is UIResponder type.
the other answer works as expected.
create New File, select Objective-C Class
Class: MyApplication
Subclass of: UIApplication
paste this code in the .m file:
- (BOOL)openURL:(NSURL *)url {
if ([self handleOpenURL:url])
return YES;
else
return [super openURL:url];
}
- (BOOL)handleOpenURL:(NSURL*)url {
NSLog(#"my url handler");
return YES;
}
next open your main.m and change the third parameter
return UIApplicationMain(argc, argv, nil, NSStringFromClass([SampleAppDelegate class]));
to your UIApplication-subclass name
return UIApplicationMain(argc, argv, #"MyApplication", NSStringFromClass([SampleAppDelegate class]));
Take a look at this GitHub project: MSTextView
Assuming you just need to display a static label with links, we have a fairly powerful attributed label in Nimbus that you may wish to check out:
http://docs.nimbuskit.info/group___nimbus_attributed_label.html
The label uses CoreText and NSAttributedString, so it is built on core Apple technologies. It acts in every way like a UILabel. Here's an example of implementing the NIAttributedLabel delegate:
https://github.com/jverkoey/nimbus/blob/master/examples/attributedlabel/BasicAttributedLabel/BasicAttributedLabel/src/MashupViewController.m#L92
More info:
http://nimbuskit.info/
Related
I just came to know about an awesome ios feature for UITextViews i.e UITextview dataDetectorTypes. It is really useful to display text as links.
However, I noticed one thing. When the string is a physical address, Google Map is opened which is appropriate, but in a different application.
Is there any way we can open that google map in our application and not go into default iOS application wherein map is opened? So that I can go back into my application from the map. Is there any delegate method which can control this? Right now I have to minimize the application(make it run in background) and again open it which does not looks good.
Pretty easy, you'll need to subclass UIApplication, override it's openURL: and pass the application class name to the target's main.m int main(...) like this:
int main(int argc, char *argv[])
{
#autoreleasepool {
return UIApplicationMain(argc, argv, #"MyApplication", NSStringFromClass([MyAppDelegate class]));
}
}
intercepting the urls you can return NO for maps: schemes not to launch the Maps app and handle the address in whatever way you wish.
In the project create a new class subclassing UIApplication
Add the following method to be overridden:
-(BOOL)openURL:(NSURL *)url
{
NSLog(#"Open %#", [url absoluteString]);
// do something if the url scheme is maps:
return NO;
}
In the target's main.m file change the default int main(int argc, char *argv[]) implementation to make it to use your UIApplication class, it should look like this:
#import < UIKit/UIKit.h> //remove the leading space to compile
#import "LXAppDelegate.h"
#import "LXapp.h"
int main(int argc, char *argv[])
{
#autoreleasepool {
return UIApplicationMain(argc, argv, NSStringFromClass([MyUIApplication class]), NSStringFromClass([MyAppDelegate class]));
}
}
That's not for ARC (i'm never using it), refer to the UIApplicationMain documentation to understand what happens and what should be probably changed for ARC support.
You should use another solution for your problem.
If you use dataDetectorTypes, the link is alway opened in built-in app firstly.
You can make your action with button and custom string as below:
push your text into an UIButton.
make your text displayed as link with NSAtributedSring as this question, use UIButton instead of UITextView:
Underline text inside uitextview
make action for your button when user click on it.
Good luck!
I am pretty new with Three20. I have followed ray wenderlich's nice introduction to three20 and the examples within the three20 framework. When I click on a thumbnail in a thumbnail view (subclass of TTThumbsViewController) to launch a Details view, a standard Details image view (deployed by TTPhotoViewController or its super class). I would like to use my own implementation of a Details View instead of the default. I put the following code when I initiated the subclass of TTThumbsViewController and TTThumbsViewControllerDelegate method:
- (id)initWithDelegate:(id<TTThumbsViewControllerDelegate>)delegate {
[super initWithDelegate:delegate];
return self;
}
- (void)thumbsViewController: (TTThumbsViewController*)controller
didSelectPhoto: (id<TTPhoto>)photo {
[navigationController.pushViewController:photoDetailViewController
animated:Yes];
}
But the default TTPhotoViewController view still prevail. When I put a NSLog in the delegate method. I coud see the method was called. I think there is another delegate someone already set in TTThumViewController? Can someone recommend a way to display my detail photo view? Is there another thumbs view controller I can use? Any suggestion will be greatly appreciated.
I'm really new to all of this (coding, etc.) but I'll share what I've found. By looking up the definition of ttthumbsviewcontroller, I was able to find the following method(wrong term?):-
- (void)thumbsTableViewCell:(TTThumbsTableViewCell*)cell didSelectPhoto:(id<TTPhoto>)photo {
[_delegate thumbsViewController:self didSelectPhoto:photo];
BOOL shouldNavigate = YES;
if ([_delegate respondsToSelector:#selector(thumbsViewController:shouldNavigateToPhoto:)]) {
shouldNavigate = [_delegate thumbsViewController:self shouldNavigateToPhoto:photo];
}
if (shouldNavigate) {
NSString* URL = [self URLForPhoto:photo];
if (URL) {
TTOpenURLFromView(URL, self.view);
} else {
TTPhotoViewController* controller = [self createPhotoViewController];
controller.centerPhoto = photo;
[self.navigationController pushViewController:controller animated:YES];
}
}
}
In the else statement, I've found this calls the creation of the photoviewcontroller. By recalling this method (?) in the actual body of my own code and changing the body in the else statement I was able to add a custom detail view. Further down the definition of the ttthumbsnailviewcontroller, you can find that the creatPhotoViewController calls for an initiation of the PhotoViewController so calling that method(?) in the body of the code and initializing another view also works.
If someone can explain whether or not this is a good method of doing this (I have a feeling that is not), it would be appreciated. Also why does putting the method in the body of the code override the call there.
I followed the same exact code as the TTCatalog example of TTSplitViewController, starting from the app delegate code, the TTSplitViewController code, and as well as the code for the TTTableViewController. However, when I run the apps I am getting a blank screen.
I started from a window based application and removed the nib file, as the example on TTCatalog doesn't have it.
What am I doing wrong here?
Here's some code, in my app delegate didFinishLaunchedWithOptions I have:
TTNavigator* navigator = [TTNavigator navigator];
navigator.supportsShakeToReload = YES;
navigator.persistenceMode = TTNavigatorPersistenceModeAll;
TTURLMap* map = navigator.URLMap;
[map from:#"*" toViewController:[TTWebController class]];
if (TTIsPad()) {
[map from: #"tt://catalog"
toSharedViewController: [SplitViewController class]];
SplitViewController* controller =
(SplitViewController*)[[TTNavigator navigator] viewControllerForURL:#"tt://catalog"];
TTDASSERT([controller isKindOfClass:[SplitViewController class]]);
map = controller.rightNavigator.URLMap;
}
and everything else is similar to the TTCatalog example.
I was just wondering if anyone can give me a pointer on how to create a TTSplitViewController app, as this is quite frustrating. The example on the TTCatalog seems so simple, but when replicating it, everything fails.
For a full code, can be downloaded here
If you created a project using a xcode template, it means your app delegate is loaded using a nib file. You will have to change it, because Three20 doesn't use nib files at all.
open the main.m file, and change:
int retVal = UIApplicationMain(argc, argv, nil, nil);
to
int retVal = UIApplicationMain(argc, argv, nil, #"AppDelegate");
(Replace #"AppDelegate" with your UIApplicationDelegate class name. That should load your main window into the device.
Also note, that the TTSplitViewController class is a little buggy. I had to modify some code in three20 to make it work as it should. see https://github.com/aporat/three20-splitview-example if you want to try my version of TTSplitViewController.
I have specified dataDetectorTypes on a UITextView so that URLs open in Safari when touched.
Is it possible to intercept this behaviour so I load the URL in a UIWebView instead? Or would I have write my own URL detector code to re-route this?
You would have to do the URL detection yourself and manually load the UIWebView when the URL is tapped.
Everything needs to be custom-done because Apple sends all http:// and https:// URL openings to Safari.
The answer above that works best is the replacement of method implementation for [UIApplication openURL:]
Another way to achieve that, without using runtime.h is to subclass UIApplication. Then, override the openURL: selector. With this approach, you can call [super openURL:] from your subclass for URLs you want the default handling for. It also seems a little cleaner to me since you don't need to mess with the internal method implementations of the classes.
If you choose this approach, though, there are 2 other important steps. In the main.m file you need to change the 3rd argument to the UIApplicationMain function call so that it matches the name of your subclass:
int retVal = UIApplicationMain(argc, argv, #"MyApplicationSubclass", nil);
Also, you should probably change the class of the File's Owner in your MainWindow.xib file from UIApplication to your subclass.
I did everyone a favor and answered your question with a blog post and demo app.
http://52apps.net/post/879106231/method-swizzling-uitextview-and-safari
http://github.com/marksands/UITextViewLinkOptions
To expand on tt.Kilew's post, you create the category, but call your method something else such as customOpenURL. When you want to go back to Safari you do something called Method Swizzling. It looks like this:
#import <objc/runtime.h>
..
Method customOpenUrl = class_getInstanceMethod([UIApplication class], #selector(customOpenURL:));
Method openUrl = class_getInstanceMethod([UIApplication class], #selector(openURL:));
method_exchangeImplementations(customOpenUrl, openUrl);
Just call this method to swap the openURL implementation with your customOpenURL implementation when you do and don't want to use Safari.
Check out the demo app for more detail. Hope this helps! :)
Edit
If you don't want to risk your app getting rejected, you might want to check out a custom UITextView I developed to better suit the situation: https://github.com/marksands/MSTextView
Another Answer :) That works fine for me is to re-implement UIApplication openURL:(NSURL *) url
#interface UIApplication (Private)
- (BOOL)openURL:(NSURL*)url;
#end
#implementation UIApplication (Private)
- (BOOL)openURL:(NSURL*)url {
// all viewcontrollers should change currentViewController to self
if ([MyWatcher currentViewController]) {
// Do anything you want
[[MyWatcher handleURL:url withController:[MyWatcher currentViewController]];
return YES;
}
return NO;
}
#end
... Some view controller
- (void)viewDidLoad {
[super viewDidLoad];
[MyWatcher setCurrentController:self];
}
Swift version:
Your standard UITextView setup should look something like this, don't forget the delegate and dataDetectorTypes.
var textView = UITextView(x: 10, y: 10, width: CardWidth - 20, height: placeholderHeight) //This is my custom initializer
textView.text = "dsfadsaf www.google.com"
textView.selectable = true
textView.dataDetectorTypes = UIDataDetectorTypes.Link
textView.delegate = self
addSubview(textView)
After your class ends add this piece:
Note that you need https://github.com/TransitApp/SVWebViewController this library, which is the best one out there as far as I know.
class myVC: UIViewController {
//viewdidload and other stuff here
}
extension MainCard: UITextViewDelegate {
func textView(textView: UITextView, shouldInteractWithURL URL: NSURL, inRange characterRange: NSRange) -> Bool {
//Do your stuff over here
var webViewController = SVModalWebViewController(URL: URL)
view.presentViewController(webViewController, animated: true, completion: nil)
return false
}
}
You can try implementing application:handleOpenURL: in your Application Delegate.
This method should get called whenever a url gets opened. Here you should be able to make the URL open in your webview.
Does any one know, how can i disable cut, copy and paste option on iPhone 3.0?
Thanks for your help and time.
I, too, couldn't find much documentation on using canPerformAction:withSender: for this purpose. So, I settled for clearing the pasteboard when exiting the application. In my AppDelegate.m:
- (void)applicationWillTerminate:(UIApplication *)application {
NSLog(#"application terminating");
// Clear pasteboard to prevent pasting into other applications:
UIPasteboard *pasteBoard = [UIPasteboard generalPasteboard];
pasteBoard.items = nil;
}
This worked well for my user-annotated reference application. I don't mind users copying and pasting within my application, but I'd rather they not republish my original content.
At some point I'd like more fine-grained control, perhaps with canPerformAction:withSender:, so that I can allow users to copy/paste the content they do create themselves.
Override this method in the controller class.
// Hide cut/copy/paste menu
-(BOOL)canPerformAction:(SEL)action withSender:(id)sender {
if ( [UIMenuController sharedMenuController] )
{
[UIMenuController sharedMenuController].menuVisible = NO;
}
return NO;
}
Any responder (UIView or UIWindow subclass) can override the canPerformAction:withSender: method, so you could just return NO for all the actions you don't want to permit.
See the UIResponder documentation...