I have a code (objective-c) that should open a new window (viewcontroller) when a link with a certain string in a uiwebview is clicked. But it doesn't work.
Here's the code from the .m file:
-(BOOL)webView2:(UIWebView*)webView2 shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType {
NSURL *url = request.URL;
NSString *urlString = url.absoluteString;
//Check if special link
if ( [ urlString isEqualToString: #"http://google.com/" ] ) {
//Here present the new view controller
ViewController *ViewController8 = [[ViewController alloc] init];
[self presentViewController:ViewController8 animated:YES completion:nil];
return NO;
}
return YES;
}
The new viewcontroller subclass name is: ViewController8 and the UIWebView subclass is: webView2
Here's the code from the .h file:
#import <UIKit/UIKit.h>
#interface ViewController8 : UIViewController
#end
#interface ViewController : UIViewController{
IBOutlet UIScrollView *scrollView;
IBOutlet UIButton *openMenu;
int draw1;
}
- (IBAction)OpenMenu:(id)sender;
#property (retain, nonatomic) IBOutlet UIScrollView *scrollView;
#end
How do I fix it so a new window (viewcontroller) is opened when a link with a certain string in a uiwebview is clicked.
First, are you sure about your method signature for the shouldStartLoadWithRequest delegate method?
Did you really override the default method to have it call:
-(BOOL)webView2:(UIWebView*)webView2 shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType
???
Or should you instead be replacing "webview2" with "webView" there?
Even if you did, the naming convention would be very confusing.
The default implementation is for a class named "UIWebView", but the delegate method references "webView".
But in your case, you have a class called "webView2", and you're calling a delegate method that should be named:
-(BOOL)webView2:(webView2 *)webView2 shouldStartLoadWithRequest...
Doesn't look right at all.
Somehow I think the problem is mixed up in there. But maybe I'm wrong. So the second question is, have you set a breakpoint at the beginning of your shouldStartLoadWithRequest method to see if it ever gets called?
When you say it "doesn't work", what does that mean? How far does it get?
If it actually gets to the method, then perhaps the problem is that the URL it contains is formatted differently than the string you're looking for. Perhaps the trailing '/' isn't there or "www." is there.
Edit:
I would try something like this:
-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType {
NSRange rangeOfGoogle = [request.URL.absoluteString rangeOfString:#"google.com"];
//Check if special link
if (rangeOfGoogle.location != NSNotFound) {
//Here present the new view controller
ViewController8 *viewController = [[ViewController8 alloc] initWithNibName:nil bundle:nil];
[self presentViewController:viewController animated:YES completion:nil];
return NO;
}
return YES;
}
I hope this will work for you
-(BOOL)webView:(UIWebView*)webView2 shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType {
if (navigationType == UIWebViewNavigationTypeLinkClicked) {
NSURL *url = request.URL;
NSString *urlString = url.absoluteString;
//Check if special link
if ( [ urlString isEqualToString: #"http://google.com/" ] ) {
//Here present the new view controller
ViewController *ViewController8 = [[ViewController alloc] init];
[self presentViewController:ViewController8 animated:YES completion:nil];
return NO;
}
}
return YES;
}
it works for me.
Related
Okay it seems like I have made some mistakes and I did not get it with pointer and initializations by now...
Here is the problem :
I have a UIViewController for a registration process called : RegisterViewController
It calls a method in its ViewDidLoad :
[self performSelector:#selector(activateUsernamePopover) withObject:nil afterDelay:0.1];
This method looks like this :
- (void) activateUsernamePopover {
PopoverViewController *popcontroller = [[PopoverViewController alloc] init];
popcontroller.title = nil;
[popcontroller setPopoverText:#"Test"];
FPPopoverController *popover = [[FPPopoverController alloc] initWithViewController:popcontroller];
popover.arrowDirection = FPPopoverArrowDirectionUp;
popover.border = NO;
popover.tint = MgoGreyTint;
[popover setShadowsHidden:true];
[popover presentPopoverFromView:_usernameInput]; }
This will made a Popover visible. This works great.
But I Do have a few more TextFields where I want to show a Popover with a different text.
So I made a method in the PopoverViewController called setPopoverText :
- (void)setPopoverText:(NSString *)text {
[_popoverLabel setText:text];
[_popoverLabel setNeedsDisplay]; }
I call it in my activateUsernamePopover method :
[popcontroller setPopoverText:#"Test"];
And there is the problem.
I can log the text in the PopoverViewControllers method setPopoverText its fine.
But it did not change the text. I logged the _popoverLabel like this :
NSLog(#"%#",_popoverLabel);
and its (null).
I know there is some issue with the pointer or the instance of PopoverViewController I am working with, but objective c is not that clear to me yet.
Anyone got some answers for me ?
How can I change the Text of that UILabel ?
I also could imagine giving the Text to the Controller while instancing it.
Something like that :
PopoverViewController *popcontroller = [[PopoverViewController alloc] initWithPopoverText:#"Test"];
But I don´t know how. I don´t need to change the Text while the popover is visible. It will be released when the user taps in the TextField or elsewhere.
Thanks so far.
Since the UILabel is not created yet when you call init method. the way to do it is to keep text in the NSString property.
In you PopoverViewController, create the init method like this
#interface ViewController : UIViewController
- (id)initWithPopoverText:(NSString *)text;
#end
In the implementation file, keep hold of the text in the property and on viewDidLoad, you could set the text to the label.
#interface PopoverViewController ()
#property (nonatomic) NSString *popoverText;
#end
#implement PopoverViewController
- (id)initWithPopoverText:(NSString *)text {
self = [super init];
if (self) {
_popoverText = text;
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
//set label.text here
self.popoverLabel.text = self.popoverText;
}
#end
I am trying to let my iOS app pull from a text file on a server and display it in a Text view. This works fine if I just do this by setting the url in the viewDidLoad method. But if I do it the way I need to, a button click calls a method that sets the url based on which button is clicked and then populates the Text view also while moving to the view controller, then the Text view does not receive any text.
I am not really sure if this has anything to do with it but could it possibly be because I am using one button that has both a triggered segue to move to the next view controller and then a sent event in order to pull the information? Could it be doing it out of order or something?
Here is my code:
#import "ViewController.h"
#import "STTwitter.h"
#interface ViewController ()
{
STTwitterAPI *twitter;
}
#property (weak, nonatomic) IBOutlet UITextView *scheduleText;
#property (weak, nonatomic) IBOutlet UITextView *tweetText;
#property (weak, nonatomic) IBOutlet UIScrollView *mScrollView;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//pull from server to populate schedule
//[self pullInfo:(1)];
//load tweets
//[self callTwitter];
//set scroll view size
_mScrollView.contentSize = CGSizeMake(320, 300);
}//end viewDidLoad
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}//end didReceiveMemoryWarning
- (void) pullInfo: (int) page
{//pull information from server
NSError* err;
NSURL* url = nil;
if (page == 1)
url = [NSURL URLWithString:#"http://www.mckendree.edu /aecschedule1.txt"];
else if (page == 2)
url = [NSURL URLWithString:#"http://www.mckendree.edu/aecschedule2.txt"];
else if (page == 3)
url = [NSURL URLWithString:#"http://www.mckendree.edu/aecschedule3.txt"];
else if (page == 4)
url = [NSURL URLWithString:#"http://www.mckendree.edu/aecschedule4.txt"];
else if (page == 5)
url = [NSURL URLWithString:#"http://www.mckendree.edu/aecschedule5.txt"];
else if (page == 6)
url = [NSURL URLWithString:#"http://www.mckendree.edu/aecschedule6.txt"];
else if (page == 7)
url = [NSURL URLWithString:#"http://www.mckendree.edu/aecschedule7.txt"];
else if (page == 8)
url = [NSURL URLWithString:#"http://www.mckendree.edu/aecschedule8.txt"];
else if (page == 9)
url = [NSURL URLWithString:#"http://www.mckendree.edu/aecschedule9.txt"];
else if (page == 10)
url = [NSURL URLWithString:#"http://www.mckendree.edu/aecschedule10.txt"];
else if (page == 11)
url = [NSURL URLWithString:#"http://www.mckendree.edu/aecschedule11.txt"];
else if (page == 12)
url = [NSURL URLWithString:#"http://www.mckendree.edu/aecschedule12.txt"];
else if (page == 13)
url = [NSURL URLWithString:#"http://www.mckendree.edu/aecschedule13.txt"];
NSData *htmlData = [NSData dataWithContentsOfURL:url];
NSAttributedString *attrString = [[NSAttributedString alloc] initWithData:htmlData options:#{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute: #(NSUTF8StringEncoding)} documentAttributes:nil error:nil];
//retrieve the text if there was no reading error
if (err != nil)
printf("Error retrieving text");
else
{
[_scheduleText setAttributedText:attrString];
[_scheduleText sizeToFit];
[_scheduleText setTextColor:[UIColor whiteColor]];
}//end else
}//end pullInfo
- (IBAction)settingsClicked:(id)sender
{
UIAlertController *alert = [UIAlertController alertControllerWithTitle:#"McK AEC" message:#"Developed by: Sean Boehnke" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *defaultAction = [UIAlertAction actionWithTitle:#"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {}];
[alert addAction:defaultAction];
[self presentViewController:alert animated:YES completion:nil];
}//end settingsClicked
- (IBAction)time1Clicked:(id)sender
{
[self pullInfo:(1)];
}//end time1Clicked
- (IBAction)time2Clicked:(id)sender
{
[self pullInfo:(2)];
}//end time2Clicked
- (IBAction)time3Clicked:(id)sender
{
[self pullInfo:(3)];
}//end time3Clicked
- (IBAction)time4Clicked:(id)sender
{
[self pullInfo:(4)];
}//end time4Clicked
- (IBAction)time5Clicked:(id)sender
{
[self pullInfo:(5)];
}//end time5Clicked
- (IBAction)time6Clicked:(id)sender
{
[self pullInfo:(6)];
}//end time6Clicked
- (IBAction)time7Clicked:(id)sender
{
[self pullInfo:(7)];
}//end time7Clicked
- (IBAction)time8Clicked:(id)sender
{
[self pullInfo:(8)];
}//end time8Clicked
- (IBAction)time9Clicked:(id)sender
{
[self pullInfo:(9)];
}//end time9Clicked
- (IBAction)time10Clicked:(id)sender
{
[self pullInfo:(10)];
}//end time10Clicked
- (IBAction)time11Clicked:(id)sender
{
[self pullInfo:(11)];
}//end time11Clicked
- (IBAction)time12Clicked:(id)sender
{
[self pullInfo:(12)];
}//end time12Clicked
- (IBAction)time13Clicked:(id)sender
{
[self pullInfo:(13)];
}//end time13Clicked
#end
So based on your description of the issue and your comments there're a few fundamental things that are wrong here. First and foremost, the reason why this will not populate data on your pushed viewController is because you are setting the attributed text on scheduleText which is an instance variable on ViewController. If you are pushing another viewController after those buttons are pressed, then it makes perfect sense that the controller you're pushing would not have this data set because you didn't set it there, you set it on the previous controller. This data has no reason to assume you actually meant to pass it forward. That's just simply not what you asked it to do. If your intent is to pass the data forward, and you have your heart set on storyboard segues you will need to implement prepareForSegue and expose a property you can use to configure the new viewController as it's being prepared for presentation.
Sorry for the wall of text, but this is my recommendation to get through this.
First step, on your storyboard, give all of your buttons hooked up to segues button tags in the preferences tab of the right pane of interface builder. You should tag them 1 through 13 (tradition says start at 0 but this will make the next step simpler for our purposes.)
Next, get rid of all those IBActions for the buttons. We aren't going to need them anymore and they're cluttering your class. You MUST also unhook them in your storyboard after you delete the methods or your app will crash with an error that says "this class is not key value coding-compliant"
Next you need to implement the method -prepareForSegue on your viewController to do the rest of your heavy lifting
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSAttributedString *attrString;
if ([sender isKindOfClass:[UIButton class]]) {
NSUInteger seguePageNumber = ((UIButton *)sender).tag;
attrString = [self pullInfo:seguePageNumber];
}
YourViewControllerClass *vc = (YourViewControllerClass*)[segue destinationViewController];
vc.attributedTextPropertyIExposed = attrString;
//This property needs to be exposed in the new VC's header file. Once the new controller presents you can then use this property to set the string the way you want.
}
As a bonus, here's a pull info method that I referenced above that I find much easier to read.
- (NSAttributedString *)pullInfo:(NSUInteger)pageNumber
{
NSString* urlString = [NSString stringWithFormat:#"http://www.mckendree.edu/aecschedule%lu.txt", (long)pageNumber];
NSURL *url = [NSURL URLWithString:urlString];
NSData *htmlData = [NSData dataWithContentsOfURL:url];
NSAttributedString *attrString = [[NSAttributedString alloc] initWithData:htmlData options:#{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute: #(NSUTF8StringEncoding)} documentAttributes:nil error:nil];
return attrString;
}
it's been almost a week of reading and trying all of these different solutions from this website and others .. but unfortunately nothing work ..
I'm trying to develop a News app (basically, main page and Details page) .. I want to use two different uiwebviews in two view controllers .. For example: The FirstView includes the First uiwebview .. and this uiwebview shows the page (index.htm ) which includes many different news (links).. when the user click on any link ( e.g. details.htm?Id=..) it shows that link in the Second uiwebview in the SecondView controller ...
what I need exactly is, when user click on a link on uiwebview1, it directly open the view controller2 (SecondView) and open that link on the webview2 ... I know it's by using shouldStartLoadWithRequest as ive seen many ( if not all ) examples of how to use it .. but it never worked with me .. the second view controller can never be shown ..as I also set the delegate = self ..
I really tried to do it, but as i'm new ios developer .. I really need some help to get this done ... and i would really appreciate more if someone gives me a link to download the example, not because of anything, but I sometimes find it difficult to put the code on the right place ...and this is might me my problem ...
Many thanks ...
=========
I found this solution on Within a (BOOL)webView: How to open a URL clicked in UIWebView that opens a Modal UIWebView
and after much work .. all errors disappeared .. but still cant move the second view controller .. it never shown .. I used this code :
this is in the viewcontroller.h
#property (nonatomic, strong) IBOutlet UIWebView *webView;
//- (IBAction)prepareForSegue;
#property (strong, nonatomic) NSURL *url;
#property (strong, nonatomic) NSURL *targetUrl;
and this is on the viewcontroller.m
- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType {
//Gets the link.
if (navigationType == UIWebViewNavigationTypeLinkClicked) {
NSURL *URL = [request URL];
NSLog(#"url:%#",request); //Get's the url itself
// [self.navigationController pushViewController:SecondView animated:YES];
// [secondView release];
self.webView.delegate = self;
// ViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:#"SecondView"];
// [self.navigationController pushViewController:controller animated:YES];
//
if ([[URL scheme] isEqualToString:#"http"] ||
[[URL scheme] isEqualToString: #"https" ]) {
targetUrl = url;
[self performSegueWithIdentifier:#"SecondView" sender:self];
return NO;
}
return YES;
}
return YES;
}
and before that
#synthesize webView;
#synthesize targetUrl;
#synthesize url;
and finally :
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
NSLog(#"Source Controller = %#", [segue sourceViewController]);
NSLog(#"Destination Controller = %#", [segue destinationViewController]);
NSLog(#"Segue Identifier = %#", [segue identifier]);
if ([segue.identifier isEqualToString:#"SecondView"]) {
ViewController *wVC = [segue destinationViewController];
wVC.url = targetUrl ; // replace article.url with your url.
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)viewDidLoad {
NSURL *urla= [NSURL URLWithString:#"Index.htm"]; NSURLRequest *requestURL = [NSURLRequest requestWithURL:urla]; [webView loadRequest:requestURL];
//
I exactly copied the code above in my project .. and I believe there is a very tiny mistake ... it doesn't show my SecondView at all when I click on links from index.htm... what should I change on that code ...
Many thanks ...
Your main problem is that you don't have any segue defined in your storyboard. If you connect your two view controllers with a segue, name it "SecondView", and uncomment the following line...
self.webView.delegate = self;
...you'll get past your current problem.
(When the second controller displays, it doesn't seem to load the new URL...but that's some different problem.)
I have a standalone UIViewController with a UIWebView. I need to check if a certain URL has been hit, and if so, present a new UIViewController inside of a UINavigationController.
Here is my code:
-(BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType {
NSURL *url = request.URL;
NSString *urlString = url.absoluteString;
//Check if special link
if ( [ urlString isEqualToString: #"http://www.mysite.com/store" ] ) {
//Here present the new view controller
StoreViewController *controller = [[StoreViewController alloc] init];
[self presentViewController:controller animated:YES completion: nil];
return NO;
}
return YES;
}
However, when I run the app, I get the following error:
WebKit threw an uncaught exception in the method
webView:decidePolicyForNavigationAction:request:frame:decisionListener:
delegate:
<'NSInvalidArgumentException'> * -[__NSArrayM insertObject:atIndex:]:
object cannot be nil
If I try and open the UINavigationController itself it works fine...but then how do I pass data to the StoreViewController itself?
Let's try these solutions:
Destroy webview's delegate in your view controller:
-(void)dealloc{ self.yourWebView.delegate = nil}
Stop request from webView:
-(BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType {
StoreViewController *controller = [[StoreViewController alloc] init];
[self presentViewController:controller animated:YES completion: nil];
//stop loading here
[webview stopLoading];
return NO;
}
Double check in new view controller, do you have any array which it's element is assigned to nil
Hope this helps you
Lets go through the problems one by one:
WebKit Exception: You can resolve this by stopping the webview loading. Just call [webView stopLoading];
Pass data: If you declare your required data in the StoreViewController.h you can easily set them when you are initializing the view controller.
StoreViewController *controller = [[StoreViewController alloc] init];
controller.myStringData = #"Required Data";
controller.myDataDictionary = someDictionary;
You will be able to get the data in the viewDidLoad method of StoreViewController
Hope this helps.
I am a real noob in ios dev. Now i am working on my study project using Zxing.
I make my own project which included dependency third party libraries(Zxing).
Once I scan QRCode which contains with a URL inside, my project will call a class in Zxing library then alert an alertView.
After that, once I click open button on pop-up alertView, it would open that URL by activating Safari.
the code in Zxing looks like this:
//============================================================
- (void)openURL {
[[UIApplication sharedApplication] openURL:self.URL]; //<===== open URL by Safari browser.
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex != [alertView cancelButtonIndex]) {
// perform the action
[self openURL];
}
}
//========================================================
However, my wish is I would like to open that URL in my own webView which constructed by Interface Builder in my "own project" NOT by Safari. Do you have any suggestions? What I have to code in (void)openURL {} ? I got stuck with this issue for 3 days and I now seem to be crazy [p]
Thank you very much for your advance help.
Cheers,
What i did to do this is that I make a new view controller which has webView in it. A property URLstring which get set when the OpenURL method starts. You have to implement delegate methods of webView if you need. The code that I am using is
in WebViewCOntroller.h
#interface WebViewController : UIViewController <UIWebViewDelegate>{
IBOutlet UIWebView *webView;
UIView *activityView;
}
#property (nonatomic, retain) NSString *buyProductLink;
#end
in WebViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
webView.scalesPageToFit = YES;
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:self.buyProductLink]];
[webView loadRequest:request];
[request release];
}
- (BOOL) webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
return YES;
}
- (void) webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
[activityView removeFromSuperview];
}
- (void) webViewDidFinishLoad:(UIWebView *)webView {
[activityView removeFromSuperview];
[activityView release]; activityView = nil;
}
In openURL method use
WebViewController *webViewVC = [[WebViewController alloc] initWithNibName:#"WebViewController" bundle:nil];
webViewVC.buyProductLink = [NSString stringWithFormat:#"%#",result];
[self.navigationController pushViewController:webViewVC animated:YES];