http://startupmeme.com/wp-content/uploads/2008/09/stanza-on-iphone.png
I want to achieve functionality like the famous Stanza application screenshot shows.
Content is displayed with the help of UIWebView in html format
A single tap on the UIWebView would show two overlay controls (top & bottom)
The bottom toolbar consists of controls & a slider to give pagination
Please help.
How would I achieve the above in following way:
How do i build up these custom controls?
On single tap, how will i overlay these controls?
How do i combine the UIToolbar(which contains controls) & the slider?
Also there is a need of transition slide effect, top header comes from top of screen, bottom control & slider come from bottom of screen. How will i achieve this?
Please help me out elaborately for (a) - (d). Some code guidance would be very helpful.
Thanks
I am doing what you are looking for in a project I've been working on recently.
Basically I have a UIWebView inside of a UINavigationController with a UIToolbar as a sibling to the UIWebView. I setup the layout of all of this using IB to create a nib linked to my view controller class. I presume you know how to use IB and how to correctly setup all of the delegates, IBOutlets, etc. so will not cover that here.
You need to implement the appropriate delegates in your view controller for this to all work. Here is my interface for the view controller class:
@interface MyViewController : UIViewController <UIWebViewDelegate, UIGestureRecognizerDelegate> {
}
@property (retain) IBOutlet UIWebView *webView;
@property (retain) IBOutlet UINavigationItem *navigationItem;
@property (retain) IBOutlet UIToolbar *toolbar;
- (void)handleTapFrom:(UITapGestureRecognizer *)recognizer;
// UIGestureRecognizerDelegate methods
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer;
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer;
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch;
// UIWebViewDelegate methods
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType;
- (void)webViewDidStartLoad:(UIWebView *)webView;
- (void)webViewDidFinishLoad:(UIWebView *)webView;
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error;
@end
Technically what you are asking about only requires the UIGestureRecognizerDelegate implementation but I presume you will be doing something interesting in your webView and thus will want to also implement the UIWebViewDelegate
I found it was critical to implement the following for these three UGestureRecognizer delegate methods to make this all work since the UIWebView is also recognizing taps:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
return YES;
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
return YES;
}
I register a UITapGestureRecognizer on the webView inside my controller's viewDidLoad method:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
// I perform other appropriate initialization here like adding or removing items from the navigation bar or toolbar
UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapFrom:)];
tapRecognizer.numberOfTapsRequired = 1;
tapRecognizer.delegate = self;
[self.webView addGestureRecognizer:tapRecognizer];
[tapRecognizer release];
}
Here is my handleTapFrom callback:
- (void)handleTapFrom:(UITapGestureRecognizer *)recognizer
{
CGPoint location = [recognizer locationInView:self.navigationController.topViewController.view];
CGRect bounds = self.navigationController.topViewController.view.bounds;
if (location.x < bounds.size.width / 5.0) {
// This is in the left most quadrant
// I implement code here to perform a "previous page" action
} else if (location.x > bounds.size.width * 4.0 / 5.0) {
// This is in the right most quadrant
// I implement code here to perform a "next page" action
} else if ((location.x > bounds.size.width / 3.0) && (location.x < bounds.size.width * 2.0 / 3.0)) {
// This is in the middle third
BOOL hidden = [self.navigationController isNavigationBarHidden];
// resize the height of self.webView1, self.webView2, and self.webView3 based on the toolbar hiding / showing
CGRect webViewControllerFrame = self.webView.frame;
webViewControllerFrame.size.height += (hidden ? -44 : 44);
self.webView.frame = webViewControllerFrame;
// I hide all of the upper status bar and navigation bar, and bottom toolbar for a clean reading screen
[[UIApplication sharedApplication] setStatusBarHidden:!hidden];
[self.navigationController setNavigationBarHidden:!hidden animated:YES];
self.toolbar.hidden = !hidden;
// I perform content relayout here in the now modified webView screen real estate
}
}
This basic framework got me going and hopefully answers your question or at least points you in the right direction.
Notes:
I have not yet dealt with the fact that I may interpret a tap as "show/hide the status/nav/toolbars" AND the UIWebView may act on this same tap as a clicked link, etc. I am planning on looking into that shortly…
The transparency you show in the Stanza screen shot is not a big deal. You will have to play with the alpha settings on the various nav/toolbars to accomplish that plus change the resizing code on the UIWebView above. I in fact periodically overlay an additional semi-transparent toolbar for temporary status, alerts, etc and do not resize the UIWebView so that it is underneath and still somewhat visible through this alert toolbar.
bg clearly understands iPhone mechanics, so definitely +1 there, but I might know another way.
Overlay a button (or view) onto the top.
Register a tap catcher however you want (Recognizer, touches ended with [[event touches] tapCount] or IB, or manual action... basically grab the taps).
After you get the tap, save where it was, call a function that notifies your web view to split (or if it's like stanza, says to add the overlay) then literally send the touch through the views by "faking" a touch, similar to this: Is there a way to pass touches through on the iPhone?
or create your own target-action method and send it (probably easier).
If you understand the SDK, the above should make sense to you. Specifically the views and everything related (except the graphics, you can skip that reading)