UIViewController 停止在 UIWebView 上接收触摸事件

Posted

技术标签:

【中文标题】UIViewController 停止在 UIWebView 上接收触摸事件【英文标题】:UIViewController stops receiving touch events on UIWebView 【发布时间】:2012-08-13 06:53:52 【问题描述】:

我正在开发杂志查看器,由于 html5 交互式内容,我必须将 UIWebView 用于页面。首先,我在 UIScrollView 中尝试了 uiwebviews,但滚动视图在滑动页面上太慢了。 所以现在我正在尝试编写自己的类似滚动视图的代码。我有一个 MainView.xib、一个视图控制器 (Viewer) 和扩展 UIWindow 类 (TouchCapturingWindow),我从这里获取:http://wyldco.com/blog/2010/11/how-to-capture-touches-over-a-uiwebview/

当我尝试快速滑动页面时,没有问题,但是当我触摸并通过不拉手指慢慢滑动时,“查看器”视图控制器停止接收触摸事件,因此页面停止移动。我正在记录 TouchCapturingWindow,它仍在发送事件。我搜索了许多信息和教程,但我无法使其工作。如何让它连续接收触摸事件?

我上传了一个简单的 Xcode 项目,其中仅包含我项目的这一部分。你可以在这里下载:http://testdergi.mysys.com/touchEvents.zip 运行项目时,应先点击“下载页面”按钮下载页面(180Kb),然后点击“打开查看器”按钮。

你也可以看看下面的代码:

TouchCapturingWindow.h:

@interface TouchCapturingWindow : UIWindow 
    NSMutableArray *views;

@private
    UIView *touchView;


- (void)addViewForTouchPriority:(UIView*)view;
- (void)removeViewForTouchPriority:(UIView*)view;

@end

TouchCapturingWindow.m:

@implementation TouchCapturingWindow


- (void)dealloc 



- (void)addViewForTouchPriority:(UIView*)view 
    if ( !views ) views = [[NSMutableArray alloc] init];
    [views addObject:view];


- (void)removeViewForTouchPriority:(UIView*)view 
    if ( !views ) return;
    [views removeObject:view];


- (void)sendEvent:(UIEvent *)event 

    //get a touch
    UITouch *touch = [[event allTouches] anyObject];

    //check which phase the touch is at, and process it
    if (touch.phase == UITouchPhaseBegan) 
            for ( UIView *view in views ) 
                //if ( CGRectContainsPoint([view frame], [touch locationInView:[view superview]]) ) 
                NSLog(@"TouchCapturingWindow --> TouchPhaseBegan");
                touchView = view;
                [touchView touchesBegan:[event allTouches] withEvent:event];
                break;
            
    
    else if (touch.phase == UITouchPhaseMoved) 
            NSLog(@"TouchCapturingWindow --> TouchPhaseMoved");

            if ( touchView ) 

                [touchView touchesMoved:[event allTouches] withEvent:event];
            
            else
            
                NSLog(@"touch view is nil");
            

    
    else if (touch.phase == UITouchPhaseCancelled) 
            NSLog(@"TouchCapturingWindow --> TouchPhaseCancelled");
            if ( touchView ) 
                [touchView touchesCancelled:[event allTouches] withEvent:event];
                touchView = nil;
            
    
    else if (touch.phase == UITouchPhaseEnded) 
            NSLog(@"TouchCapturingWindow --> TouchPhaseEnded");
            if ( touchView ) 
                [touchView touchesEnded:[event allTouches] withEvent:event];
                touchView = nil;
            
    

    //we need to send the message to the super for the
    //text overlay to work (holding touch to show copy/paste)
    [super sendEvent:event];


@end

Viewer.h:

@interface Viewer : UIViewController
    int currentPage;
    int totalPages;
    IBOutlet UIView *pagesView;
    int lastTchX;
    int difference;
    BOOL hasMoved;
    int touchBeganSeritX;


- (IBAction)backBtnClicked:(id)sender;
- (void)loadImages;
- (void)animationDidStop;
- (void)loadSinglePage:(int)pageNo;

@property (nonatomic, retain) IBOutlet UIView *pagesView;

@end

Viewer.m:

@interface Viewer ()

@end

@implementation Viewer

@synthesize pagesView;

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil

    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) 
        // Custom initialization
    
    return self;


- (void)viewDidLoad

    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.


- (IBAction)backBtnClicked:(id)sender

    [self.navigationController popViewControllerAnimated:YES];


- (void)loadImages

    for(UIView *subView in pagesView.subviews)
    
        [subView removeFromSuperview];
    

    currentPage = 1;
    totalPages = 12;
    for(int count = 1; count <= 12; count++)
    
        [self loadSinglePage:count];
    



