Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UIScrollView paging enabled with content inset is working strange

I created the UIScrollView with content insets.

scrollView.frame = CGRectMake(-80, 180, 480, 190)
self.scrollView.contentInset = UIEdgeInsetsMake(0, 160, 0, 160);
self.scrollView.pagingEnabled = YES;
[self.scrollView setContentSize:CGSizeMake(480, 190)];

// Add three Views
[self.scrollView addSubview:view1];
[self.scrollView addSubview:view2];
[self.scrollView addSubview:view3];

[view1 setFrame:CGRectMake(0, 0, 160, 190)];
[view2 setFrame:CGRectMake(160, 0, 160, 190)];
[view3 setFrame:CGRectMake(320, 0, 160, 190)];

d

At first time, scrollView.contentOffset.x was -160.0

But the weird problem is when I tap on scrollView(Yellow Area), content offset x value is resetting to 0 and shown like this.

enter image description here

I tried several times, but tapping on Scroll View resets the content offset to 0.

How can I prevent this?

like image 428
Fury Avatar asked Sep 28 '13 13:09

Fury


2 Answers

UIScrollView paging works by scrolling pages with the same width of the scrollView (in your case pages of 480 width). This means that you have 1 single page (you'd still be able to scroll left and right due to the 160 content inset).

One way to make this work would be:

self.scrollView.frame = CGRectMake(80, 180, 160, 190);
self.scrollView.clipsToBounds = NO;
self.scrollView.contentInset = UIEdgeInsetsZero;
self.scrollView.pagingEnabled = YES;
[self.scrollView setContentSize:CGSizeMake(480, 190)];

This will draw and scroll correctly, however, the sides of the screen will not be interactive (80 pixels on each side, since the control starts at frame.origin.x=80 and ends at 80+160=240).

Second option would be to handle paging yourself, by using methods provided by UIScrollViewDelegate.

- (void)viewDidLoad
{
    [super viewDidLoad];
    // pageIndex must be declared as a class member - this is used to prevent skipping pages during scroll
    pageIndex = 0;
    self.scrollView.frame = CGRectMake(0, 180, 320, 190);
    self.scrollView.contentInset = UIEdgeInsetsMake(0, 80, 0, 80);
    self.scrollView.pagingEnabled = NO;
    self.scrollView.clipsToBounds = YES;
    [self.scrollView setContentSize:CGSizeMake(480, 190)];
    self.scrollView.delegate = self;
}

- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset{
    int pageWidth = 160;
    int pageX = pageIndex*pageWidth-scrollView.contentInset.left;
    if (targetContentOffset->x<pageX) {
        if (pageIndex>0) {
            pageIndex--;
        }
    }
    else if(targetContentOffset->x>pageX){
        if (pageIndex<3) {
            pageIndex++;
        }
    }
    targetContentOffset->x = pageIndex*pageWidth-scrollView.contentInset.left;
    NSLog(@"%d %d", pageIndex, (int)targetContentOffset->x);
}
like image 78
alex-i Avatar answered Oct 06 '22 01:10

alex-i


In addition to alex's first approach with setting clipsToBounds to NO, I need to react to the scroll outside of the scroll view bounds. So I created ScrollForwarderView class which is subclass of UIView.

ScrollForwarderView.h

#import <UIKit/UIKit.h>

@interface ScrollForwarderView : UIView
@property (nonatomic, weak) UIScrollView *scrollView;
@end

ScrollForwarderView.m

...
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    if ([self pointInside:point withEvent:event]) {
        return _scrollView;
    }
    return nil;
}

Then place UIView with custom class ScrollForwarderView above the scroll view, link scrollView property to my scroll view and it nicely forwarded the user events to scrollview.

like image 32
Fury Avatar answered Oct 06 '22 01:10

Fury