iOS開(kāi)發(fā):給UIWebview的導(dǎo)航欄添加返回、關(guān)閉按鈕

在我們平日的開(kāi)發(fā)中,不免有原生與H5的交互,比如說(shuō):從原生頁(yè)面的一個(gè)按鈕,點(diǎn)擊之后跳轉(zhuǎn)到了一個(gè)H5的頁(yè)面A,A頁(yè)面中又有一個(gè)按鈕,點(diǎn)擊之后,又加載了一個(gè)新的H5頁(yè)面B,從B點(diǎn)擊一個(gè)按鈕,又加載一個(gè)新的H5頁(yè)面C,如果此時(shí)我們點(diǎn)擊左上角的返回按鈕,會(huì)直接返回到我們的原生頁(yè)面;

是不是上面給用戶的體驗(yàn)很不好(當(dāng)然殘品經(jīng)理會(huì)覺(jué)得是,我們都是無(wú)所謂的啦),此時(shí)我們想要重新定制返回按鈕,我們想要從C頁(yè)面判斷是否還有上一級(jí)H5頁(yè)面可供返回,如果有上一級(jí)頁(yè)面還是H5,點(diǎn)擊左上角的返回則返回到B頁(yè)面,并且在B頁(yè)面的左上角加上一個(gè)關(guān)閉按鈕,這個(gè)關(guān)閉按鈕的作用主要是為了關(guān)閉所有的H5的頁(yè)面,直接返回到我們?cè)捻?yè)面;如果我們不點(diǎn)擊關(guān)閉按鈕,還是點(diǎn)擊返回,則從B頁(yè)面返回到A頁(yè)面;再次點(diǎn)擊返回,則關(guān)閉了H5的頁(yè)面,回到了原生的頁(yè)面;

說(shuō)的也許有點(diǎn)兒繞,不過(guò)大致思想就是:先判斷當(dāng)前的H5頁(yè)面是否可以返回:

//判斷當(dāng)前H5是否可以返回
[self.webView canGoBack]

如果可以返回,則返回到上一個(gè)H5頁(yè)面,并在左上角添加一個(gè)關(guān)閉按鈕,如果不可以返回,則直接:

//回到原生頁(yè)面
[self.navigationController popViewControllerAnimated:YES];

下面是我的主要實(shí)現(xiàn)代碼,我寫(xiě)一個(gè)繼承與UIViewController的類,接受了UIWebviewDelegate,并定義了一個(gè)UIwebview的屬性,給外面留了一個(gè)方法,只需要傳遞一個(gè)URL,我們就可以加載;如果有地方需要加載H5的頁(yè)面,我們可以直接集成與這個(gè)類,這樣的好處在于方便維護(hù);

當(dāng)然我封裝的這個(gè)類,同時(shí)也是支持HTTPS的請(qǐng)求的;話不多說(shuō),代碼如下:

創(chuàng)建一個(gè)類,繼承與UIViewController,.h中的代碼

#import <UIKit/UIKit.h>

@interface SYWebViewController : UIViewController<UIWebViewDelegate, NSURLConnectionDelegate>

//定義一個(gè)屬性,方便外接調(diào)用
@property (nonatomic, strong) UIWebView *webView;

//聲明一個(gè)方法,外接調(diào)用時(shí),只需要傳遞一個(gè)URL即可
- (void)loadHTML:(NSString *)htmlString;

@end

.m中的實(shí)現(xiàn)如下:

#import "SYWebViewController.h"

@interface NSURLRequest (InvalidSSLCertificate)

+ (BOOL)allowsAnyHTTPSCertificateForHost:(NSString*)host;
+ (void)setAllowsAnyHTTPSCertificate:(BOOL)allow forHost:(NSString*)host;

@end

@interface SYWebViewController ()

@property (nonatomic, strong) NSURLRequest *request;
//判斷是否是HTTPS的
@property (nonatomic, assign) BOOL isAuthed;

//返回按鈕
@property (nonatomic, strong) UIBarButtonItem *backItem;
//關(guān)閉按鈕
@property (nonatomic, strong) UIBarButtonItem *closeItem;

@end

@implementation SYWebViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor whiteColor];
    self.webView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height - 64)];
    [self.view addSubview:self.webView];
    
    [self addLeftButton];
}

//加載URL
- (void)loadHTML:(NSString *)htmlString
{
    NSURL *url = [NSURL URLWithString:htmlString];
    self.request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:5.0];
    [NSURLRequest setAllowsAnyHTTPSCertificate:YES forHost:[url host]];
    [self.webView loadRequest:self.request];
}

#pragma mark - UIWebViewDelegate

//開(kāi)始加載
- (BOOL)webView:(UIWebView *)awebView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
    NSString* scheme = [[request URL] scheme];
    //判斷是不是https
    if ([scheme isEqualToString:@"https"]) {
        //如果是https:的話,那么就用NSURLConnection來(lái)重發(fā)請(qǐng)求。從而在請(qǐng)求的過(guò)程當(dāng)中吧要請(qǐng)求的URL做信任處理。
        if (!self.isAuthed) {
            NSURLConnection* conn = [[NSURLConnection alloc] initWithRequest:request delegate:self];
            [conn start];
            [awebView stopLoading];
            return NO;
        }
    }
    return YES;
}

