Initial commit
This commit is contained in:
Generated
+21
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013 Satoshi Asano
|
||||
|
||||
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.
|
||||
@@ -0,0 +1,35 @@
|
||||
//
|
||||
// NJKWebViewProgress.h
|
||||
//
|
||||
// Created by Satoshi Aasano on 4/20/13.
|
||||
// Copyright (c) 2013 Satoshi Asano. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#undef njk_weak
|
||||
#if __has_feature(objc_arc_weak)
|
||||
#define njk_weak weak
|
||||
#else
|
||||
#define njk_weak unsafe_unretained
|
||||
#endif
|
||||
|
||||
extern const float NJKInitialProgressValue;
|
||||
extern const float NJKInteractiveProgressValue;
|
||||
extern const float NJKFinalProgressValue;
|
||||
|
||||
typedef void (^NJKWebViewProgressBlock)(float progress);
|
||||
@protocol NJKWebViewProgressDelegate;
|
||||
@interface NJKWebViewProgress : NSObject<UIWebViewDelegate>
|
||||
@property (nonatomic, njk_weak) id<NJKWebViewProgressDelegate>progressDelegate;
|
||||
@property (nonatomic, njk_weak) id<UIWebViewDelegate>webViewProxyDelegate;
|
||||
@property (nonatomic, copy) NJKWebViewProgressBlock progressBlock;
|
||||
@property (nonatomic, readonly) float progress; // 0.0..1.0
|
||||
|
||||
- (void)reset;
|
||||
@end
|
||||
|
||||
@protocol NJKWebViewProgressDelegate <NSObject>
|
||||
- (void)webViewProgress:(NJKWebViewProgress *)webViewProgress updateProgress:(float)progress;
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,204 @@
|
||||
//
|
||||
// NJKWebViewProgress.m
|
||||
//
|
||||
// Created by Satoshi Aasano on 4/20/13.
|
||||
// Copyright (c) 2013 Satoshi Asano. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NJKWebViewProgress.h"
|
||||
|
||||
NSString *completeRPCURL = @"webviewprogressproxy:///complete";
|
||||
|
||||
const float NJKInitialProgressValue = 0.1f;
|
||||
const float NJKInteractiveProgressValue = 0.5f;
|
||||
const float NJKFinalProgressValue = 0.9f;
|
||||
|
||||
@implementation NJKWebViewProgress
|
||||
{
|
||||
NSUInteger _loadingCount;
|
||||
NSUInteger _maxLoadCount;
|
||||
NSURL *_currentURL;
|
||||
BOOL _interactive;
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_maxLoadCount = _loadingCount = 0;
|
||||
_interactive = NO;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)startProgress
|
||||
{
|
||||
if (_progress < NJKInitialProgressValue) {
|
||||
[self setProgress:NJKInitialProgressValue];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)incrementProgress
|
||||
{
|
||||
float progress = self.progress;
|
||||
float maxProgress = _interactive ? NJKFinalProgressValue : NJKInteractiveProgressValue;
|
||||
float remainPercent = (float)_loadingCount / (float)_maxLoadCount;
|
||||
float increment = (maxProgress - progress) * remainPercent;
|
||||
progress += increment;
|
||||
progress = fmin(progress, maxProgress);
|
||||
[self setProgress:progress];
|
||||
}
|
||||
|
||||
- (void)completeProgress
|
||||
{
|
||||
[self setProgress:1.0];
|
||||
}
|
||||
|
||||
- (void)setProgress:(float)progress
|
||||
{
|
||||
// progress should be incremental only
|
||||
if (progress > _progress || progress == 0) {
|
||||
_progress = progress;
|
||||
if ([_progressDelegate respondsToSelector:@selector(webViewProgress:updateProgress:)]) {
|
||||
[_progressDelegate webViewProgress:self updateProgress:progress];
|
||||
}
|
||||
if (_progressBlock) {
|
||||
_progressBlock(progress);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)reset
|
||||
{
|
||||
_maxLoadCount = _loadingCount = 0;
|
||||
_interactive = NO;
|
||||
[self setProgress:0.0];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark UIWebViewDelegate
|
||||
|
||||
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
|
||||
{
|
||||
if ([request.URL.absoluteString isEqualToString:completeRPCURL]) {
|
||||
[self completeProgress];
|
||||
return NO;
|
||||
}
|
||||
|
||||
BOOL ret = YES;
|
||||
if ([_webViewProxyDelegate respondsToSelector:@selector(webView:shouldStartLoadWithRequest:navigationType:)]) {
|
||||
ret = [_webViewProxyDelegate webView:webView shouldStartLoadWithRequest:request navigationType:navigationType];
|
||||
}
|
||||
|
||||
BOOL isFragmentJump = NO;
|
||||
if (request.URL.fragment) {
|
||||
NSString *nonFragmentURL = [request.URL.absoluteString stringByReplacingOccurrencesOfString:[@"#" stringByAppendingString:request.URL.fragment] withString:@""];
|
||||
isFragmentJump = [nonFragmentURL isEqualToString:webView.request.URL.absoluteString];
|
||||
}
|
||||
|
||||
BOOL isTopLevelNavigation = [request.mainDocumentURL isEqual:request.URL];
|
||||
|
||||
BOOL isHTTP = [request.URL.scheme isEqualToString:@"http"] || [request.URL.scheme isEqualToString:@"https"];
|
||||
if (ret && !isFragmentJump && isHTTP && isTopLevelNavigation) {
|
||||
_currentURL = request.URL;
|
||||
[self reset];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
- (void)webViewDidStartLoad:(UIWebView *)webView
|
||||
{
|
||||
if ([_webViewProxyDelegate respondsToSelector:@selector(webViewDidStartLoad:)]) {
|
||||
[_webViewProxyDelegate webViewDidStartLoad:webView];
|
||||
}
|
||||
|
||||
_loadingCount++;
|
||||
_maxLoadCount = fmax(_maxLoadCount, _loadingCount);
|
||||
|
||||
[self startProgress];
|
||||
}
|
||||
|
||||
- (void)webViewDidFinishLoad:(UIWebView *)webView
|
||||
{
|
||||
if ([_webViewProxyDelegate respondsToSelector:@selector(webViewDidFinishLoad:)]) {
|
||||
[_webViewProxyDelegate webViewDidFinishLoad:webView];
|
||||
}
|
||||
|
||||
_loadingCount--;
|
||||
[self incrementProgress];
|
||||
|
||||
NSString *readyState = [webView stringByEvaluatingJavaScriptFromString:@"document.readyState"];
|
||||
|
||||
BOOL interactive = [readyState isEqualToString:@"interactive"];
|
||||
if (interactive) {
|
||||
_interactive = YES;
|
||||
NSString *waitForCompleteJS = [NSString stringWithFormat:@"window.addEventListener('load',function() { var iframe = document.createElement('iframe'); iframe.style.display = 'none'; iframe.src = '%@'; document.body.appendChild(iframe); }, false);", completeRPCURL];
|
||||
[webView stringByEvaluatingJavaScriptFromString:waitForCompleteJS];
|
||||
}
|
||||
|
||||
BOOL isNotRedirect = _currentURL && [_currentURL isEqual:webView.request.mainDocumentURL];
|
||||
BOOL complete = [readyState isEqualToString:@"complete"];
|
||||
if (complete && isNotRedirect) {
|
||||
[self completeProgress];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
|
||||
{
|
||||
if ([_webViewProxyDelegate respondsToSelector:@selector(webView:didFailLoadWithError:)]) {
|
||||
[_webViewProxyDelegate webView:webView didFailLoadWithError:error];
|
||||
}
|
||||
|
||||
_loadingCount--;
|
||||
[self incrementProgress];
|
||||
|
||||
NSString *readyState = [webView stringByEvaluatingJavaScriptFromString:@"document.readyState"];
|
||||
|
||||
BOOL interactive = [readyState isEqualToString:@"interactive"];
|
||||
if (interactive) {
|
||||
_interactive = YES;
|
||||
NSString *waitForCompleteJS = [NSString stringWithFormat:@"window.addEventListener('load',function() { var iframe = document.createElement('iframe'); iframe.style.display = 'none'; iframe.src = '%@'; document.body.appendChild(iframe); }, false);", completeRPCURL];
|
||||
[webView stringByEvaluatingJavaScriptFromString:waitForCompleteJS];
|
||||
}
|
||||
|
||||
BOOL isNotRedirect = _currentURL && [_currentURL isEqual:webView.request.mainDocumentURL];
|
||||
BOOL complete = [readyState isEqualToString:@"complete"];
|
||||
if (complete && isNotRedirect) {
|
||||
[self completeProgress];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Method Forwarding
|
||||
// for future UIWebViewDelegate impl
|
||||
|
||||
- (BOOL)respondsToSelector:(SEL)aSelector
|
||||
{
|
||||
if ( [super respondsToSelector:aSelector] )
|
||||
return YES;
|
||||
|
||||
if ([self.webViewProxyDelegate respondsToSelector:aSelector])
|
||||
return YES;
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector
|
||||
{
|
||||
NSMethodSignature *signature = [super methodSignatureForSelector:selector];
|
||||
if(!signature) {
|
||||
if([_webViewProxyDelegate respondsToSelector:selector]) {
|
||||
return [(NSObject *)_webViewProxyDelegate methodSignatureForSelector:selector];
|
||||
}
|
||||
}
|
||||
return signature;
|
||||
}
|
||||
|
||||
- (void)forwardInvocation:(NSInvocation*)invocation
|
||||
{
|
||||
if ([_webViewProxyDelegate respondsToSelector:[invocation selector]]) {
|
||||
[invocation invokeWithTarget:_webViewProxyDelegate];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// NJKWebViewProgressView.h
|
||||
// iOS 7 Style WebView Progress Bar
|
||||
//
|
||||
// Created by Satoshi Aasano on 11/16/13.
|
||||
// Copyright (c) 2013 Satoshi Asano. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface NJKWebViewProgressView : UIView
|
||||
@property (nonatomic) float progress;
|
||||
|
||||
@property (nonatomic) UIView *progressBarView;
|
||||
@property (nonatomic) NSTimeInterval barAnimationDuration; // default 0.1
|
||||
@property (nonatomic) NSTimeInterval fadeAnimationDuration; // default 0.27
|
||||
@property (nonatomic) NSTimeInterval fadeOutDelay; // default 0.1
|
||||
|
||||
- (void)setProgress:(float)progress animated:(BOOL)animated;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,75 @@
|
||||
//
|
||||
// NJKWebViewProgressView.m
|
||||
//
|
||||
// Created by Satoshi Aasanoon 11/16/13.
|
||||
// Copyright (c) 2013 Satoshi Asano. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NJKWebViewProgressView.h"
|
||||
|
||||
@implementation NJKWebViewProgressView
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame
|
||||
{
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
[self configureViews];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)awakeFromNib
|
||||
{
|
||||
[super awakeFromNib];
|
||||
[self configureViews];
|
||||
}
|
||||
|
||||
-(void)configureViews
|
||||
{
|
||||
self.userInteractionEnabled = NO;
|
||||
self.autoresizingMask = UIViewAutoresizingFlexibleWidth;
|
||||
_progressBarView = [[UIView alloc] initWithFrame:self.bounds];
|
||||
_progressBarView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
|
||||
UIColor *tintColor = [UIColor colorWithRed:22.f / 255.f green:126.f / 255.f blue:251.f / 255.f alpha:1.0]; // iOS7 Safari bar color
|
||||
if ([UIApplication.sharedApplication.delegate.window respondsToSelector:@selector(setTintColor:)] && UIApplication.sharedApplication.delegate.window.tintColor) {
|
||||
tintColor = UIApplication.sharedApplication.delegate.window.tintColor;
|
||||
}
|
||||
_progressBarView.backgroundColor = tintColor;
|
||||
[self addSubview:_progressBarView];
|
||||
|
||||
_barAnimationDuration = 0.27f;
|
||||
_fadeAnimationDuration = 0.27f;
|
||||
_fadeOutDelay = 0.1f;
|
||||
}
|
||||
|
||||
-(void)setProgress:(float)progress
|
||||
{
|
||||
[self setProgress:progress animated:NO];
|
||||
}
|
||||
|
||||
- (void)setProgress:(float)progress animated:(BOOL)animated
|
||||
{
|
||||
BOOL isGrowing = progress > 0.0;
|
||||
[UIView animateWithDuration:(isGrowing && animated) ? _barAnimationDuration : 0.0 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
|
||||
CGRect frame = _progressBarView.frame;
|
||||
frame.size.width = progress * self.bounds.size.width;
|
||||
_progressBarView.frame = frame;
|
||||
} completion:nil];
|
||||
|
||||
if (progress >= 1.0) {
|
||||
[UIView animateWithDuration:animated ? _fadeAnimationDuration : 0.0 delay:_fadeOutDelay options:UIViewAnimationOptionCurveEaseInOut animations:^{
|
||||
_progressBarView.alpha = 0.0;
|
||||
} completion:^(BOOL completed){
|
||||
CGRect frame = _progressBarView.frame;
|
||||
frame.size.width = 0;
|
||||
_progressBarView.frame = frame;
|
||||
}];
|
||||
}
|
||||
else {
|
||||
[UIView animateWithDuration:animated ? _fadeAnimationDuration : 0.0 delay:0.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
|
||||
_progressBarView.alpha = 1.0;
|
||||
} completion:nil];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
Generated
+66
@@ -0,0 +1,66 @@
|
||||
# NJKWebViewProgress
|
||||
NJKWebViewProgress is a progress interface library for UIWebView. Currently, UIWebView doesn't have official progress interface. You can implement progress bar for your in-app browser using this module.
|
||||
|
||||
<img src="https://raw.github.com/ninjinkun/NJKWebViewProgress/master/DemoApp/Screenshot/screenshot1.png" alt="iOS ScreenShot 1" width="240px" style="width: 240px;" />
|
||||
|
||||
NJKWebViewProgress doesn't use CocoaTouch's private methods. It's AppStore safe.
|
||||
|
||||
# Used in Production
|
||||
- [Yahoo! JAPAN](https://itunes.apple.com/app/yahoo!-japan/id299147843?mt=8)
|
||||
- [Facebook](https://itunes.apple.com/app/facebook/id284882215?mt=8)
|
||||
|
||||
# Requirements
|
||||
- iOS 4.3 or later
|
||||
- ARC
|
||||
|
||||
# Usage
|
||||
Instance `NJKWebViewProgress` and set `UIWebViewDelegate`. If you set `webViewProxyDelegate`, `NJKWebViewProgress` should perform as a proxy object.
|
||||
|
||||
```objc
|
||||
_progressProxy = [[NJKWebViewProgress alloc] init]; // instance variable
|
||||
webView.delegate = _progressProxy;
|
||||
_progressProxy.webViewProxyDelegate = self;
|
||||
_progressProxy.progressDelegate = self;
|
||||
```
|
||||
|
||||
When UIWebView start loading, `NJKWebViewProgress` call delegate method and block with progress.
|
||||
```objc
|
||||
-(void)webViewProgress:(NJKWebViewProgress *)webViewProgress updateProgress:(float)progress
|
||||
{
|
||||
[progressView setProgress:progress animated:NO];
|
||||
}
|
||||
```
|
||||
|
||||
```objc
|
||||
progressProxy.progressBlock = ^(float progress) {
|
||||
[progressView setProgress:progress animated:NO];
|
||||
};
|
||||
```
|
||||
|
||||
You can determine the current state of the document by comparing the `progress` value to one of the provided constants:
|
||||
|
||||
```objc
|
||||
-(void)webViewProgress:(NJKWebViewProgress *)webViewProgress updateProgress:(float)progress
|
||||
{
|
||||
if (progress == NJKInteractiveProgressValue) {
|
||||
// The web view has finished parsing the document,
|
||||
// but is still loading sub-resources
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This repository contains iOS 7 Safari style bar `NJKWebViewProgressView`. You can choose `NJKWebViewProgressView`, `UIProgressView` or your custom bar.
|
||||
|
||||
# Install
|
||||
## CocoaPods
|
||||
|
||||
```
|
||||
pod 'NJKWebViewProgress'
|
||||
```
|
||||
|
||||
# License
|
||||
[Apache]: http://www.apache.org/licenses/LICENSE-2.0
|
||||
[MIT]: http://www.opensource.org/licenses/mit-license.php
|
||||
[GPL]: http://www.gnu.org/licenses/gpl.html
|
||||
[BSD]: http://opensource.org/licenses/bsd-license.php
|
||||
[MIT license][MIT].
|
||||
Reference in New Issue
Block a user