- (void)loadSinglePage:(int)pageNo

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory , NSUserDomainMask, YES);
    NSString *cachesDir = [paths objectAtIndex:0];
    NSString *pagesDir = [NSString stringWithFormat:@"%@/pages", cachesDir];

    int pageX = (pageNo - 1) * 768;

    UIWebView *aPageWebView = [[UIWebView alloc] init];
    [aPageWebView setFrame:CGRectMake(pageX, 0, 768, 1024)];
    aPageWebView.backgroundColor = [UIColor clearColor];
    aPageWebView.opaque = YES;
    [aPageWebView setClearsContextBeforeDrawing:YES];
    aPageWebView.clipsToBounds = NO;
    [aPageWebView setScalesPageToFit:YES];

    NSString *hamData = [NSString stringWithFormat:@"<!DOCTYPE html><html><head><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"user-scalable=yes, width=1024, height=1365, maximum-scale=1.0\"><style type=\"text/css\">body margin:0; padding:0;</style></head><body bgcolor=\"#508CCF\"><div id=\"touchable\" style=\"top:0px; left:0px; width:1024px; height:1365px; background-image:url(%@.jpg)\"></div></body></html>", [[NSNumber numberWithInt:pageNo] stringValue]];

    [aPageWebView loadHTMLString:hamData baseURL:[NSURL fileURLWithPath:pagesDir isDirectory:YES]];
    aPageWebView.scrollView.bounces = NO;
    [aPageWebView.scrollView setMaximumZoomScale:1.3333f];
    [aPageWebView.scrollView setMinimumZoomScale:1.0f];
    aPageWebView.scrollView.zoomScale = 1.0f;
    [aPageWebView setMultipleTouchEnabled:YES];
    [pagesView addSubview:aPageWebView];



- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event

    NSLog(@"touchesBegan");

    UITouch *myTouch = [[event allTouches] anyObject];
    int curTchX = [myTouch locationInView:self.view].x;

    lastTchX = curTchX;
    hasMoved = NO;

    touchBeganSeritX = pagesView.frame.origin.x;


- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event

    NSLog(@"Viewer : .....moved");

    hasMoved = YES;
    UITouch *myTouch = [[event allTouches] anyObject];
    int curTchX = [myTouch locationInView:self.view].x;
    difference = curTchX - lastTchX;

    int newX = (pagesView.frame.origin.x + difference);
    if(newX <= 0)
    
        [pagesView setFrame:CGRectMake((pagesView.frame.origin.x + difference), 0, pagesView.frame.size.width, 1024)];
    
    lastTchX = curTchX;


- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event

    NSLog(@"touchesEnded");
    if(hasMoved == YES)
    
        hasMoved = NO;

        int curSeritX = pagesView.frame.origin.x;
        curSeritX = curSeritX / (-1);

        int newX = 0;

        if(difference < 0) //Sağa geçilecek
        
            if((currentPage + 1) <= totalPages)
            
                currentPage++;
            
        
        else //Sola geçilecek
        
            if((currentPage - 1) >= 1)
            
                currentPage--;
            
        

        newX = (currentPage - 1)*768*(-1);

        [UIView animateWithDuration:0.2f
                              delay:0.0f
                            options:UIViewAnimationOptionCurveEaseOut
                         animations:^
                             // Do your animations here.
                             [pagesView setFrame:CGRectMake(newX, 0, pagesView.frame.size.width, pagesView.frame.size.height)];
                         
                         completion:^(BOOL finished)
                             if (finished) 
                                 // Do your method here after your animation.
                             
                         ];
    


- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event

    NSLog(@"touchesCancelled");



- (void)viewDidUnload

    [super viewDidUnload];


- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation

    return YES;


@end

【问题讨论】:

【参考方案1】:

我正在回答我自己的问题。经过一番努力,我找到了一些东西。我更改了“(void)sendEvent:(UIEvent *)event”方法,如下面的代码。我看到使用“[super sendEvent:event];” UITouchPhaseMoved 阶段后有问题。

- (void)sendEvent:(UIEvent *)event 
    //we need to send the message to the super for the
    //text overlay to work (holding touch to show copy/paste)
    //[super sendEvent:event];

    //get a touch
    UITouch *touch = [[event allTouches] anyObject];

    //check which phase the touch is at, and process it
    if (touch.phase == UITouchPhaseBegan) 
            for ( UIView *view in views ) 
                //if ( CGRectContainsPoint([view frame], [touch locationInView:[view superview]]) ) 
                NSLog(@"TouchCapturingWindow --> TouchPhaseBegan");
                touchView = view;
                [touchView touchesBegan:[event allTouches] withEvent:event];


                break;
            
        [super sendEvent:event];
    
    else if (touch.phase == UITouchPhaseMoved) 
            NSLog(@"TouchCapturingWindow --> TouchPhaseMoved");

            if ( touchView ) 

                [touchView touchesMoved:[event allTouches] withEvent:event];

                int curTchX = [touch locationInView:self].x;
                NSLog(@"curTchX : %d", curTchX);
            
            else
            
                NSLog(@"touch view is nil");
            

    
    else if (touch.phase == UITouchPhaseCancelled) 
            NSLog(@"TouchCapturingWindow --> TouchPhaseCancelled");
            if ( touchView ) 
                [touchView touchesCancelled:[event allTouches] withEvent:event];
                touchView = nil;
            
        [super sendEvent:event];
    
    else if (touch.phase == UITouchPhaseEnded) 
            NSLog(@"TouchCapturingWindow --> TouchPhaseEnded");
            if ( touchView ) 
                [touchView touchesEnded:[event allTouches] withEvent:event];
                touchView = nil;
            
        [super sendEvent:event];
    

    //we need to send the message to the super for the
    //text overlay to work (holding touch to show copy/paste)


但新的问题是;如果我在网页中添加视频,并尝试使用滑块转发视频,页面正在移动。我必须找到一种方法来检测用户是否点击了视频。

【讨论】:

以上是关于UIViewController 停止在 UIWebView 上接收触摸事件的主要内容,如果未能解决你的问题,请参考以下文章

UiWebView 全屏显示

如何停止将 UIViewController 推到自身之上?

对于UINavigationController和UIViewController,在swift 4中禁用屏幕方向

UIViewController 内容未显示在情节提要上

使 UIViewController 中的 NSTimer 无效以避免保留周期的最佳时间

当我的 UIViewController 被弹出时调用的方法?