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

标签 ios objective-c cocoa-touch uiwebview uiscrollview

我有一个 ScrollView ,或者实际上是一个 UIWebView,它最初位于距其父 View 顶部 320 像素的位置。

当用户开始滚动时,我希望整个 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 在接受的答案中建议的那样使用插图非常有效。代码也变得更简单了。您可以在这里查看解决方案: http://gist.github.com/melke/8684172

最佳答案

我认为你想做的更简单,而不是移动 ScrollView ,是设置一个内容插入

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

请注意,您需要将部署目标设置为 iOS5+ 才能像这样抓取 ScrollView ,而不是像您那样循环遍历 subview 。

总的来说,您的 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];
}

此外,根据您在原始帖子中的一条评论,您似乎也在移动另一个 View 以及 ScrollView 。 在这种情况下,您需要跟踪 ScrollView 委托(delegate)的滚动,并相应地移动其他 View 。根据其他 View 的内容(例如,如果它只是一个 imageView 横幅类型的东西),我个人认为调整/裁剪其他 View 比将它移出屏幕更优雅;但我想这必须是另一个问题。

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

关于ios - 滚动时移动整个 UIScrollView。在顶部时,开始正常滚动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21416434/

相关文章:

c# - c# 中的 Apple 推送通知服务代码服务器端

ios - 验证来自多个应用程序的 iOS 自动续订订阅

ios - OpenGL ES 2.0 立方体贴图不显示纹理

iphone - 使用快速枚举的监听器模式问题

objective-c - UIAlert View Objective C - 打开应用商店链接

iphone - UITextField -clearButtonMode 仅在代码中,不在 IB 中?

ios - SpriteKit : How to make physics body of a sprite to copy an actual image?

ios - UITableView 中的数据错误

iphone - UIView 动画完成后执行代码?

objective-c - ConnectionKit框架: Adding it to a project