关于 ios:Bounds 在 UIScrollView 上自动更改内容插入

Bounds automatically changes on UIScrollView with content insets

我使用 UIScrollView 作为我的分页滚动视图,pagesScrollView。在其中,我放置了专门用于缩放的单个 UIScrollView。在其中的每一个中,我都有一个视图,它是应该可以缩放的页面项目。所有这些都在带有半透明导航栏的 UINavigationController 中。

我的 pagesScrollViewcontentInset.top = 64bounds.origin.y = -64 (这对我来说似乎很奇怪,但这是系统自动为我设置的),这很好用。我的屏幕看起来很棒!

但是,在我滚动 pagesScrollView 一点点之后,只要调用 scrollViewWillEndDraggingpagesScrollView 就会开始从 bounds.origin.y = -64bounds.origin.y = 0 的动画变化,这会导致我的页面项目被遮挡通过导航栏。

左边是加载时的样子,右边是我拖动几个像素然后放开后的样子,它在导航栏下向上滑动(因为 bounds.origin.y 去了到 0).

enter

这里是下载一个基本项目的链接,它只有几行代码来演示这个问题。只需单击滚动视图,您就会看到它随着边界的变化而向上移动。 http://inadaydevelopment.com/stackoverflow/WeirdScrollViews.zip

如何在滚动视图上启用分页,而不会在滚动和移动导航栏下的所有内容时出现边界问题?

可以将导航栏设置为不透明并避免问题,但理想的情况是具有标准的 iOS7 行为,以便在内容视图缩放后,然后允许内容位于导航栏下方,并应通过半透明正常。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
- (void) viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];

    NSArray *colors = @[
                        [UIColor blueColor],
                        [UIColor orangeColor],
                        [UIColor magentaColor],
                        ];

    NSArray *zoomerColors = @[
                        [UIColor greenColor],
                        [UIColor yellowColor],
                        [UIColor purpleColor],
                        ];


    self.scroller.pagingEnabled = YES;

    [self.scroller setContentSize:CGSizeMake(self.scroller.frame.size.width*colors.count, self.scroller.frame.size.height)];

    CGRect subviewFrame = CGRectMake(0, 0, 160, 240);
    for (int index=0; index < colors.count; index++) {
        UIColor *color = [colors objectAtIndex:index];
        UIColor *zoomerColor = [zoomerColors objectAtIndex:index];

        UIView *subview = [[UIView alloc] initWithFrame:subviewFrame];
        subview.backgroundColor = color;

        CGRect zoomerFrame = CGRectMake(index*self.scroller.frame.size.width, 0, self.scroller.frame.size.width, self.scroller.frame.size.height);

        UIScrollView *zoomer = [[UIScrollView alloc] initWithFrame:zoomerFrame];
        [zoomer addSubview:subview];
        zoomer.backgroundColor = zoomerColor;

        [self.scroller addSubview:zoomer];

    }
}


只需关闭调整滚动视图插图

enter

1
2
3
4
5
6
7
8
9
10
@implementation CSScrollView

- (void)setContentOffset:(CGPoint)contentOffset
{
    NSLog(@"%0.0f %@", contentOffset.y, [NSThread callStackSymbols]);
    NSLog(@"[%@]", self.layer.animationKeys);
    [super setContentOffset:contentOffset];
}

@end

(并更改了故事板中的视图类)

当你松开手指时,一个名为 UIScrollView _smoothScrollDisplayLink: 的方法开始动画滚动视图到它的最终位置。根据第二个日志,没有 CAAnimation 涉及,滚动视图使用自己的显示链接进行自己的转换。该自定义代码似乎犯了从 y = whatevery = 0 的动画错误,没有考虑到内容偏移。

作为概念验证黑客,我将代码更改为:

1
2
3
4
5
6
7
8
9
@implementation CSScrollView

- (void)setContentOffset:(CGPoint)contentOffset
{
    contentOffset.y = -64.0f;
    [super setContentOffset:contentOffset];
}

@end

不出所料,问题就消失了。

您可能不想对 -64.0f 进行硬编码,但我得出的结论是:

  • 这是一个 iOS 错误;
  • 通过使用 - setContentOffset: 的适当自定义实现的 UIScrollView 子类拒绝无意义的值来解决此问题。

一种合理的通用方法可能是检查 self.panGestureRecognizerstate 和其他滚动,而无需依赖任何未记录的 API 或复杂的委托捕获事件。然后,如有必要,从当前值中提取正确的 contentOffset.y 而不是对其进行硬编码。


It turns out the issue (described below) only appears once PAGING IS ENABLED on the UIScrollView! Wtf? :)

正如你所说,如果启用滚动分页,UIScrollView 将在拖动或任何移动后停止在分页边缘,这是框架Promise的。 Bounds.origin.y 设置为零意味着第一页边缘与滚动视图框架边缘匹配,因为那里有 64 个 contentInsets。所以这不是错误,就是这样。而且由于您的栏是半透明的,请记住滚动视图的框架边缘在哪里,它在栏下方。总而言之,我认为这不是错误,而是滚动分页的效果。


我已经检查了您在 viewController.m 文件中使用以下代码的示例

1
2
3
4
5
6
-(void)viewDidLoad
{
    if ([[UIDevice currentDevice] systemVersion].floatValue>=7.0) {
        self.edgesForExtendedLayout = UIRectEdgeNone;
    }
}

一切正常……


My pagesScrollView has contentInset.top = 64 and bounds.origin.y = -64 (that seems weird to me, but that's what the system is setting automatically for me), and this works just fine. My screen looks great!

这是因为 iOS 7 在所有滚动视图上将 contentInset.top 设置为 64。
只需将这行代码添加到您的视图控制器中,一切都会按预期工作:

1
2
-(UIRectEdge)edgesForExtendedLayout {
return UIRectEdgeNone;

}

我检查了你的示例项目。