UIScrollView的内容插入会自动更改边界

8
我正在使用UIScrollView作为我的分页滚动视图,pagesScrollView。其中,我放置了专门用于缩放的单独的UIScrollViews。每个缩放控件中都有一个应该可缩放的页面项。所有这些都在具有半透明导航栏的UINavigationController中。
我的pagesScrollViewcontentInset.top = 64bounds.origin.y = -64(这对我来说似乎很奇怪,但这是系统自动为我设置的),这很好地工作了。我的屏幕看起来很棒!
但是,当我稍微滚动一下pagesScrollView之后,甚至只要调用scrollViewWillEndDraggingpagesScrollView就会开始从bounds.origin.y = -64bounds.origin.y = 0进行动画效果,这会导致我的页面项目被导航栏遮挡。
左侧是加载时的样子,右侧是我拖动了几个像素后松开时的样子,它会向上滑动到导航栏下面(因为bounds.origin.y变成了0)。
问题是我没有任何修改bounds的代码,也没有在各种滚动委托方法中添加任何代码。我添加了一堆滚动委托方法,并只添加了NSLog()以便我可以弄清楚何时/何处发生更改,但没在我的代码中发现更改。
所以,我不知道我能向您展示哪些代码来帮助您帮助我。
编辑:我从头开始构建了一个新项目,以消除所有其他变量。我将裸的UIViewController放入UINavigationController中。我在View中放置了一个UIScrollView,大小与视图相同。以下是整个项目的所有代码。
结果发现当UIScrollView上启用PAGING时才会出现下述问题!它到底怎么回事?:)
这里有一个链接可下载一个具有少量代码的基本项目,该项目演示了问题。只需点击滚动视图,您就会看到它因bounds更改而向上移动。http://inadaydevelopment.com/stackoverflow/WeirdScrollViews.zip 如何在我的滚动视图上启用分页,而不会在滚动期间使bounds出现问题并将所有内容移动到导航栏下方?
可以将导航栏设置为不透明状态,这样就避免了问题,但理想情况下是要具有标准的iOS7行为,即在内容视图缩放后,然后允许内容处于导航栏下面,并应正常显示透明度。
- (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];

    }
}

如果您在使用边界时,x和y点为0,0,则需要使用frame。 - nitin kachhadiya
放置scrollViewWillEndDragging的代码或放置单个UIScrollViews的代码 - iPatel
@nitinkachhadiya,我根本没有改变边界,而且边界从-64开始...这看起来对我来说是错误的,但这是系统自己设置的。 - Kenny Wyland
@iPatel,我已经添加了你要求的代码,但是正如我所说,它是空的。在我添加它之前,我的类中甚至没有这个代码方法,直到我添加它才能放置一个NSLog()。 - Kenny Wyland
5个回答

16

只需关闭“调整滚动视图插图”选项

在此输入图片描述


11

这是一个 iOS 的 bug。我创建了下面这个 UIScrollView 的子类来记录 y 随时间发生的变化以及推动它的是谁:

@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 = whatever动画到y = 0,未考虑内容偏移量。

为了证明概念性黑客,我更改了代码:

@implementation CSScrollView

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

@end

不出所料,问题得到了解决。

你可能不想硬编码-64.0f,但我会得出以下结论:

  • 这是一个iOS的bug;
  • 通过拒绝不合理的值来解决它,可以使用UIScrollView的子类,并使用适当的自定义实现-setContentOffset:

一个明智的通用方法可能是检查self.panGestureRecognizerstate——这将允许您区分用户负责的滚动和其他滚动,而不依赖于任何未记录的API或复杂的委托事件捕获。然后,如果必要,从当前值中获取正确的contentOffset.y而不是硬编码它。


太棒了!虽然我怀疑这可能是iOS 8中的一个错误,但一直找不出问题。使用您的解决方案后,完美地解决了问题。谢谢! - Johanneke

0

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

-(void)viewDidLoad
{
    if ([[UIDevice currentDevice] systemVersion].floatValue>=7.0) {
        self.edgesForExtendedLayout = UIRectEdgeNone;
    }
}

它正常运行...


它确实预防了错误的出现,但这是因为它禁用了 iOS7 的核心 UI 功能。当 UI 扩展时,它也应该正常运行。 - Kenny Wyland

0
我的pagesScrollView的contentInset.top = 64,bounds.origin.y = -64(这对我来说很奇怪,但这是系统自动为我设置的),这很好用。我的屏幕看起来很棒! 这是因为iOS 7在所有滚动视图上将contentInset.top设置为64。 只需将此行代码添加到您的视图控制器中,一切都会按预期工作:
-(UIRectEdge)edgesForExtendedLayout {
return UIRectEdgeNone;

}

我查看了你的示例项目。


感谢您的回复。不幸的是,这个答案只是避免了问题而没有真正解决它。当内容视图被缩放和平移时,内容应该理想地在导航栏下面,并以标准的iOS7方式显示出来。我可以使导航栏不透明并避免这个问题,但这并不是真正的理想情况。这可能实际上是一个iOS的bug。 - Kenny Wyland

0
原来问题是在UIScrollView启用分页功能后才出现的!怎么回事? :)
就像你说的那样,如果启用了滚动分页,UIScrollView会在拖动或任何移动后停在分页边缘,这是由框架承诺的。通过将Bounds.origin.y设置为零,意味着第一个页面边缘与滚动视图框架边缘匹配,因为你有64个内容插入。所以这不是bug,这就是它的本来面目。而且由于你的导航栏是半透明的,请记住你的滚动视图的框架边缘在导航栏下方。总之,我认为这不是bug,而是滚动分页的效果。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接