【问题标题】:UIScrollView with UIWebViewsUIScrollView 与 UIWebViews
【发布时间】:2010-03-08 13:22:35
【问题描述】:

stackoverflow 上似乎有很多关于这个主题的问题,但没有一个涉及到 3.0 中所做的更新。经过几个小时的摸索,我终于发现,完全支持嵌套滚动视图(在我的情况下,滚动视图中的 web 视图),但是http://developer.apple.com/iphone/library/documentation/WindowsViews/Conceptual/UIScrollView_pg/Introduction/Introduction.html 给出的示例非常基本。

我有一个启用分页的主滚动视图,网络视图布局为子视图,这样我可以左右分页更改不同的网络视图,还可以在子视图内上下滚动。

本质上这似乎工作正常,但是我不知道一旦用户已经开始滚动网络视图,如何停止父滚动视图向左或向右分页。本质上,我想将滚动锁定到它开始的任何方向。有趣的是,如果我先开始分页,这很好用,但如果我先开始向上或向下滚动,它也会同时允许页面(在相同的开始-移动-结束循环期间)。

例如,股票应用会正确锁定滚动。

【问题讨论】:

  • 此时我也尝试子类化最顶层的 UIScollView 以返回 no in - (BOOL)touchesShouldCancelInContentView:(UIView *)view 如果计时器(应该与内部滚动视图同时到期)用于确定是否需要转发触摸的计时器)。问题是,这并不总是在正确的时间触发,因为触摸事件似乎锁定了主线程。
  • 我已经设法通过让我提到的计时器在另一个线程上运行来获得方向锁定。现在,如果我能弄清楚如何修改分页/滚动的阈值(默认情况下似乎过于偏爱分页),我会是黄金。

标签: cocoa-touch uiwebview uiscrollview nested


【解决方案1】:

编辑:这在 iOS 4.0 上完全被破坏了。一旦我找出问题所在,我会更新此内容。

由于 UIWebView 不能很好地配合 3.0 中引入的自动嵌套滚动,并且不再支持向 UIScrollView 发送 touchesBegin/Moved/Ended,这就是我想出的。

我在所有其他视图之上添加了一个透明的 UIView 子类,并让它捕捉到所有的触摸。 当触摸开始时,我将其转发到当前活动的 UIWebView 并启动一个短计时器(或者更确切地说是另一个使用 usleep() 休眠的线程 - 根据我的经验,当大量触摸事件发生时,主线程可能会被锁定传入和计时器可以关闭)。

在 touchesMoved 中,我检查我启动的计时器是否未过期 - 如果尚未过期,并且 fabs(location.x - lastLocation.x) > fabs(location.y - lastLocation.y) 那么它看起来像用户正在尝试分页(这可以通过乘数进行调整,但现在这似乎只是最佳点)。 如果确定用户正在尝试分页,我会发送 web 视图 touchesCancelled 并开始相应地调整滚动视图的 contentOffset.x。

在 touchesEnded 中,如果确定用户正在分页,我会应用一些牛顿物理学来查看触摸以及滚动的一些动态延续是否足以跨越到下一页(超过下一页的一半可见)。如果是这样,我会根据滚动速度为滚动设置动画以继续。

警告:由于尝试了十亿种不同的东西,这段代码很糟糕。我还没有机会清理它。希望这对某人有所帮助。

-(void)timer {
    usleep(250000);
    expired = YES;
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    paging = NO;
    expired = NO;
    determined = NO;


    if(navManager == nil) {
        navManager = [[[[UIApplication sharedApplication] delegate] viewController] navManager];
    }

    UITouch *touch = [touches anyObject];
    CGPoint location = [touch locationInView:self];

    touchStartX = location.x;
    touchStarted = touch.timestamp;

    [NSThread detachNewThreadSelector:@selector(timer) toTarget:self withObject:nil];

    [[navManager.currentNavItem.webView hitTest:CGPointZero withEvent:event] touchesBegan:touches withEvent:event];
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
    if(!paging) {
        [[navManager.currentNavItem.webView hitTest:CGPointZero withEvent:event] touchesCancelled:touches withEvent:event];
    }

}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    if(!paging) {
        [[navManager.currentNavItem.webView hitTest:CGPointZero withEvent:event] touchesEnded:touches withEvent:event];
    }
    else {
        UITouch *touch = [touches anyObject];
        CGPoint location = [touch locationInView:self];
        NSTimeInterval touchLasted = touch.timestamp - touchStarted;
        CGFloat touchLen = location.x - touchStartX;
        float dir = touchLen/fabs(touchLen);
        float touchSpeed = touchLen/touchLasted;
        float deAccelRate = -3000.0;
        float timeToDeAccel = (-touchSpeed) / deAccelRate;
        float averageVelocity = touchSpeed / 2.0;
        float couldTravel = averageVelocity*timeToDeAccel;

        if(couldTravel > navManager.scrollView.frame.size.width/2.0) {
            couldTravel = navManager.scrollView.frame.size.width/2.0;
        }
        couldTravel = dir*couldTravel;

        NSLog(@"could travel: %f, touchSpeed: %f, timeToDeAccel = %f, averageVelocity: %f", couldTravel, touchSpeed, timeToDeAccel, averageVelocity);

        int page = round((navManager.scrollView.contentOffset.x - couldTravel) / navManager.scrollView.frame.size.width);
        if(page < 0) 
            page = 0;
        else if(page > round(navManager.scrollView.contentSize.width / navManager.scrollView.frame.size.width) - 1) 
            page = round(navManager.scrollView.contentSize.width / navManager.scrollView.frame.size.width) - 1;

        CGPoint newOffset = CGPointMake(page*navManager.scrollView.frame.size.width, navManager.scrollView.contentOffset.y);
        float needToMove = fabs(newOffset.x - navManager.scrollView.contentOffset.x);
        float timeToAnimate = needToMove / averageVelocity;

        [UIView beginAnimations:nil context:NULL];
        [UIView setAnimationDelegate:nil];
        [UIView setAnimationDuration:timeToAnimate];
        [UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
        navManager.scrollView.contentOffset = newOffset;
        [UIView commitAnimations];
    }
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    UITouch *touch = [touches anyObject];
    CGPoint location = [touch locationInView:self];
    CGPoint lastLocation = [touch previousLocationInView:self];

    if(!determined && !expired) {

        if(fabs(location.x - lastLocation.x) > fabs(location.y - lastLocation.y)) {
            NSLog(@"PAGE!!");
            paging = YES;
            [[navManager.currentNavItem.webView hitTest:CGPointZero withEvent:event] touchesCancelled:touches withEvent:event];
        }
        else
            [navManager.scrollView touchesCancelled:touches withEvent:event];

        determined = YES;
    }

    if(!paging) 
        [[navManager.currentNavItem.webView hitTest:CGPointZero withEvent:event] touchesMoved:touches withEvent:event];

    else {
        float xScroll = navManager.scrollView.contentOffset.x-(location.x - lastLocation.x);

        CGPoint newOffset = CGPointMake(xScroll, navManager.scrollView.contentOffset.y);
        navManager.scrollView.contentOffset = newOffset;
    }
}

还有一些东西要添加,让它感觉更原生,但这应该是一个很好的起点。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-07-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-18
    • 1970-01-01
    相关资源
    最近更新 更多