Created
January 5, 2015 01:35
-
-
Save shawnthroop/e5a7c5b7a59710b6bf0e to your computer and use it in GitHub Desktop.
A self contained UINavigationViewController and UIViewController for presenting a WKWebView on iOS 8
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import <WebKit/WebKit.h> | |
@protocol PRSProgressDelegate <NSObject> | |
- (void)setNavigationTitle:(NSString *)title; | |
- (void)setProgress:(CGFloat)progress animated:(BOOL)animated; | |
- (void)setVisible:(BOOL)visible animated:(BOOL)animated; | |
@end | |
typedef void(^PRSControllerDismissBlock)(UIViewController *viewController); | |
@interface PRSModalWebViewController : UINavigationController <PRSProgressDelegate> | |
- (instancetype)initWithURL:(NSURL *)URL dismissBlock:(PRSControllerDismissBlock)block; | |
@end | |
@interface PRSProgressNavigationBar : UINavigationBar | |
- (void)setProgressBarColor:(UIColor *)color; | |
- (void)setProgressBarVisible:(BOOL)visible aniamted:(BOOL)animated; | |
- (void)setProgress:(CGFloat)progress animated:(BOOL)animated; | |
@end | |
@interface PRSWebViewController : UIViewController | |
@property (nonatomic, readonly) WKWebView *webView; | |
- (instancetype)initWithURL:(NSURL *)URL progressDelegate:(id<PRSProgressDelegate>)delegate dismissBlock:(PRSControllerDismissBlock)block; | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import "PRSModalWebViewController.h" | |
@class PRSWebViewController; | |
@interface PRSModalWebViewController () | |
@property (nonatomic, strong) PRSWebViewController *webViewController; | |
@property (nonatomic, readonly) PRSProgressNavigationBar *progressNavigationBar; | |
@end | |
@implementation PRSModalWebViewController | |
- (instancetype)initWithURL:(NSURL *)URL dismissBlock:(PRSControllerDismissBlock)block | |
{ | |
if (self = [super initWithNavigationBarClass:[PRSProgressNavigationBar class] toolbarClass:nil]) { | |
self.webViewController = [[PRSWebViewController alloc] initWithURL:URL progressDelegate:self dismissBlock:block]; | |
} | |
return self; | |
} | |
- (PRSProgressNavigationBar *)progressNavigationBar | |
{ | |
if ([self.navigationBar isKindOfClass:[PRSProgressNavigationBar class]]) { | |
return (PRSProgressNavigationBar *)self.navigationBar; | |
} | |
return nil; | |
} | |
- (void)setNavigationTitle:(NSString *)title | |
{ | |
self.webViewController.title = title; | |
} | |
- (void)setProgress:(CGFloat)progress animated:(BOOL)animated | |
{ | |
[self.progressNavigationBar setProgress:progress animated:animated]; | |
} | |
- (void)setVisible:(BOOL)visible animated:(BOOL)animated | |
{ | |
[self.progressNavigationBar setProgressBarVisible:visible aniamted:animated]; | |
} | |
- (void)viewDidLoad | |
{ | |
[super viewDidLoad]; | |
[self.progressNavigationBar setProgressBarColor:[UIColor redColor]]; | |
} | |
@end | |
static void * PRSWebViewControllerContext = &PRSWebViewControllerContext; | |
@interface PRSWebViewController () | |
@property (nonatomic, readwrite) WKWebView *webView; | |
@property (nonatomic) NSURL *initialURL; | |
@property (nonatomic, weak) id<PRSProgressDelegate> progressDelegate; | |
@property (nonatomic, copy) PRSControllerDismissBlock dismissBlock; | |
@end | |
@implementation PRSWebViewController | |
- (instancetype)initWithURL:(NSURL *)URL progressDelegate:(id<PRSProgressDelegate>)delegate dismissBlock:(PRSControllerDismissBlock)block | |
{ | |
if (self = [super init]) { | |
_initialURL = URL; | |
_progressDelegate = delegate; | |
_dismissBlock = block; | |
} | |
return self; | |
} | |
- (void)registerObservers | |
{ | |
[self.webView addObserver:self forKeyPath:PropertyKey(title) options:NSKeyValueObservingOptionNew context:PRSWebViewControllerContext]; | |
[self.webView addObserver:self forKeyPath:PropertyKey(estimatedProgress) options:NSKeyValueObservingOptionNew context:PRSWebViewControllerContext]; | |
[self.webView addObserver:self forKeyPath:@"loading" options:NSKeyValueObservingOptionNew context:PRSWebViewControllerContext]; | |
} | |
- (void)unregisterObservers | |
{ | |
[self.webView removeObserver:self forKeyPath:PropertyKey(title) context:PRSWebViewControllerContext]; | |
[self.webView removeObserver:self forKeyPath:PropertyKey(estimatedProgress) context:PRSWebViewControllerContext]; | |
[self.webView removeObserver:self forKeyPath:@"loading" context:PRSWebViewControllerContext]; | |
} | |
- (void)viewDidLoad | |
{ | |
[super viewDidLoad]; | |
self.webView = [[WKWebView alloc] initWithFrame:self.view.bounds]; | |
[self.view addSubview:self.webView]; | |
UIBarButtonItem *back = [[UIBarButtonItem alloc] initWithTitle:@"Back" style:UIBarButtonItemStylePlain target:self.webView action:@selector(goBack)]; | |
UIBarButtonItem *forward = [[UIBarButtonItem alloc] initWithTitle:@"Forward" style:UIBarButtonItemStylePlain target:self.webView action:@selector(goForward)]; | |
UIBarButtonItem *close = [[UIBarButtonItem alloc] initWithTitle:@"Close" style:UIBarButtonItemStyleDone target:self action:@selector(close)]; | |
UIBarButtonItem *flexibleSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil]; | |
UIBarButtonItem *space = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil]; | |
self.navigationController.toolbarHidden = NO; | |
self.navigationController.toolbarItems = @[back, forward]; | |
self.webView.allowsBackForwardNavigationGestures = YES; | |
[self registerObservers]; | |
} | |
- (void)viewDidAppear:(BOOL)animated | |
{ | |
[super viewDidAppear:animated]; | |
if (self.initialURL) { | |
[self.webView loadRequest:[NSURLRequest requestWithURL:self.initialURL]]; | |
[self.progressDelegate setNavigationTitle:self.initialURL.absoluteString]; | |
} | |
} | |
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context | |
{ | |
if (context == PRSWebViewControllerContext) { | |
if ([keyPath isEqualToString:PropertyKey(title)]) { | |
NSString *title = change[NSKeyValueChangeNewKey]; | |
[self.progressDelegate setNavigationTitle:title]; | |
} else if ([keyPath isEqualToString:PropertyKey(estimatedProgress)]) { | |
double estimatedProgress = [change[NSKeyValueChangeNewKey] doubleValue]; | |
// NSLog(@"KVO - estimatedProgress: %@", @(estimatedProgress)); | |
[self.progressDelegate setProgress:estimatedProgress animated:YES]; | |
} else if ([keyPath isEqualToString:@"loading"]) { | |
BOOL loading = [change[NSKeyValueChangeNewKey] boolValue]; | |
NSLog(@"KVO - loading: %@", @(loading)); | |
[self.progressDelegate setVisible:loading animated:YES]; | |
} | |
} else { | |
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; | |
} | |
} | |
- (void)close | |
{ | |
__weak typeof(self) welf = self; | |
[self dismissViewControllerAnimated:YES completion:^{ | |
typeof(welf) strongSelf = welf; | |
if (strongSelf && strongSelf.dismissBlock) { | |
strongSelf.dismissBlock(strongSelf); | |
} | |
}]; | |
} | |
- (void)dealloc | |
{ | |
[self unregisterObservers]; | |
} | |
@end | |
@interface PRSProgressNavigationBar () | |
@property (nonatomic, strong) UIProgressView *progressView; | |
@property (nonatomic, getter = isVisible) BOOL visible; | |
@end | |
@implementation PRSProgressNavigationBar | |
- (instancetype)initWithFrame:(CGRect)frame | |
{ | |
if (self = [super initWithFrame:frame]) { | |
_progressView = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleBar]; | |
_progressView.translatesAutoresizingMaskIntoConstraints = NO; | |
[self addSubview:_progressView]; | |
[self addConstraint:[NSLayoutConstraint constraintWithItem:_progressView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeWidth multiplier:1.0 constant:0]]; | |
[self addConstraint:[NSLayoutConstraint constraintWithItem:_progressView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0]]; | |
[self addConstraint:[NSLayoutConstraint constraintWithItem:_progressView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0]]; | |
} | |
return self; | |
} | |
- (void)setProgressBarColor:(UIColor *)color | |
{ | |
[self.progressView setProgressTintColor:color]; | |
} | |
- (void)setProgress:(CGFloat)progress animated:(BOOL)animated; | |
{ | |
[self.progressView setProgress:(float)progress animated:animated]; | |
} | |
+ (BOOL)automaticallyNotifiesObserversOfVisible | |
{ | |
return NO; | |
} | |
- (void)setProgressBarVisible:(BOOL)visible aniamted:(BOOL)animated | |
{ | |
if (_visible != visible) { | |
self.progressView.alpha = visible ? 0.0f : 1.0f; | |
[UIView animateWithDuration:animated ? 0.35f : 0.0f delay:visible ? 0.2f : 0.0f options:0 animations:^{ | |
self.progressView.alpha = visible ? 1.0f : 0.0f; | |
} completion:nil]; | |
[self willChangeValueForKey:PropertyKey(isVisible)]; | |
_visible = visible; | |
[self didChangeValueForKey:PropertyKey(isVisible)]; | |
} | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is all kind of moot now that we have SFSafariViewController...