Skip to content

Instantly share code, notes, and snippets.

@vanbungkring
Created November 11, 2012 10:22
Show Gist options
  • Save vanbungkring/4054411 to your computer and use it in GitHub Desktop.
Save vanbungkring/4054411 to your computer and use it in GitHub Desktop.
mini
//
// TSMiniWebBrowser.m
// TSMiniWebBrowserDemo
//
// Created by Toni Sala Echaurren on 18/01/12.
// Copyright 2012 Toni Sala. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#import "TSMiniWebBrowser.h"
#import <QuartzCore/QuartzCore.h>
@implementation UINavigationBar (UINavigationBarCategory)
- (void)drawRect:(CGRect)rect {
}
@end
@implementation TSMiniWebBrowser
@synthesize delegate;
@synthesize mode;
@synthesize showURLStringOnActionSheetTitle;
@synthesize showPageTitleOnTitleBar;
@synthesize showReloadButton;
@synthesize showActionButton;
@synthesize barStyle;
@synthesize modalDismissButtonTitle;
#define kToolBarHeight 44
#define kTabBarHeight 49
enum actionSheetButtonIndex {
kSafariButtonIndex,
kChromeButtonIndex,
};
#pragma mark - Private Methods
-(void)setTitleBarText:(NSString*)pageTitle {
if (mode == TSMiniWebBrowserModeModal) {
navigationBarModal.topItem.title = pageTitle;
} else if(mode == TSMiniWebBrowserModeNavigation) {
if(pageTitle) [[self navigationItem] setTitle:pageTitle];
}
}
-(void) toggleBackForwardButtons {
buttonGoBack.enabled = webView.canGoBack;
buttonGoForward.enabled = webView.canGoForward;
}
-(void)showActivityIndicators {
[activityIndicator setHidden:NO];
[activityIndicator startAnimating];
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
}
-(void)hideActivityIndicators {
[activityIndicator setHidden:YES];
[activityIndicator stopAnimating];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}
-(void) dismissController {
if ( webView.loading ) {
[webView stopLoading];
}
[self dismissViewControllerAnimated:YES completion:nil];
// Notify the delegate
if (self.delegate != NULL && [self.delegate respondsToSelector:@selector(tsMiniWebBrowserDidDismiss)]) {
[delegate tsMiniWebBrowserDidDismiss];
}
}
//Added in the dealloc method to remove the webview delegate, because if you use this in a navigation controller
//TSMiniWebBrowser can get deallocated while the page is still loading and the web view will call its delegate-- resulting in a crash
-(void)dealloc
{
[webView setDelegate:nil];
[super dealloc];
}
#pragma mark - Init
// This method is only used in modal mode
-(void) initTitleBar {
// Create a containing view to position the button
UIView *containingView = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, 50, 30)] autorelease];
UIView *containingViewleft = [[[UIView alloc] initWithFrame:CGRectMake(5, 0, 50, 30)] autorelease];
// Create a custom button with the image
UIButton *barUIButton = [UIButton buttonWithType:UIButtonTypeCustom];
[barUIButton setImage:[UIImage imageNamed:@"Close-browser"] forState:UIControlStateNormal];
barUIButton.frame = CGRectMake(30, 8, 14,14);
[barUIButton addTarget:self action:@selector(dismissController) forControlEvents:UIControlEventTouchUpInside];
UIButton *browser = [UIButton buttonWithType:UIButtonTypeCustom];
[browser setImage:[UIImage imageNamed:@"Send-to-Safari"] forState:UIControlStateNormal];
browser.frame = CGRectMake(0, 7, 17,17);
[browser addTarget:self action:@selector(buttonActionTouchUp:) forControlEvents:UIControlEventTouchUpInside];
UIButton *prev = [UIButton buttonWithType:UIButtonTypeCustom];
[prev setImage:[UIImage imageNamed:@"Prev"] forState:UIControlStateNormal];
prev.frame = CGRectMake(0, 7, 17,17);
[prev addTarget:self action:@selector(backButtonTouchUp:) forControlEvents:UIControlEventTouchUpInside];
UIButton *next = [UIButton buttonWithType:UIButtonTypeCustom];
[next setImage:[UIImage imageNamed:@"next"] forState:UIControlStateNormal];
next.frame = CGRectMake(32, 7, 17,17);
[next addTarget:self action:@selector(forwardButtonTouchUp:) forControlEvents:UIControlEventTouchUpInside];
[containingView addSubview:barUIButton];
[containingView addSubview:browser];
[containingViewleft addSubview:prev];
[containingViewleft addSubview:next];
// Create a container bar button
UIBarButtonItem *containingBarButton = [[[UIBarButtonItem alloc] initWithCustomView:containingView] autorelease];
UIBarButtonItem *containingBarButtonleft = [[[UIBarButtonItem alloc] initWithCustomView:containingViewleft] autorelease];
UINavigationItem *titleBar = [[UINavigationItem alloc] initWithTitle:@""];
// titleBar.leftBarButtonItem = backButton;
titleBar.rightBarButtonItem=containingBarButton;
titleBar.leftBarButtonItem=containingBarButtonleft;
CGFloat width = self.view.frame.size.width;
navigationBarModal = [[UINavigationBar alloc] initWithFrame:CGRectMake(0, 0, width, 44)];
[[UINavigationBar appearance] setBackgroundImage:[UIImage imageNamed:@"Menu-Bar"]
forBarMetrics:UIBarMetricsDefault];
navigationBarModal.layer.zPosition=700.0;
NSLog(@"%f",navigationBarModal.layer.zPosition);
//navigationBar.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleBottomMargin;
navigationBarModal.autoresizingMask = UIViewAutoresizingFlexibleWidth;
[navigationBarModal pushNavigationItem:titleBar animated:NO];
[self.view addSubview:navigationBarModal];
}
-(void) initWebView {
CGSize viewSize = self.view.frame.size;
if (mode == TSMiniWebBrowserModeModal) {
webView = [[UIWebView alloc] initWithFrame:CGRectMake(0, kToolBarHeight, viewSize.width, viewSize.height)];
} else if(mode == TSMiniWebBrowserModeNavigation) {
webView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, viewSize.width, viewSize.height-kToolBarHeight)];
} else if(mode == TSMiniWebBrowserModeTabBar) {
self.view.backgroundColor = [UIColor redColor];
webView = [[UIWebView alloc] initWithFrame:CGRectMake(0, kToolBarHeight-1, viewSize.width, viewSize.height-kToolBarHeight+1)];
}
webView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.view addSubview:webView];
webView.scalesPageToFit = YES;
webView.delegate = self;
// Load the URL in the webView
NSURLRequest *requestObj = [NSURLRequest requestWithURL:urlToLoad];
[webView loadRequest:requestObj];
}
#pragma mark -
- (id)initWithUrl:(NSURL*)url {
self = [self init];
if(self)
{
urlToLoad = url;
// Defaults
mode = TSMiniWebBrowserModeNavigation;
showURLStringOnActionSheetTitle = YES;
showPageTitleOnTitleBar = YES;
showReloadButton = YES;
showActionButton = YES;
modalDismissButtonTitle = NSLocalizedString(@"Done", nil);
forcedTitleBarText = nil;
barStyle = UIBarStyleDefault;
}
return self;
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.layer.zPosition=100;
// Main view frame.
if (mode == TSMiniWebBrowserModeTabBar) {
CGFloat viewWidth = [UIScreen mainScreen].bounds.size.width;
CGFloat viewHeight = [UIScreen mainScreen].bounds.size.height - kTabBarHeight;
if (![UIApplication sharedApplication].statusBarHidden) {
viewHeight -= [UIApplication sharedApplication].statusBarFrame.size.height;
}
self.view.frame = CGRectMake(0, 0, viewWidth, viewHeight);
}
// Store the current navigationBar bar style to be able to restore it later.
if (mode == TSMiniWebBrowserModeNavigation) {
originalBarStyle = self.navigationController.navigationBar.barStyle;
}
// Init tool bar
// [self initToolBar];
// Init web view
[self initWebView];
// Init title bar if presented modally
if (mode == TSMiniWebBrowserModeModal) {
[self initTitleBar];
}
// Status bar style
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackOpaque animated:NO];
// UI state
buttonGoBack.enabled = NO;
buttonGoForward.enabled = NO;
if (forcedTitleBarText != nil) {
[self setTitleBarText:forcedTitleBarText];
}
}
- (void)viewDidUnload
{
[super viewDidUnload];
}
-(void) viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
// Restore navigationBar bar style.
if (mode == TSMiniWebBrowserModeNavigation) {
self.navigationController.navigationBar.barStyle = originalBarStyle;
}
// Restore Status bar style
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackOpaque animated:NO];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
/* Fix for landscape + zooming webview bug.
* If you experience perfomance problems on old devices ratation, comment out this method.
*/
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
CGFloat ratioAspect = webView.bounds.size.width/webView.bounds.size.height;
switch (toInterfaceOrientation) {
case UIInterfaceOrientationPortraitUpsideDown:
case UIInterfaceOrientationPortrait:
// Going to Portrait mode
for (UIScrollView *scroll in [webView subviews]) { //we get the scrollview
// Make sure it really is a scroll view and reset the zoom scale.
if ([scroll respondsToSelector:@selector(setZoomScale:)]){
scroll.minimumZoomScale = scroll.minimumZoomScale/ratioAspect;
scroll.maximumZoomScale = scroll.maximumZoomScale/ratioAspect;
[scroll setZoomScale:(scroll.zoomScale/ratioAspect) animated:YES];
}
}
break;
default:
// Going to Landscape mode
for (UIScrollView *scroll in [webView subviews]) { //we get the scrollview
// Make sure it really is a scroll view and reset the zoom scale.
if ([scroll respondsToSelector:@selector(setZoomScale:)]){
scroll.minimumZoomScale = scroll.minimumZoomScale *ratioAspect;
scroll.maximumZoomScale = scroll.maximumZoomScale *ratioAspect;
[scroll setZoomScale:(scroll.zoomScale*ratioAspect) animated:YES];
}
}
break;
}
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
}
#pragma mark - Action Sheet
- (void)showActionSheet {
NSString *urlString = @"";
if (showURLStringOnActionSheetTitle) {
NSURL* url = [webView.request URL];
urlString = [url absoluteString];
}
UIActionSheet *actionSheet = [[UIActionSheet alloc] init];
actionSheet.title = urlString;
actionSheet.delegate = self;
[actionSheet addButtonWithTitle:NSLocalizedString(@"Open in Safari", nil)];
if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"googlechrome://"]]) {
// Chrome is installed, add the option to open in chrome.
[actionSheet addButtonWithTitle:NSLocalizedString(@"Open in Chrome", nil)];
}
actionSheet.cancelButtonIndex = [actionSheet addButtonWithTitle:NSLocalizedString(@"Cancel", nil)];
actionSheet.actionSheetStyle = UIActionSheetStyleBlackTranslucent;
if (mode == TSMiniWebBrowserModeTabBar) {
[actionSheet showFromTabBar:self.tabBarController.tabBar];
}
//else if (mode == TSMiniWebBrowserModeNavigation && [self.navigationController respondsToSelector:@selector(tabBarController)]) {
else if (mode == TSMiniWebBrowserModeNavigation && self.navigationController.tabBarController != nil) {
[actionSheet showFromTabBar:self.navigationController.tabBarController.tabBar];
}
else {
[actionSheet showInView:self.view];
}
}
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == [actionSheet cancelButtonIndex]) return;
NSURL *theURL = [webView.request URL];
if (theURL == nil || [theURL isEqual:[NSURL URLWithString:@""]]) {
theURL = urlToLoad;
}
if (buttonIndex == kSafariButtonIndex) {
[[UIApplication sharedApplication] openURL:theURL];
}
else if (buttonIndex == kChromeButtonIndex) {
NSString *scheme = theURL.scheme;
// Replace the URL Scheme with the Chrome equivalent.
NSString *chromeScheme = nil;
if ([scheme isEqualToString:@"http"]) {
chromeScheme = @"googlechrome";
} else if ([scheme isEqualToString:@"https"]) {
chromeScheme = @"googlechromes";
}
// Proceed only if a valid Google Chrome URI Scheme is available.
if (chromeScheme) {
NSString *absoluteString = [theURL absoluteString];
NSRange rangeForScheme = [absoluteString rangeOfString:@":"];
NSString *urlNoScheme = [absoluteString substringFromIndex:rangeForScheme.location];
NSString *chromeURLString = [chromeScheme stringByAppendingString:urlNoScheme];
NSURL *chromeURL = [NSURL URLWithString:chromeURLString];
// Open the URL with Chrome.
[[UIApplication sharedApplication] openURL:chromeURL];
}
}
}
#pragma mark - Actions
- (void)backButtonTouchUp:(id)sender {
[webView goBack];
[self toggleBackForwardButtons];
}
- (void)forwardButtonTouchUp:(id)sender {
[webView goForward];
[self toggleBackForwardButtons];
}
- (void)reloadButtonTouchUp:(id)sender {
[webView reload];
[self toggleBackForwardButtons];
}
- (void)buttonActionTouchUp:(id)sender {
[self showActionSheet];
}
#pragma mark - Public Methods
- (void)setFixedTitleBarText:(NSString*)newTitleBarText {
forcedTitleBarText = newTitleBarText;
showPageTitleOnTitleBar = NO;
}
- (void)loadURL:(NSURL*)url {
[webView loadRequest: [NSURLRequest requestWithURL: url]];
}
#pragma mark - UIWebViewDelegate
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
if ([[request.URL absoluteString] hasPrefix:@"sms:"]) {
[[UIApplication sharedApplication] openURL:request.URL];
return NO;
}
if ([[request.URL absoluteString] hasPrefix:@"http://www.youtube.com/v/"] ||
[[request.URL absoluteString] hasPrefix:@"http://itunes.apple.com/"] ||
[[request.URL absoluteString] hasPrefix:@"http://phobos.apple.com/"]) {
[[UIApplication sharedApplication] openURL:request.URL];
return NO;
}
return YES;
}
- (void)webViewDidStartLoad:(UIWebView *)webView {
[self toggleBackForwardButtons];
[self showActivityIndicators];
}
- (void)webViewDidFinishLoad:(UIWebView *)_webView {
// Show page title on title bar?
if (showPageTitleOnTitleBar) {
NSString *pageTitle = [webView stringByEvaluatingJavaScriptFromString:@"document.title"];
[self setTitleBarText:pageTitle];
}
[self hideActivityIndicators];
[self toggleBackForwardButtons];
}
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
[self hideActivityIndicators];
// To avoid getting an error alert when you click on a link
// before a request has finished loading.
if ([error code] == NSURLErrorCancelled) {
return;
}
// Show error alert
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Could not load page", nil)
message:error.localizedDescription
delegate:self
cancelButtonTitle:nil
otherButtonTitles:NSLocalizedString(@"OK", nil), nil];
[alert show];
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment