滚动时移动整个UIScrollView。在顶部时,开始正常滚动

时间:2014-01-28 20:44:10

标签: ios objective-c cocoa-touch uiwebview uiscrollview

我有一个scrollview,或者实际上是一个UIWebView,它最初位于距其父视图顶部320px处。

当用户开始滚动时,我希望整个UIWebView向上跟随移动直到它到达顶部,然后webview应该开始正常滚动。我希望这发生在同一个手指运动中。 (也就是说,用户不需要抬起手指)。

我已经在UIWebView上使用UIPanGestureRecognizer实现了这一点(参见下面的代码)。手势处理程序移动UIWebView并不断将scrollview的contentOffset重置为0.它可以工作,但性能很差,特别是如果webview包含繁重的页面。我想这是webview的滚动和重置,使渲染变得沉重。我的解决方案闻起来很糟糕,我认为必须有更好的方法吗?

您是否知道有任何更好的解决方案可以实现我的目标?

@interface ViewController ()
@property (strong, nonatomic) IBOutlet UIWebView *webView;
@property (nonatomic, strong) UIPanGestureRecognizer *panGestureRecognizer;
@property(nonatomic, strong) UIScrollView *webViewScrollView;
@property (strong, nonatomic) IBOutlet NSLayoutConstraint *webViewTopMarginConstraint;
@end

@implementation ViewController {
    BOOL gestureEnabled;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    gestureEnabled = YES;

    // Initially put the webview 320 px down on the topview
    self.webView.translatesAutoresizingMaskIntoConstraints = NO;
    self.webViewTopMarginConstraint.constant = 320.0;

    // SET UP GESTURE RECOGNIZER
    _panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanGesturesForWebview:)];
    _panGestureRecognizer.minimumNumberOfTouches = 1;
    _panGestureRecognizer.maximumNumberOfTouches = 1;
    _panGestureRecognizer.delegate = self;
    [self.webView addGestureRecognizer:_panGestureRecognizer];

    // Get hold of the webviews scrollview
    for (UIView* subView in self.webView.subviews) {
        if ([subView isKindOfClass:[UIScrollView class]]) {
            _webViewScrollView = (UIScrollView *)subView;
        }
    }

    // Load a web page in the webview
    NSURLRequest *requestObj = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.macrumors.com"]];
    [self.webView loadRequest:requestObj];
}

- (void)handlePanGesturesForWebview:(UIPanGestureRecognizer *)gesture {

    if (gesture.state == UIGestureRecognizerStateChanged) {
        CGFloat transY = [gesture translationInView:self.view].y; //transY will be negative by the number of pixels panned when panning upwards
        if (gestureEnabled) {
            // Move the whole webview according to gesture movement upwards
            // todo Handle scrolling in the opposite direction
            self.webViewTopMarginConstraint.constant = 320 + transY;
            if (self.webViewTopMarginConstraint.constant <= 0.0) {
                // The webview is at the top, disable the gesture recognizer
                gestureEnabled = NO;
                self.webViewTopMarginConstraint.constant = 0.0;
                self.panGestureRecognizer.delegate = nil;
            }
            // "Rewind" the web scrolling
            CGPoint offset = CGPointMake(0.0, 0.0);
            [self.webViewScrollView setContentOffset:offset animated:NO];
        }
    }
}

#pragma mark UIGestureRecognizerDelegate impl
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
    return YES;
}
@end

编辑:使用@JPHribovsek中的insets在接受的答案中建议完美。代码也变得更简单了。您可以在此处查看解决方案: http://gist.github.com/melke/8684172

1 个答案:

答案 0 :(得分:1)

我认为在不移动滚动视图的情况下,您想要更简单地做的是设置内容插入

CGFloat top = 320.0;     
self.webView.scrollView.contentInset = UIEdgeInsetsMake(top, 0.0, 0.0, 0.0);

请注意,您需要将部署目标设置为iOS5 +才能像这样获取滚动视图,而不是像您一样循环浏览子视图。

总体而言,您的viewDidLoad方法会更简单,并且不需要手势识别器:

- (void)viewDidLoad
{
    [super viewDidLoad];

    CGFloat top = 320.0;     
    self.webView.scrollView.contentInset = UIEdgeInsetsMake(top, 0.0, 0.0, 0.0);
    self.webview.scrollView.delegate = self;
    // Load a web page in the webview
    NSURLRequest *requestObj = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.macrumors.com"]];
    [self.webView loadRequest:requestObj];
}

此外,根据您原始帖子中的一条评论,您似乎还在移动另一个视图以及滚动视图。 在这种情况下,您将需要跟踪滚动视图滚动委托,并相应地移动其他视图。根据其他视图的内容(例如,如果它只是一个imageView横幅类型的东西),我个人会发现调整大小/裁剪其他视图而不是将其移出屏幕更为优雅;但这应该是我猜的另一个问题。

- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
    CGFloat offsetY = scrollView.contentOffset.y;
    //here whatever code you use to set that other view frame position
}