How to implement a progress bar on top of UIWebView? - ios

I am developing application for iOS7 in xcode 5. I have a view controller ADMSViewController
The .h file is as follows
#import <UIKit/UIKit.h>
#import "IMTWebView.h"
#interface ADMSViewController : UIViewController <UIWebViewDelegate,IMTWebViewProgressDelegate>
{
NSString *barcode;
NSString *vinNumber;
NSTimer *timer;
}
#property (nonatomic,retain) IBOutlet UIWebView *webView;
#property (nonatomic,retain) IBOutlet UIProgressView *progressView;
#end
The .m file is as follows
#import "ADMSViewController.h"
#import <QuartzCore/QuartzCore.h>
#implementation ADMSViewController
#synthesize webView;
#synthesize progressView;
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://google.com/"]]];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.navigationController setNavigationBarHidden:YES animated:animated];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[self.navigationController setNavigationBarHidden:NO animated:animated];
}
- (void)webView:(IMTWebView *)_webView didReceiveResourceNumber:(int)resourceNumber totalResources:(int)totalResources {
[self.progressView setProgress:((float)resourceNumber) / ((float)totalResources)];
if (resourceNumber == totalResources) {
_webView.resourceCount = 0;
_webView.resourceCompletedCount = 0;
}
}
- (void)viewDidUnload
{
[super viewDidUnload];
self.webView = nil;
self.progressView = nil;
}
#end
The IMTWebview.h file is as follows
#import <UIKit/UIKit.h>
#class IMTWebView;
#protocol IMTWebViewProgressDelegate <NSObject>
#required
- (void) webView:(IMTWebView*)webView didReceiveResourceNumber:(int)resourceNumber totalResources:(int)totalResources;
#end
#interface IMTWebView : UIWebView {
}
#property (nonatomic, assign) int resourceCount;
#property (nonatomic, assign) int resourceCompletedCount;
#property (nonatomic, assign) id<IMTWebViewProgressDelegate> progressDelegate;
#end
the IMTWebCiew.m file is as follows
#import "IMTWebView.h"
#interface UIWebView ()
-(id)webView:(id)view identifierForInitialRequest:(id)initialRequest fromDataSource:(id)dataSource;
-(void)webView:(id)view resource:(id)resource didFinishLoadingFromDataSource:(id)dataSource;
-(void)webView:(id)view resource:(id)resource didFailLoadingWithError:(id)error fromDataSource:(id)dataSource;
#end
#implementation IMTWebView
#synthesize progressDelegate;
#synthesize resourceCount;
#synthesize resourceCompletedCount;
-(id)webView:(id)view identifierForInitialRequest:(id)initialRequest fromDataSource:(id)dataSource
{
[super webView:view identifierForInitialRequest:initialRequest fromDataSource:dataSource];
return [NSNumber numberWithInt:resourceCount++];
}
- (void)webView:(id)view resource:(id)resource didFailLoadingWithError:(id)error fromDataSource:(id)dataSource {
[super webView:view resource:resource didFailLoadingWithError:error fromDataSource:dataSource];
resourceCompletedCount++;
if ([self.progressDelegate respondsToSelector:#selector(webView:didReceiveResourceNumber:totalResources:)]) {
[self.progressDelegate webView:self didReceiveResourceNumber:resourceCompletedCount totalResources:resourceCount];
}
}
-(void)webView:(id)view resource:(id)resource didFinishLoadingFromDataSource:(id)dataSource
{
[super webView:view resource:resource didFinishLoadingFromDataSource:dataSource];
resourceCompletedCount++;
if ([self.progressDelegate respondsToSelector:#selector(webView:didReceiveResourceNumber:totalResources:)]) {
[self.progressDelegate webView:self didReceiveResourceNumber:resourceCompletedCount totalResources:resourceCount];
}
}
#end
My issue is that the progress bar is not animating in the webview. Please help me as I am a newbie to ios development. If there is any other method to implement the same, do inform me.
Thank you in advance for your answers.

For this kind of thing, you can only really 'detect' page size by using Content-Length headers, but otherwise you can still present a loading control (like one of the moving zebra crossing type bars which doesn't show a discrete % progress but shows that activity is occurring.. or even just a UIActivityIndicator). You could try a ready-made class like http://allseeing-i.com/ASIHTTPRequest/ASIWebPageRequest too, which CAN show progress. The author states:
ASIWebPageRequests do not currently support progress tracking for an entire request with its external resources. However, progress updates from external resource requests are passed on to your delegate, so with a bit of work it may be possible to implement this yourself.

Related

How to make the keyboard disappear programmatically in iOS

I am having trouble getting the keyboard to disappear after entering text. I have many solutions for previous versions of Xcode, but nothing for Xcode 7. My current ViewController.h file looks like:
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController <UITextFieldDelegate>
#property (strong, nonatomic) IBOutlet UITextField *txtUsername;
#property (strong, nonatomic) IBOutlet UITextField *txtPassword;
#end
My .m file looks like:
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize txtUsername;
#synthesize txtPassword;
- (void)viewDidLoad {
[super viewDidLoad];
self.txtUsername.delegate = self;
self.txtPassword.delegate = self;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (BOOL) textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
return YES;
}
#end
I have assigned the delegate from the textField to the ViewController as well.
Update The View I was working with was not assigned to the ViewController class and therefore did not inherit the textFielfShouldReturn method I needed.
Try:
[self.view endEditing:YES];

delegate respondsToSelector:selector not working

I saw a lot of this kind of questions and answers here, but couldn't find solution to my problem. I'm trying to send data from one view controller to another and use delegate. But don't know why my postDelegate doesn't responds to selector. Is something wrong with this code or what is the problem?
PostViewController.h file
#protocol GetDataDelegate <NSObject>
-(void)getPassedInfo:(NSString*)info;
#end
#interface PostViewController : UIViewController
#property (nonatomic, weak) id <GetDataDelegate> postDelegate;
#end;
PostViewController.m file
#import "PostViewController.h"
- (IBAction)postData:(id)sender {
if ([_postDelegate respondsToSelector:#selector(getPassedInfo:)]) {
[self.postDelegate getPassedInfo:#"data"];
NSLog(#"responds");
}
[self dismissViewControllerAnimated:YES completion:nil];
}
in second view controllers .h file
#import "PostViewController.h"
#interface MainViewController : UITableViewController <GetDataDelegate>
and in .m file
#implementation MainWindowTableViewController
- (void)viewDidLoad
{
[super viewDidLoad];
PostViewController * postController = [[PostViewController alloc]init];
postController.postDelegate = self;
}
and here is delegate method:
-(void)getPassedInfo:(NSString *)info{
NSLog(#"info is %#", info);
}
You need to make postController a property or an ivar. Currently it is a local variable in the viewDidLoad method which will be deallocated after viewDidLoad completes as #CodaFi said above.
#import "PostViewController.h"
#interface MainViewController : UITableViewController <GetDataDelegate>
#property (nonatomic, strong) PostViewController *postController;
#end
Then:
- (void)viewDidLoad
{
[super viewDidLoad];
self.postController = [[PostViewController alloc]init];
self.postController.postDelegate = self;
}

UITextField doesn't work in my SecondViewController

I have a big noob problem. I new in iOS and I'm trying to do this:
I have two ViewControllers. The first one has an button that if it is pushed, control goes to a second view controller.
That works but the problem is when I try to get data in my second view controller. The UITextfield doesn't work.
I'm trying to display which I insert into textfield in the label. But THE TEXTFIELD DOESN'T WORK :(
I putted the IBOutlets succesfully in the xibs and connect the buttons with their IBActions...
This is my code:
ViewController.h
#import <UIKit/UIKit.h>
#import "SecondViewController.h"
#class SecondViewController;
#interface ViewController : UIViewController
#property (strong, nonatomic) SecondViewController *secondViewController;
-(IBAction)buttonClicked:(id)sender;
#end
ViewController.m
#import "ViewController.h"
#implementation ViewController
#synthesize secondViewController;
-(IBAction)buttonClicked:(id)sender {
self.secondViewController = [[SecondViewController alloc]initWithNibName:#"SecondViewController" bundle:nil];
[self presentViewController:self.secondViewController animated:YES completion:nil];
}
SecondViewController.h
#import <UIKit/UIKit.h>
#interface SecondViewController : UIViewController {
IBOutlet UITextField *textField;
UIButton *obtener;
IBOutlet UILabel *label;
}
#property (nonatomic, retain) IBOutlet UITextField *textField;
#property (nonatomic, retain) IBOutlet UIButton *obtener;
#property (nonatomic, retain) IBOutlet UILabel *label;
-(IBAction)obtenerClicked:(id)sender;
#end
SecondViewController.m
#import "SecondViewController.h"
#implementation SecondViewController
#synthesize obtener, textField, label;
-(IBAction)obtenerClicked:(id)sender {
label.text = textField.text;
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return YES;
}
#end
In your SecondViewController.h, add this property:
#property(nonatomic, readwrite) NSString* myString;
now in firstViewController's onClick method, add this line
-(IBAction)buttonClicked:(id)sender {
//....... Previous code....
self.secondViewController.myString= #"String to be sent";
}
This will pass the string for you..
if you want to pass the string in text field, use this:
-(IBAction)buttonClicked:(id)sender {
//....... Previous code....
self.secondViewController.textField.text= #"String to be sent";
}
hope it will work fine for your requirement.
UPDATE:
Do the following to get expected results:
1. make your secondViewController a textView delegate.
in your secondViewController.h
replace #interface SecondViewController : UIViewController with #interface SecondViewController : UIViewController<UITextFieldDelegate>
put a button in your secondViewController & create an IBAction for it.
on Click event of button, write this:
self.label.text= self.textfield.text;
tell me if it does not work.

UITextFieldDelegate not working

I'm trying to separate the UITextViewDelegate methods from the main class of my project, I created a class to manage the delegate methods, but I can not change the values of the IBOulets from the main class.
I made a test project with a ViewController and a TextFieldController, in the Storyboard I add a text field and a label. What I want to do is change the text of the label when I start to write in the text field. Here is the code:
ViewController.h:
#import <UIKit/UIKit.h>
#import "TextFieldController.h"
#interface ViewController : UIViewController
#property (strong, nonatomic) IBOutlet UITextField *textField;
#property (strong, nonatomic) IBOutlet UILabel *charactersLabel;
#end
ViewController.m:
#import "ViewController.h"
#interface ViewController ()
#property (nonatomic, strong) TextFieldController *textFieldController;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
_textFieldController = [[TextFieldController alloc] init];
_textField.delegate = _textFieldController;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#end
TextFieldController.h:
#import <UIKit/UIKit.h>
#import "ViewController.h"
#interface TextFieldController : UIViewController <UITextFieldDelegate>
#end
Text Field Controller.m:
#import "TextFieldController.h"
#interface TextFieldController ()
#property ViewController *viewController;
#end
#implementation TextFieldController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (BOOL) textFieldShouldBeginEditing:(UITextField *)textField {
NSLog(#"hello");
_viewController.charactersLabel.text = #"hello";
return YES;
}
#end
When I start writing in the text field the message "Hello" is printed in the log, but the text of the label does not change. I want to know how to change the label text value from the other class.
First change the TextFieldController.h like this:
#import <UIKit/UIKit.h>
#import "ViewController.h"
#interface TextFieldController : NSObject <UITextFieldDelegate>
{
}
#property (nonatomic, assign) ViewController *viewController;
#end
Then change your TextFieldController.m file like this:
#import "TextFieldController.h"
#interface TextFieldController ()
#end
#implementation TextFieldController
- (BOOL) textFieldShouldBeginEditing:(UITextField *)textField {
NSLog(#"hello");
self.viewController.charactersLabel.text = #"hello";
return YES;
}
#end
In the ViewController.m do like that:
#import "ViewController.h"
#interface ViewController ()
#property (nonatomic, strong) TextFieldController *textFieldController;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
_textFieldController = [[TextFieldController alloc] init];
_textFieldController.viewController = self;
_textField.delegate = _textFieldController;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#end
This will work but I personally dont like that way you took.
Good luck :)
It's failing because _viewController is nil. You need to assign the viewController property in your delegate in order to support the two way communication.
Also, I'd strongly recommend you make your delegate object a subclass of NSObject, and not UIViewController. It does nothing with controlling views. You can just manually instantiate it in your ViewController objects viewDidLoad.
In TextViewController I don't see where the viewController property (_viewController ivar) is being set so it is probably nil. You should set it when you create the TextViewController instance.
When you are navigating to other controllers using storyboad's segue then you need to implement prepareForSegue method to initialised its properties as follows
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([segue.identifier isEqualToString:#"segue for textFieldController"])
{
TextFieldController *_textFieldController = [segue destinationViewController];
_textField.delegate = _textFieldController;
}
}
But I was wondering, why are you setting textFieldDelegate here, why can't you set in TextFieldController's viewDidLoad method as then you didn't you to implement above prepareForSegue method call?
Besides you are keeping strong reference of each other and you are creating strong retain cycle.
One more thing, following code
_textField.delegate = _textFieldController;
will not work, until textFieldController is loaded and its viewDidLoad method is being called as you are only initialising it but its outlets will not be connected until view is loaded into navigation stack.

Sharing data between an IOS Utility Application views

I have created a very basic application using the Utility Application template in Xcode 4.2 in which I want an integer variable obtained from a slider or text field in my FlipsideViewController available in my MainViewController.
I have been searching for hour on global variables but can't find a nice simple answer that works for my specific case.
Please help
(note: I am very new at developing for IOS and objective C. Dumb your answer down for me as much as you are capable!)
Thanks a lot
The following is a basic version of my code showing what I want to do.
FlipSideViewController.h
#import <UIKit/UIKit.h>
#class FlipsideViewController;
#protocol FlipsideViewControllerDelegate
- (void)flipsideViewControllerDidFinish:(FlipsideViewController *)controller;
#end
#interface FlipsideViewController : UIViewController
#property (weak, nonatomic) id <FlipsideViewControllerDelegate> delegate;
- (IBAction)done:(id)sender;
- (IBAction)sliderChange:(id)sender;
#property (weak, nonatomic) IBOutlet UILabel *sliderValueOnFlipside;
#end
FlipSideViewController.m
#import "FlipsideViewController.h"
#interface FlipsideViewController ()
#end
#implementation FlipsideViewController
#synthesize sliderValueOnFlipside;
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)viewDidUnload
{
[self setSliderValueOnFlipside:nil];
[super viewDidUnload];
}
- (BOOL)shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
#pragma mark - Actions
- (IBAction)done:(id)sender
{
[self.delegate flipsideViewControllerDidFinish:self];
}
- (IBAction)sliderChange:(id)sender {
UISlider *slider = (UISlider *) sender;
int var = [slider value];
sliderValueOnFlipside.text = [NSString stringWithFormat:#"Slider Value is %d",var];
}
#end
MainViewController.h
#import "FlipsideViewController.h"
#interface MainViewController : UIViewController <FlipsideViewControllerDelegate>
- (IBAction)showInfo:(id)sender;
#property (weak, nonatomic) IBOutlet UILabel *sliderValueOnMain;
#end
MainViewController.m
#import "MainViewController.h"
#interface MainViewController ()
#end
#implementation MainViewController
#synthesize sliderValueOnMain;
- (void)viewDidLoad
{
[super viewDidLoad];
sliderValueOnMain.text = [NSString stringWithFormat:#"Slider Value from flipside is %d", var];
}
- (void)viewDidUnload
{
[self setSliderValueOnMain:nil];
[super viewDidUnload];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
#pragma mark - Flipside View
- (void)flipsideViewControllerDidFinish:(FlipsideViewController *)controller
{
[self dismissModalViewControllerAnimated:YES];
}
- (IBAction)showInfo:(id)sender
{
FlipsideViewController *controller = [[FlipsideViewController alloc] initWithNibName:#"FlipsideViewController" bundle:nil];
controller.delegate = self;
controller.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:controller animated:YES];
}
#end
I can easily get the value of the slider to be displayed on the flipside view however I also want that value displayed on the main view.
Global variables are generally frowned upon in polite programming circles.
If you want a method in MainViewController to react to a change in state in FlipsideViewController, then you could make MVC a delegate of FVC, and have FVC call a method on MVC when the value changes.
There's a good explanation of the delegate design pattern here: http://mobiledevelopertips.com/objective-c/the-basics-of-protocols-and-delegates.html

Resources