UIWebview加载H5界面侧滑返回上一级
一、UIWebview的发现
问题发现:当UIWebview王深层次点击的时候,返回时需要webView执行goBack方法一级一级返回,这样看到的webView只是在该界面执行刷新,并看不到类似iOS系统那样的侧滑返回上一级。
实现思想:我们可以从第一级开始对每一级webView加载的内容,截取屏幕的图片并保存到数组中,然后给webView添加pan手势,判断手势侧滑的时候,添加UIImageView显示视频里面截图的内容,同时调整webView的x值和imageView的x值,当侧滑完全返回时,移除imageView,webView并重新加载新的链接,即可实现侧滑返回效果。
二、实现代码如下
1、DLPanableWebView.h代码实现
#import <UIKit/UIKit.h>
@class DLPanableWebView;
@protocol DLPanableWebViewDelegate <NSObject>
// 0 成功 1 完成 2 失败
- (void)webViewLoadState:(NSInteger)state;
@optional
- (void)panableWebView:(DLPanableWebView *)webView panPopGesture:(UIPanGestureRecognizer *)pan;
@end
@interface DLPanableWebView : UIWebView
@property(nonatomic, weak) id <DLPanableWebViewDelegate> panDelegate;
@property(nonatomic, assign) BOOL enablePanGesture;
- (void)goBack;
@end
2、DLPanableWebView.m代码实现
#import "DLPanableWebView.h"
@interface DLPanableWebView()<UIWebViewDelegate>
@property (nonatomic, strong) UIGestureRecognizer* popGesture;
@property (nonatomic, weak) id <UIWebViewDelegate> originDelegate;
@property (nonatomic, strong)UIImageView *historyView;
@property (nonatomic, strong) NSMutableArray *historyStack;
@property (nonatomic, assign) CGFloat panStartX;
@end
@implementation DLPanableWebView
+ (UIImage *)screenshotOfView:(UIView *)view {
UIGraphicsBeginImageContextWithOptions(view.frame.size, YES, 0.0);
if ([view respondsToSelector:@selector(drawViewHierarchyInRect:afterScreenUpdates:)]) {
[view drawViewHierarchyInRect:view.bounds afterScreenUpdates:YES];
}
else{
[view.layer renderInContext:UIGraphicsGetCurrentContext()];
}
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
+ (void)addShadowToView:(UIView *)view{
CALayer *layer = view.layer;
UIBezierPath *path = [UIBezierPath bezierPathWithRect:layer.bounds];
layer.shadowPath = path.CGPath;
layer.shadowColor = [UIColor blackColor].CGColor;
layer.shadowOffset = CGSizeZero;
layer.shadowOpacity = 0.4f;
layer.shadowRadius = 8.0f;
}
- (void)setDelegate:(id<UIWebViewDelegate>)delegate{
self.originDelegate = delegate;
}
- (id<UIWebViewDelegate>)delegate{
return self.originDelegate;
}
- (void)goBack{
[super goBack];
[self.historyStack removeLastObject];
}
- (void)setEnablePanGesture:(BOOL)enablePanGesture{
self.popGesture.enabled = enablePanGesture;
}
- (BOOL)enablePanGesture{
return self.popGesture.enabled;
}
- (NSMutableArray *)historyStack {
if (!_historyStack) {
_historyStack = [NSMutableArray array];
}
return _historyStack;
}
- (UIImageView *)historyView{
if (!_historyView) {
if (self.superview) {
_historyView = [[UIImageView alloc] initWithFrame:self.bounds];
[self.superview insertSubview:_historyView belowSubview:self];
}
}
return _historyView;
}
- (id)init{
if (self = [super init]) {
[self commonInit];
}
return self;
}
- (id)initWithCoder:(NSCoder *)aDecoder{
if (self = [super initWithCoder:aDecoder]) {
[self commonInit];
}
return self;
}
- (id)initWithFrame:(CGRect)frame{
if (self = [super initWithFrame:frame]) {
[self commonInit];
}
return self;
}
- (void)commonInit{
self.popGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGesture:)];
[self addGestureRecognizer:self.popGesture];
[super setDelegate:self];
[DLPanableWebView addShadowToView:self];
}
- (void)dealloc {
if (self.historyView) {
[self.historyView removeFromSuperview];
self.historyView = nil;
}
}
- (void)layoutSubviews {
[super layoutSubviews];
self.historyView.frame = self.bounds;
}
#pragma mark === gesture===
- (void)panGesture:(UIPanGestureRecognizer *)sender{
if (![self canGoBack] || self.historyStack.count == 0) {
if (self.panDelegate && [self.panDelegate respondsToSelector:@selector(panableWebView:panPopGesture:)]) {
[self.panDelegate panableWebView:self panPopGesture:sender];
}
return;
}
CGPoint point = [sender translationInView:self];
if (sender.state == UIGestureRecognizerStateBegan) {
_panStartX = point.x;
}
else if (sender.state == UIGestureRecognizerStateChanged){
CGFloat deltaX = point.x - _panStartX;
if (deltaX > 0) {
if ([self canGoBack]) {
assert(self.historyStack.count > 0);
self.historyView.image = [self.historyStack.lastObject objectForKey:@"preview"];
self.x = deltaX;
self.historyView.x = -self.width / 2.0f + deltaX / 2.0f;
}
}
}
else if (sender.state == UIGestureRecognizerStateEnded){
CGFloat deltaX = point.x - _panStartX;
CGFloat duration = .5f;
if ([self canGoBack]) {
if (deltaX > self.width / 4.0f) {
[UIView animateWithDuration:(1.0f - deltaX / self.width) * duration animations:^{
self.x = self.width;
self.historyView.x = 0;
[self goBack];
} completion:^(BOOL finished) {
self.x = 0;
[self.historyView removeFromSuperview];
self.historyView = nil;
}];
}
else{
[UIView animateWithDuration:(deltaX/self.bounds.size.width)*duration animations:^{
CGRect rc = self.frame;
rc.origin.x = 0;
self.frame = rc;
rc.origin.x = -self.bounds.size.width/2.0f;
self.historyView.frame = rc;
} completion:^(BOOL finished) {
}];
}
}
}
}
#pragma mark ===uiwebview===
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
BOOL ret = YES;
if (self.originDelegate && [self.originDelegate respondsToSelector:@selector(webView:shouldStartLoadWithRequest:navigationType:)]) {
ret = [self.originDelegate webView:webView shouldStartLoadWithRequest:request navigationType:navigationType];
}
BOOL isFragmentJump = NO;
if (request.URL.fragment) {
NSString *nonFragmentURL = [request.URL.absoluteString stringByReplacingOccurrencesOfString:[@"#" stringByAppendingString:request.URL.fragment] withString:@""];
if (webView.request.URL.absoluteString) {
NSString *preNonFragmentURL;
if (webView.request.URL.fragment) {
preNonFragmentURL = [webView.request.URL.absoluteString stringByReplacingOccurrencesOfString:[@"#" stringByAppendingString:webView.request.URL.fragment] withString:@""];
}
else{
preNonFragmentURL = webView.request.URL.absoluteString;
}
isFragmentJump = [nonFragmentURL isEqualToString:preNonFragmentURL];
}
}
BOOL isTopLevelNavigation = [request.mainDocumentURL isEqual:request.URL];
BOOL isHTTPOrFile = [request.URL.scheme isEqualToString:@"http"] || [request.URL.scheme isEqualToString:@"https"] || [request.URL.scheme isEqualToString:@"file"];
if (ret && !isFragmentJump && isHTTPOrFile && isTopLevelNavigation) {
if ((navigationType == UIWebViewNavigationTypeLinkClicked || navigationType == UIWebViewNavigationTypeOther) && [[webView.request.URL description] length]) {
if (![[self.historyStack.lastObject objectForKey:@"url"] isEqualToString:[self.request.URL description]]) {
UIImage *curPreview = [DLPanableWebView screenshotOfView:self];
[self.historyStack addObject:@{@"preview":curPreview, @"url":[self.request.URL description]}];
}
}
}
// 点击自带返回,移除一个
if (navigationType == UIWebViewNavigationTypeBackForward) {
[self.historyStack removeLastObject];
}
NSLog(@"数组个数 ===> %zd",self.historyStack.count);
return ret;
}
- (void)webViewDidStartLoad:(UIWebView *)webView {
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
if (self.originDelegate && [self.originDelegate respondsToSelector:@selector(webViewDidStartLoad:)]) {
[self.originDelegate webViewDidStartLoad:webView];
}
if ([self.panDelegate respondsToSelector:@selector(webViewLoadState:)]) {
[self.panDelegate webViewLoadState:0];
}
}
- (void)webViewDidFinishLoad:(UIWebView *)webView {
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
if (self.originDelegate && [self.originDelegate respondsToSelector:@selector(webViewDidFinishLoad:)]) {
[self.originDelegate webViewDidFinishLoad:webView];
}
if ([self.panDelegate respondsToSelector:@selector(webViewLoadState:)]) {
[self.panDelegate webViewLoadState:1];
}
}
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
if (self.originDelegate && [self.originDelegate respondsToSelector:@selector(webView:didFailLoadWithError:)]) {
[self.originDelegate webView:webView didFailLoadWithError:error];
}
if ([self.panDelegate respondsToSelector:@selector(webViewLoadState:)]) {
[self.panDelegate webViewLoadState:2];
}
}
@end
UIWebview加载H5界面侧滑返回上一级的更多相关文章
- 移动web、webApp、混合APP、原生APP、androd H5混合开发 当无网络下,android怎么加载H5界面
PhoneGap是一个采用HTML,CSS和JavaScript的技术,创建移动跨平台移动应用程序的快速开发平台.它使开发者能够在网页中调用IOS,Android,Palm,Symbian,WP7,W ...
- iOS “请在微信客户端打开链接” UIWebview加载H5页面携带session、cookie、User-Agent信息 设置cookie、清除cookie、设置User-Agent
公司新开的一个项目..内容基本上是加载H5页面显示..当时觉得挺简单的..后来发现自己掉坑里了..一些心理历程就不说了..说这个项目主要用到的知识点吧..也是自己踩得坑. 首先说说..这个项目上的内容 ...
- 新浪微博客户端(13)-使用UIWebView加载OAuth授权界面
使用UIWebView加载OAuth授权界面 DJOAuthViewController.m #import "DJOAuthViewController.h" @interfac ...
- 浅试 Webview 一app 加载 H5小游戏
整体架构: InventionActivity:实现UI的实例化,基本的按钮Activity之间跳转 GameActivity:实现UI的实例化,Webview的基本使用 MyProgressDial ...
- 【iOS进阶】UIWebview加载搜狐视频,自动跳回客户端 问题解决
UIWebview加载搜狐视频,自动跳回搜狐客户端 问题解决 当我们用UIWebview(iOS端)加载网页视频的时候,会发现,当真机上有搜狐客户端的时候,会自动跳转到搜狐客户端进行播放,这样的体验对 ...
- Android使用WebView加载H5页面播放视频音频,退出后还在播放问题解决
Android中经常会使用到WebView来加载H5的页面,如果H5页面中有音频或者视频的播放时,还没播放完就退出界面,这个时候会发现音频或者视频还在后台播放,这就有点一脸懵逼了,下面是解决方案: 方 ...
- iOS Cordova 加载远程界面
老大说,我们的项目要hybrid,要实现1.html能调用native:2.本地html调用本地html界面:3.能加载远程界面..... 因为我的项目是已有的(以下简称 项目),所以是要在已有的项目 ...
- 【Android】首次进入应用时加载引导界面
参考文章: [1]http://blog.csdn.net/wsscy2004/article/details/7611529 [2]http://www.androidlearner.net/and ...
- 【iOS系列】-UIWebView加载网页禁止左右滑动
[iOS系列]-UIWebView加载网页禁止左右滑动 问题: 做项目时候,用UIWebView加载网页的时候,要求是和微信网页中打开的网页的效果一样,也即是只能上下滑动,不能左右滑动,也不能缩放. ...
随机推荐
- RAID 1-6
RAID 0 RAID 0亦称为带区集.它将两个以上的磁盘串联起来,成为一个大容量的磁盘.在存放数据时,分段后分散存储在这些磁盘中,因为读写时都可以并行处理,所以在所有的级别中,RAID 0的速度是最 ...
- 基于ARP的网络扫描工具netdiscover
基于ARP的网络扫描工具netdiscover ARP是将IP地址转化物理地址的网络协议.通过该协议,可以判断某个IP地址是否被使用,从而发现网络中存活的主机.Kali Linux提供的netdi ...
- 平衡树之非旋Treap
平衡树(二叉树) 线段树不支持插入or删除一个数于是平衡树产生了 常见平衡树:treap(比sbt慢,好写吧),SBT(快,比较好写,有些功能不支持),splay(特别慢,复杂度当做根号n来用,功能强 ...
- Using Blocks in iOS 4: The Basics
iOS 4 introduces one new feature that will fundamentally change the way you program in general: bloc ...
- 谈谈ssrf
一.ssrf,全称:Server-Side-Request-Forgery服务端请求伪造 二.我们正常发出的请求都是经过我们的浏览器,由我们自己的电脑发出的:而存在ssrf的目标网站,我们输入某个网址 ...
- sublimetext3打造pythonIDE
虽然pycharm是非常好用的pythonIDE,用来开发项目很方便,但是修改调整单个或几个小程序就显得很笨重,这时候我们可以选择使用sublime. 一般来说要开发项目我都用pycharm,开发简单 ...
- Jboss7类载入器
1. 类载入器理论知识介绍 类载入器基于Jboss Module,代替了层次类载入环境,避免了当类存在多个版本号时,导致类载入错误. 类载入是基于模块的.必须显示的定义模块依赖.部署也是模块化的,假设 ...
- Zookeeper demo增删改查
Zookeeper 的增删改查demo代码 public class SimpleZkClient { private static final String connectString = &quo ...
- 将App发布到WasLiberty的较稳妥方法
1.将应用解压放到一个目录 具体步骤: 1.1 建立目录,假设应用包为app.war且和新建目录sp在同一目录下 #mkdir sp 1.2 将app.war 改名为app.zip,这是为了解压#mv ...
- 搭建rocketMq环境
大体流程按照文章https://blog.csdn.net/wangmx1993328/article/details/81536168逐步搭建,下面列出踩过的一些坑 1,自己的阿里云服务器端口没开放 ...