美文网首页iOS开发攻城狮的集散地iOS开发
WKWebView+UIProgressView的简单封装(OC

WKWebView+UIProgressView的简单封装(OC

作者: 绍清_shao | 来源:发表于2017-03-27 14:39 被阅读334次

    OC版

    初始化

    //
    //  SQWebView.h
    //  UUTravel
    //
    //  Created by Dev on 2017/3/24.
    //  Copyright © 2017年 shaoqing. All rights reserved.
    //
    
    #import <UIKit/UIKit.h>
    
    @interface SQWebView : UIView
    
    - (instancetype)initWithFrame:(CGRect)frame withurl:(NSString* )webURLStr;
    - (instancetype)initWithFrame:(CGRect)frame withurl:(NSString* )webURLStr and:(NSDictionary*)parameters;
    
    @end
    

    SQWebView继承自UIView,可以像UIButton或UIImageView一样简单方便使用。
    两个初始化方法,带参数和不带参数。也只能从这两个初始化方法创建SQWebView实例。所以要在.m文件防止使用init或者initWithFrame初始化方法

    - (instancetype)initWithFrame:(CGRect)frame {
        @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"必须使用SQWebView.h文件中声明的初始化方法" userInfo:nil];
    }
    
    - (instancetype)init {
        @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"必须使用SQWebView.h文件中声明的初始化方法" userInfo:nil];
    }
    

    属性

    因为是简单运用,所以前期只有这四个属性,其中parameters是可以为nil,因为加载有些网页不需要参数。

    @interface SQWebView ()
    
    @property (nonatomic, strong, nonnull) UIProgressView *progressView; //进度条
    @property (nonatomic, strong, nonnull) WKWebView *webView;           //webview
    @property (nonatomic, strong, nonnull) NSString *webURLStr;          //requestUrlStr
    @property (nonatomic, strong, nullable) NSDictionary *parameters;    //加载url包含参数
    
    @end
    

    自定义初始化方法

    - (instancetype)initWithFrame:(CGRect)frame withurl:(NSString* )webURLStr{
        self = [super initWithFrame:frame];
        if (self) {
            _webURLStr = webURLStr.copy;
            _parameters = nil;
            _webView = [self webView];
            _progressView = [self progressView];
        }
        return self;
    }
    
    - (instancetype)initWithFrame:(CGRect)frame withurl:(NSString* )webURLStr and:(NSDictionary*)parameters{
        self = [super initWithFrame:frame];
        if (self) {
            _webURLStr = webURLStr.copy;
            _parameters = parameters.copy;
            _webView = [self webView];
            _progressView = [self progressView];
        }
        return self;
    }
    

    属性的 set 方法

    - (UIProgressView *)progressView {
        if (!_progressView) {
            UIProgressView *progressView = [[UIProgressView alloc] initWithFrame:CGRectMake(0.0, 0.0, self.bounds.size.width, 2.0)];
            _progressView = progressView;
            [self addSubview:_progressView];
        }
        return _progressView;
    }
    

    一般加载条宽 2.0,在SQWebview最顶端

    - (WKWebView *)webView {
        if (!_webView) {
            WKWebView *webView = [[WKWebView alloc] initWithFrame:CGRectMake(0.0, 0.0, self.bounds.size.width, self.bounds.size.height - 2.0)];
            
            [webView addObserver:self forKeyPath:NSStringFromSelector(@selector(estimatedProgress)) options:NSKeyValueObservingOptionNew context:nil];
            _webView = webView;
            [self addSubview:_webView];
            if (_parameters) {           // 有参数要加载参数
                __block NSString* baseURLStr = self.webURLStr.copy;
                NSArray<NSString *>* parametersKey = [_parameters allKeys];
                [parametersKey enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
                    NSString *entity = [NSString stringWithFormat:@"%@%@=%@", idx == 0? @"?":@"&", obj, _parameters[obj]];
                    baseURLStr = [baseURLStr stringByAppendingString:entity];
                }];
                [_webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:baseURLStr]]];
            } else {
                [_webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:self.webURLStr]]];
            }
        }
        return _webView;
        
    }
    

    addObserver: forKeyPath:方法添加观察webView加载进度的KVO,当webView加载网页进度有变化会触发observeValueForKeyPath:ofObject:...这个方法。相应的可以在这个方法中改变progressView进度,从而达到有进度提示的自定义webView.

    KVO回调

    #pragma mark - KVO
    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
        if ([keyPath isEqualToString:NSStringFromSelector(@selector(estimatedProgress))] && [object isEqual:self.webView]) {
            if (self.webView.estimatedProgress == 1.0) {
                self.progressView.progress = 0.0;
            } else {
                [self.progressView setProgress:self.webView.estimatedProgress animated:YES];
            }
        } else {
            // Make sure to call the superclass's implementation in the else block in case it is also implementing KVO
            [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
        }
    }
    

    如果你使用的是UIWebView的话是没有estimatedProgress(加载网页进度)属性,所以用WKWebview比UIWebView实现起来简直不要太方便了

    dealloc中移除观察者

    最后别忘了把self从webView中移除观察者

    #pragma mark - dealloc
    - (void)dealloc {
        [self.webView removeObserver:self forKeyPath:NSStringFromSelector(@selector(estimatedProgress))];
    }
    

    我朋友的一篇博客对UIWebView的简单封装写的不错,大家可以去观摩下webView进度条简单封装

    Swift版

    前话

    思路跟OC版的是一毛一样的,就是换了种语言罢了

    定义的属性

        var webURLStr: String
        var parameters: [String : String]?
        
        var webView: WKWebView
        var progressWebView: UIProgressView
    

    只有parameters是定义为可选类型,因为加载URL有不需要参数的情况,所以可以为nil。

    构造指定初始化方法(designated init)

        // MARK: - designated init
        init(webURLStr: String, parameters: [String : String]?, frame: CGRect) {
            self.webURLStr = webURLStr
            self.parameters = parameters
            self.webView = WKWebView()
            self.progressWebView = UIProgressView()
            super.init(frame: frame)
            //custom ui
            setupUI()
        }
    

    初始化好四个存储属性,再调用父类designated init,接着设置progressWebView和webView的相关操作

    设置webView 添加监听对象

        // MARK: - private
        private func setupUI() {
            //设置point&size
            self.progressWebView.frame = CGRect(x: 0.0, y: 0.0, width: self.bounds.size.width, height: 2.0)
            self.webView.frame = CGRect(x: 0.0, y: 0.0, width: self.bounds.size.width, height: self.bounds.size.height)
            
            self.addSubview(self.webView)
            self.addSubview(self.progressWebView)
            //添加监听webView网页加载进度
            self.webView.addObserver(self, forKeyPath: NSStringFromSelector(#selector(getter: webView.estimatedProgress)), options: .new, context: nil)
            //处理参数
            let requestUrl: String
            if let parameters = self.parameters {
                requestUrl = self.urlWith(parameters, baseurl: self.webURLStr)
            } else {
                requestUrl = self.webURLStr
            }
            //加载webView
            self.webView.load(URLRequest(url: URL(string: requestUrl)!))
        }
        
        private func urlWith(_ dictionary: [String : String], baseurl url: String) -> String {
            var i = 0
            var resultUrl = url
            for (key, value) in dictionary {
                resultUrl = resultUrl + (i == 0 ? "?":"&") + key + "=" + value
                i += 1
            }
            return resultUrl
        }
    

    代码都有注释,其中func urlWith(_ dictionary: [String : String], baseurl url: String) -> String这个方法是处理给定参数(存在字典中)拼接到要加载的URL中。例如
    给定参数:{"par1":"value1"} ,baseURL: https//developer.apple,处理后为:https//developer.apple.com?par1=value1

        // MARK: - 移除监听对象
        deinit {
            self.webView.removeObserver(self, forKeyPath: NSStringFromSelector(#selector(getter: webView.estimatedProgress)))
        }
    

    当然别忘了移除监听对象

    定义一个方便的构造器

        // MARK: - convenience init
        convenience init(webURLStr: String, frame: CGRect) {
            self.init(webURLStr: webURLStr, parameters: nil, frame: frame)
        }
        
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    

    这个初始化方法是用来初始化没有参数的情况,还有就是防止用init?(coder aDecoder: NSCoder)这个初始化方法。
    关于如何构造初始化方法,这里推荐两篇博文:
    Swift3御剑术(4) Initialization-初始化
    The Swift Programming Language (Swift 3.0.1)

    相关文章

      网友评论

        本文标题:WKWebView+UIProgressView的简单封装(OC

        本文链接:https://www.haomeiwen.com/subject/oyoxottx.html