//設(shè)置webview的title為導(dǎo)航欄的title
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
    self.title = [webView stringByEvaluatingJavaScriptFromString:@"document.title"];
}

#pragma mark ================= NSURLConnectionDataDelegate <NSURLConnectionDelegate>

- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace
{
    return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust];
}

- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
    if ([challenge previousFailureCount] == 0) {
        self.isAuthed = YES;
        //NSURLCredential 這個(gè)類是表示身份驗(yàn)證憑據(jù)不可變對(duì)象。憑證的實(shí)際類型聲明的類的構(gòu)造函數(shù)來(lái)確定。
        NSURLCredential *cre = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
        [challenge.sender useCredential:cre forAuthenticationChallenge:challenge];
    }
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
    NSLog(@"網(wǎng)絡(luò)不給力");
}

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
    self.isAuthed = YES;
    //webview 重新加載請(qǐng)求。
    [self.webView loadRequest:self.request];
    [connection cancel];
}

#pragma mark - 添加關(guān)閉按鈕

- (void)addLeftButton
{
    self.navigationItem.leftBarButtonItem = self.backItem;
}

//點(diǎn)擊返回的方法
- (void)backNative
{
    //判斷是否有上一層H5頁(yè)面
    if ([self.webView canGoBack]) {
          //如果有則返回
        [self.webView goBack];
        //同時(shí)設(shè)置返回按鈕和關(guān)閉按鈕為導(dǎo)航欄左邊的按鈕
        self.navigationItem.leftBarButtonItems = @[self.backItem, self.closeItem];
    } else {
        [self closeNative];
    }
}

//關(guān)閉H5頁(yè)面,直接回到原生頁(yè)面
- (void)closeNative
{
    [self.navigationController popViewControllerAnimated:YES];
}

#pragma mark - init

- (UIBarButtonItem *)backItem
{
    if (!_backItem) {
        _backItem = [[UIBarButtonItem alloc] init];
        UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
        //這是一張“<”的圖片,可以讓美工給切一張
        UIImage *image = [UIImage imageNamed:@"sy_back"];
        [btn setImage:image forState:UIControlStateNormal];
        [btn setTitle:@"返回" forState:UIControlStateNormal];
        [btn addTarget:self action:@selector(backNative) forControlEvents:UIControlEventTouchUpInside];
        [btn.titleLabel setFont:[UIFont systemFontOfSize:17]];
        [btn setTitleColor:[UIColor sy_backColor] forState:UIControlStateNormal];
        //字體的多少為btn的大小
        [btn sizeToFit];
        //左對(duì)齊
        btn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
        //讓返回按鈕內(nèi)容繼續(xù)向左邊偏移15,如果不設(shè)置的話,就會(huì)發(fā)現(xiàn)返回按鈕離屏幕的左邊的距離有點(diǎn)兒大,不美觀
        btn.contentEdgeInsets = UIEdgeInsetsMake(0, -15, 0, 0);
        btn.frame = CGRectMake(0, 0, 40, 40);
        _backItem.customView = btn;
    }
    return _backItem;
}

- (UIBarButtonItem *)closeItem
{
    if (!_closeItem) {
        _closeItem = [[UIBarButtonItem alloc] initWithTitle:@"關(guān)閉" style:UIBarButtonItemStylePlain target:self action:@selector(closeNative)];
    }
    return _closeItem;
}

@end

具體的使用方法就是,創(chuàng)建一個(gè)類,繼承與這類:SYWebViewController

#import <UIKit/UIKit.h>
#import "SYWebViewController.h"

@interface SYFlashHTMLViewController : SYWebViewController

@end

然后在這個(gè)類的.m中的viewDidLoad中,調(diào)用父視圖加載URL的方法,即:

- (void)viewDidLoad {
    [super viewDidLoad];
    self.webView.delegate = self;
    [self loadHTML:self.htmlString];
}

效果如下圖:打開(kāi)百度(圖片1),點(diǎn)擊圖片進(jìn)入(圖片2),點(diǎn)擊返回返回到(圖片3),圖片1和圖片的區(qū)別在于多了個(gè)關(guān)閉按鈕:

圖片1.png

圖片2.png

圖片3.png

GitHub地址:Demo
純手打,喜歡點(diǎn)個(gè)贊,希望對(duì)看到的你有所幫助?。?!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,932評(píng)論 25 709
  • 得到App聽(tīng)書(shū)國(guó)慶7天挑戰(zhàn)賽筆記30?《別鬧了,費(fèi)曼先生》 文/sd別有余味 和外星人偶遇你和他談什么?這是一位諾...
    sd別有余味閱讀 346評(píng)論 0 0
  • 今周的文章我一拖再拖,說(shuō)真的關(guān)于醫(yī)源性損傷,我真的不懂怎么說(shuō)才好,現(xiàn)代醫(yī)學(xué)是教我們有病要趕快治療,不要錯(cuò)過(guò)治療時(shí)機(jī)...
    A美麗人生閱讀 537評(píng)論 0 0
  • pragma mark 位運(yùn)算02-左移右移 pragma mark 概念 pragma mark 代碼
    liyuhong165閱讀 679評(píng)論 0 2

友情鏈接更多精彩內(nèi)容