0
votes

I am working on a magazine viewer and I have to use UIWebView for pages because of html5 interactive contents. First I tried uiwebviews in a UIScrollView but scrollview was too slow on sliding pages. So now I am trying to write my own scrollview-like code. I have a MainView.xib, a view controller (Viewer) and extended UIWindow class (TouchCapturingWindow) that I take from here : http://wyldco.com/blog/2010/11/how-to-capture-touches-over-a-uiwebview/

when I try to slide pages fast, there is no problem but when I touch and slowly slide by not pulling my finger, "Viewer" view controller stops receiving touch events and so pages stop moving. I am logging TouchCapturingWindow, it still sending events. I searched many information and tutorials but I couldn't make it work. How can I make it continuously receive touch events?

I uploaded a simple Xcode project that contains only this part of my project. You can download here : http://testdergi.mysys.com/touchEvents.zip When you run project, you should first download pages (180Kb) by tapping "Download Pages" button, then tap the "Open Viewer" button.

You can also look over the code below :

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

1 Answers

0
votes

I am answering my own question. I found something after a hard work. I changed "(void)sendEvent:(UIEvent *)event" method like the code below. I saw that use of "[super sendEvent:event];" after UITouchPhaseMoved phase is problematic.

- (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)

}

But the new problem is; if I add a video in a web page, and try to forward the video with its slider, page is moving. I have to find a way to detect if user taps on a video.