【问题标题】:UIScrollView adjusts contentOffset when contentSize changesUIScrollView 在 contentSize 改变时调整 contentOffset
【发布时间】:2011-09-25 06:39:13
【问题描述】:

我正在调整细节视图控制器的状态,就在它被推送到navigationController 之前:

[self.detailViewController detailsForObject:someObject];
[self.navigationController pushViewController:self.detailViewController
                                     animated:YES];

DetailViewController 中存在一个滚动视图。我根据传递的对象调整了哪些内容的大小:

- (void)detailsForObject:(id)someObject {
    // set some textView's content here
    self.contentView.frame = <rect with new calculated size>;

    self.scrollView.contentSize = self.contentView.frame.size;
    self.scrollView.contentOffset = CGPointZero;
}

现在,这一切正常,但在 navigationController 的滑入动画期间,scrollView 将其调整为 contentOffsetcontentOffset 将设置为最后一个 contentSize 和新计算的值之间的差异。这意味着第二次打开 detailsView 时,详细信息将滚动到某个不需要的位置。即使我将contentOffset 明确设置为CGPointZero

我发现重置- viewWillAppear中的contentOffset没有效果。我能想到的最好办法是重置 viewDidAppear 中的 contentOffset,导致内容明显上下移动:

- (void)viewDidAppear:(BOOL)animated {
    self.scrollView.contentOffset = CGPointZero;
}

有没有办法防止UIScrollView 在其contentSize 更改时调整其contentOffset

【问题讨论】:

  • 为什么要调整动画块内的内容偏移量?跳过 CATransaction 的东西,所以它不会动画。这样它看起来就不会波涛汹涌。
  • 删除 CATransaction 的东西确实不会改变任何事情,所以它被删除了。
  • 你确定 viewDidAppear 被调用了吗?我会在其中设置断点或 NSLog 语句。另外,您是否尝试过切换调用顺序,即在推送后设置 detailsForObject?
  • 是的,它被调用了,它为滚动视图设置了正确的 contentOffset。但是 contentOffset 动画发生在 viewDidAppear 被调用之前。

标签: ios iphone uiscrollview contentsize


【解决方案1】:

在使用UINavigationController 推送包含UIScrollViewUIViewController 时发生。

iOS 11+

解决方案 1(Swift 代码):

scrollView.contentInsetAdjustmentBehavior = .never

解决方案 2(故事板)

iOS 7

解决方案 1(代码)

@property(nonatomic, assign) BOOL automaticallyAdjustsScrollViewInsets 设置为NO

解决方案 2(故事板)

取消选中Adjust Scroll View Insets

iOS 6

解决方案(代码)

viewWillLayoutSubviews 中设置UIScrollView 的属性contentOffsetcontentInset。示例代码:

- (void)viewWillLayoutSubviews{
  [super viewWillLayoutSubviews];
  self.scrollView.contentOffset = CGPointZero;
  self.scrollView.contentInset = UIEdgeInsetsZero;
}

【讨论】:

  • 这是解决问题的新方法。它比重置 contentSize 更整洁。
  • 出色的答案。感谢您发布 iOS 7 中的差异,甚至包括要澄清的图像。超级棒!
  • 很高兴帮助了你们 :)
【解决方案2】:

添加到 KarenAnne 的答案:

iOS 11+

automaticallyAdjustsScrollViewInsets 已弃用

改用这个:

故事板:

代码(斯威夫特):

scrollView.contentInsetAdjustmentBehavior = .never

【讨论】:

  • 我认为如果您建议将此作为对 KarenAnne 答案的编辑,会更好。
  • 你是对的@Yeheshuah。抱歉,我不知道我可以提出修改建议。
【解决方案3】:

我遇到了类似的问题,UIKit 在推送动画期间设置了我的 scrollView 的 contentOffset。

这些解决方案都不适合我,可能是因为我支持 iOS 10 和 iOS 11。

我可以通过子类化我的滚动视图来解决我的问题,以防止 UIKit 在从窗口中删除滚动视图后更改我的偏移量:

/// A Scrollview that only allows the contentOffset to change while it is in the window hierarchy. This can keep UIKit from resetting the `contentOffset` during transitions, etc.
class LockingScrollView: UIScrollView {
    override var contentOffset: CGPoint {
        get {
            return super.contentOffset
        }
        set {
            if window != nil {
                super.contentOffset = newValue
            }
        }
    }
}

【讨论】:

  • 这是一个相当粗略的解决方案。您可能会遇到 iOS 更新等问题。您能否进行更多调试,看看是什么导致 UIKit 在您的情况下行为不端? (setter 什么时候被调用?UI 上有设置可以工作吗?你有其他动画在运行吗?你有自定义转换等吗?)
  • 这无疑是一种强硬的方法,我更喜欢别的方法。我做了更多的挖掘,发现 setter 是由于视图的 _didMoveFromWindow:toWindow 而被调用的。看起来这是一个相关问题:stackoverflow.com/questions/13729359/…
  • 我已经更新了我的答案,采用了一种更简洁(尽管仍然很严厉)的方法。
【解决方案4】:

这对我有用:
在情节提要中,在 scrollView 的 Size Inspector 中,将 Content Insets Adjustment Behavior 设置为“Never”。

【讨论】:

    【解决方案5】:

    我在 UIScrollview 上遇到了同样的问题,该问题是由于未设置 contentSize 引起的。将 contentSize 设置为项目数后,此问题已解决。

    self.headerScrollView.mainScrollview.contentSize = CGSizeMake(320 * self.sortedMaterial.count, 0);
    

    【讨论】:

      【解决方案6】:

      我遇到了这个问题,对于特定情况 - 我不调整大小 - 我使用了以下内容:

      float position = 100.0;//for example
      
      SmallScroll.center = CGPointMake(position + SmallScroll.frame.size.width / 2.0, SmallScroll.center.y);
      

      同样适用于 y:anotherPosition + SmallScroll.frame.size.height / 2.0

      因此,如果您不需要调整大小,这是一个快速而轻松的解决方案。

      【讨论】:

        【解决方案7】:

        虽然我找到了解决方案,但此问题的原因仍不清楚。通过在调整它们之前重置内容大小和偏移量,UIScrollView 不会动画:

        - (void)detailsForObject:(id)someObject {
            // These 2 lines solve the issue:
            self.scrollView.contentSize = CGSizeZero;
            self.scrollView.contentOffset = CGPointZero;
        
            // set some textView's content here
            self.contentView.frame = <rect with new calculated size>;
        
            self.scrollView.contentSize = self.contentView.frame.size;
            self.scrollView.contentOffset = CGPointZero;
        }
        

        【讨论】:

          【解决方案8】:

          你的 scrollView 是 DetailViewController 的根视图吗?如果是,请尝试将 scrollView 包装在一个普通的 UIView 中,并使后者成为 DetailViewController 的根视图。由于UIViews 没有contentOffset 属性,因此它们不受导航控制器所做的内容偏移调整(由于导航栏等原因)的影响。

          【讨论】:

          • scrollView 不是 DetailViewController 的根视图。 self.scrollView 绑定到位于 DetailViewController 根视图中的 UIScrollView。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-10-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多