Skip to content

Instantly share code, notes, and snippets.

@shawnthroop
Created January 5, 2015 01:35
Show Gist options
  • Save shawnthroop/e5a7c5b7a59710b6bf0e to your computer and use it in GitHub Desktop.
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
#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
#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
@shawnthroop
Copy link
Author

This is all kind of moot now that we have SFSafariViewController...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment