Пейджинг UIScrollView включен с вложением содержимого работает странно

Я создал UIScrollView с вставками содержимого.

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

В первый раз scrollView.contentOffset.x было -160.0

Но странная проблема заключается в том, что когда я нажимаю scrollView (Yellow Area), значение смещения содержимого x возвращается к 0 и отображается следующим образом.

enter image description here

Я пробовал несколько раз, но нажатие на Scroll View сбрасывает смещение содержимого на 0.

Как я могу предотвратить это?

Ответ 1

UIScrollView paging работает, прокручивая страницы с той же шириной scrollView (на ваших страницах размером 480). Это означает, что у вас есть одна единственная страница (вы все равно сможете прокручивать влево и вправо из-за 160 встроенных вложений).

Один из способов сделать эту работу:

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)];

Это будет правильно рисоваться и прокручиваться, однако стороны экрана не будут интерактивными (80 пикселей с каждой стороны, так как управление начинается с frame.origin.x = 80 и заканчивается на 80 + 160 = 240).

Второй вариант - обработать пейджинг самостоятельно, используя методы, предоставляемые 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);
}

Ответ 2

В дополнение к первому подходу alex с настройкой clipToBounds на NO, мне нужно отреагировать на прокрутку вне границ просмотра прокрутки. Поэтому я создал класс ScrollForwarderView, который является подклассом 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;
}

Затем поместите UIView с пользовательским классом ScrollForwarderView над просмотром прокрутки, привяжите свойство scrollView к моему представлению прокрутки, и он прекрасно перенаправил пользовательские события на прокрутку.