【问题标题】:UIScrollView contentSize not workingUIScrollView contentSize 不起作用
【发布时间】:2012-10-02 12:26:38
【问题描述】:

我在我的笔尖的view 中放了一个UIScrollView,并将它链接到一个IBOutlet 属性。

现在,当我在 viewDidLoad 方法中执行此操作时,它似乎对 contentSize 没有影响:

self.sv.backgroundColor = [UIColor yellowColor]; // this works
CGSize size =  CGSizeMake(1000.0, 1000.0); 
[self.sv setContentSize:size]; // this does not

它的行为就像contentSize 与框架相同。这是怎么回事? 当我关闭自动布局时,这开始工作。为什么?

【问题讨论】:

标签: objective-c ios uiscrollview


【解决方案1】:

我终于找到了自己的解决方案来解决这个问题,因为在我的情况下,我无法使用视图控制器的生命周期。创建您自己的滚动视图子类并使用它来代替 UIScrollView。这甚至适用于集合视图单元格内的滚动视图。

 class MyScrollView:UIScrollView {

    var myContentSize:CGSize = CGSize.zero  // you must set this yourself 

    override func layoutSubviews() {
       super.layoutSubviews()
       contentSize = myContentSize
    }

 }

MyScrollView 是在 nib 中定义的,标签为 90。如果是这样,这是在父视图的代码中设置内容大小的好方法。

let scrollView = viewWithTag(90) as! MyScrollView      
scrollView.myContentSize = ...

【讨论】:

    【解决方案2】:

    使用此代码。 ScrollView setContentSize 应该在主线程中调用异步。

    斯威夫特:

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
    
        DispatchQueue.main.async {
            var contentRect = CGRect.zero
    
            for view in self.scrollView.subviews {
               contentRect = contentRect.union(view.frame)
            }
    
            self.scrollView.contentSize = contentRect.size
        }
    }
    

    目标 C:

     - (void)viewDidLayoutSubviews {
         [super viewDidLayoutSubviews];
    
         dispatch_async(dispatch_get_main_queue(), ^ {
                            CGRect contentRect = CGRectZero;
    
                            for(UIView *view in scrollView.subviews)
                               contentRect = CGRectUnion(contentRect,view.frame);
    
                               scrollView.contentSize = contentRect.size;
                           });
    }
    

    【讨论】:

    • 这对我来说非常有效,我已经在网上测试了 almast 解决方案,但它并没有像我预期的那样工作
    【解决方案3】:

    试试这个...
    UIView 一样添加所有约束(在 Storyboard 中查看我的 ViewControler 的屏幕截图

    现在诡计开始了。选择最后一个对象并选择其底部约束。 (参见上面的屏幕截图,Instagram 按钮的底部约束(黄线)) 并在尺寸检查器中更改常量,如下图所示。

    我需要 Constant=8 但您可以根据自己的要求进行更改。 这个常量是那个橙色按钮的底部和滚动视图之间的空间。

    编辑

    确保您的视图的层次结构。

    0) ViewController.view(可选
    1) UIScrollView
    2) UIView(重命名为“contentView”)
    3) UIView(这个视图是你的内容,会让 scrollView 滚动)

    【讨论】:

      【解决方案4】:

      我让 Autolayout 为页面占据整个屏幕宽度的分页滚动视图工作。 页面会根据滚动视图的大小自动调整大小。我还没有测试过宽度较小的滚动视图,但如果它有效,请不要评论——我相信它应该。针对 iOS 9,在 Swift 2 中编写代码,在 awakeFromNib 中混合使用了 IB 和自定义代码。

      步骤:

      • 定义全屏滚动视图。
      • 在滚动视图中,添加一个UIView(我叫我的contentView),它的滚动视图的顶部、尾部、底部和前沿都为零;高度等于滚动视图的高度; 但宽度是滚动视图的宽度乘以页数。如果您在视觉上这样做,您会看到您的内容视图超出了界面生成器中的滚动视图。
      • 对于contentView 中的每个“页面”,添加自动布局规则以将它们并排放置,但最重要的是,为它们各自设置一个约束,使其宽度等于滚动视图的宽度,而不是内容视图的。

      下面的示例代码。 embedChildViewController 只是我添加子 VC 的便捷方法——请查看 setupLayoutRulesForPages。我正好有两页所以功能太简单了,不过你可以根据自己的需要进行扩展。

      在我的视图控制器中:

      override func loadView() {
          self.view = self.customView
      }
      
      override func viewDidLoad() {
      super.viewDidLoad()
      
      self.embedChildViewController(self.addExpenseVC, toView: self.customView.contentView, fillSuperview: false)
      self.embedChildViewController(self.addCategoryVC, toView: self.customView.contentView, fillSuperview: false)
      self.customView.setupLayoutRulesForPages(self.addExpenseVC.view, secondPage: self.addCategoryVC.view)
      }
      

      我的自定义视图:

      class __AMVCView: UIView {
      
          @IBOutlet weak var scrollView: UIScrollView!
          @IBOutlet weak var contentView: UIView!
          @IBOutlet weak var pageControl: UIPageControl!
      
          override func awakeFromNib() {
              super.awakeFromNib()
      
              self.scrollView.pagingEnabled = true
              self.scrollView.bounces = true
              self.scrollView.showsHorizontalScrollIndicator = false
              self.scrollView.showsVerticalScrollIndicator = false
      
              self.pageControl.numberOfPages = 2
      
              self.contentView.backgroundColor = UIColor.blueColor()
              self.scrollView.backgroundColor = UIColor.clearColor()
              self.backgroundColor = UIColor.blackColor()
          }
      
          func setupLayoutRulesForPages(firstPage: UIView, secondPage: UIView) {
              guard self.contentView.subviews.contains(firstPage) && self.contentView.subviews.contains(secondPage)
                  else {
                      return
              }
      
              let rules = [
                  "H:|-0-[firstPage]-0-[secondPage]-0-|",
                  "V:|-0-[firstPage]-0-|",
                  "V:|-0-[secondPage]-0-|"
              ]
              let views = [
                  "firstPage" : firstPage,
                  "secondPage" : secondPage
              ]
              let constraints = NSLayoutConstraint.constraintsWithVisualFormatArray(rules, metrics: nil, views: views)
      
              UIView.disableAutoresizingMasksInViews(firstPage, secondPage)
              self.addConstraints(constraints)
      
              // Add the width Autolayout rules to the pages.
              let widthConstraint = NSLayoutConstraint(item: firstPage, attribute: .Width, relatedBy: .Equal, toItem: self.scrollView, attribute: .Width, multiplier: 1, constant: 0)
              self.addConstraint(widthConstraint)
          }
      
      }
      

      【讨论】:

        【解决方案5】:

        标签的动态高度超过视图高度时仍然不滚动。

        我做了上面标记为正确的 yuf 的答案所说的(我在我的滚动视图中添加了一个内容视图,并设置了从内容视图到滚动视图的前导、尾随、顶部底部和相等宽度的约束。)但仍然当内部控件高度超过滚动视图的高度时,我的视图没有滚动。

        在我的内容视图中,我有一张图片和下面的 3 个标签。每个标签都会根据其中的文本量调整自己的高度(它们被设置为自动换行并且 numberoflines = 0 来实现这一点)。

        我遇到的问题是当标签超过滚动视图/主视图的高度时,我的内容视图的高度没有根据标签的动态高度进行调整。

        为了解决这个问题,我说我需要在底部标签和内容视图之间设置 Bottom Space to Container 约束,并给它一个值 40(任意选择以在底端)。这现在意味着我的内容视图调整了它的高度,以便在最后一个标签的底部和它自身之间有一个空间,它可以完美滚动

        耶!

        【讨论】:

          【解决方案6】:

          您可以在 *.m 文件中使用这行代码

          - (void)viewDidLoad{
             [scroll setContentSize:CGSizeMake(320, 800)]   ;
             [scroll setScrollEnabled:TRUE];
             [scroll setShowsVerticalScrollIndicator:NO];
             [scroll setShowsHorizontalScrollIndicator:YES];
          }    
          

          为此,您需要通过这种方式将 UIScrollView 的 IBOutlet 属性放入您的 *.h 文件中:

          IBOutlet UIScrollView *scroll;
          

          并从 Storyboard 中连接它。

          或者,

          你可以在你的 *.m 文件中使用这个方法:

          -(void)viewDidLayoutSubviews 
          {
            [scroll setContentSize:CGSizeMake(320, self.view.frame.size.height* 1.5)];
             // this will pick height automatically from device's height and multiply it with 1.5  
          }
          

          这两种解决方案都适用于 xcode-5、xcode-6、xcode-6.1、xcode-6.2

          【讨论】:

            【解决方案7】:

            我遇到了同样的问题。 UIScrollView 的自动布局搞砸了。

            解决方法:将UIScrollView 中的所有内容放入另一个UIView,并将UIView 作为UIScrollView 的唯一子代。然后你可以使用自动布局。

            如果接近尾端的事情搞砸了(UIScrollView 滚动的任何方向的尾端),请将最后的约束更改为尽可能低的优先级。

            【讨论】:

            【解决方案8】:

            在 Interface Builder 中使用带有 UIScrollViews 的 AutoLayout 的超级简单方法:

            第 1 步:创建UIScrollView

            第 2 步:创建一个 UIView,它是滚动视图的子项,如下所示:

            -UIScrollView
            ---UIView
            -----Your other content
            

            (我们称之为contentView)。

            第 3 步:在尺寸检查器中,为此视图指定高度和宽度(例如 320x700)。

            第 4 步(使用 AutoLayout): 创建从 contentView 到其父视图(UIScrollView)的明确约束:连接 4 个边(顶部、前导、尾随、底部),然后给它一个定义的宽度和高度,您也希望它滚动。

            例如:如果您的滚动视图跨越整个屏幕,您可以为内容视图设置 [设备宽度] 的宽度和 600 的高度;然后它将设置UIScrollView 的内容大小以匹配。

            或:

            第 4 步(不使用 AutoLayout): 使用 IB 将这两个新控件连接到您的视图控制器(从每个控件按 ctrl+拖动到您的视图控制器的 .h @implementation)。假设每个分别称为scrollViewcontentView。它应该是这样的:

            @interface YourViewController : UIViewController
            
            @property (strong, nonatomic) IBOutlet UIScrollView *scrollView;
            @property (strong, nonatomic) IBOutlet UIView *contentView;
            
            @end
            

            第 5 步(不使用 AutoLayout): 在视图控制器的 .h 文件中添加(实际上是覆盖)以下方法:

            -(void)viewDidLayoutSubviews
            {
                [super viewDidLayoutSubviews];
                self.scrollView.contentSize = self.contentView.frame.size;
            }
            

            【讨论】:

            • 目前为止最好最简单的方法。
            • 优秀的答案。这实际上是一个非常棘手的问题。另外,请记住将滚动视图的设置调整为正确页面,以便预期的滚动不会在中途结束
            • @ProjectNoa 是的,准确地说。
            【解决方案9】:

            如果您使用AutoLayout,设置contentSizecontentSize 的一个非常简单的方法是添加如下内容:

            CGFloat contentWidth = YOUR_CONTENT_WIDTH;
            
            NSLayoutConstraint *constraintWidth = 
             [NSLayoutConstraint constraintWithItem:self.scrollView 
                                          attribute:NSLayoutAttributeTrailing 
                                          relatedBy:NSLayoutRelationEqual 
                                             toItem:self.scrollView 
                                          attribute:NSLayoutAttributeLeading 
                                         multiplier:1 
                                           constant:contentWidth];
            
            [self.scrollView addConstraint:constraintWidth];
            

            【讨论】:

              【解决方案10】:

              我曾经以编程方式设置 uiscrollview,直到我观看了以下精彩教程,逐步了解如何让 uiscrollview 和 uiview 工作:https://www.youtube.com/watch?v=PgeNPRBrB18

              观看视频后,我相信您会开始喜欢 Interface Builder。

              投票

              【讨论】:

                【解决方案11】:

                我尝试使用 viewWillLayoutSubviews 来更新 scrollView 的 contentSize,它对我有用。

                - (void)viewDidLayoutSubviews
                {
                  [self.bgScrollView setContentSize:CGSizeMake(320, self.view.frame.size.height* 1.5)];
                }
                

                Apple Doc

                -(void)viewDidLayoutSubviews
                

                调用来通知视图控制器它的视图刚刚布置了它的子视图。

                讨论

                当视图控制器视图的边界发生变化时,视图会调整其子视图的位置,然后系统调用此方法。但是,调用此方法并不表示视图的子视图的各个布局已被调整。每个子视图负责调整自己的布局。

                您的视图控制器可以覆盖此方法以在视图布置其子视图后进行更改。这个方法的默认实现什么都不做。

                【讨论】:

                • 这是一个很好的答案,不仅因为滚动视图,当您使用情节提要并处理 3.5 英寸屏幕和 4 英寸屏幕进行布局或任何控件框架时,它也可以工作。我提高了你的回答。谢谢
                • 完美!非常感谢你,它帮助了很多
                • 感谢您的回答! (Y)
                • 您将视图高度乘以 1.5 以设置滚动视图高度,但如果滚动视图内的控件具有可变高度,这将不起作用。例如,如果您在滚动视图中有一个高度可变的 uiTextView(取决于其内容),则滚动视图高度与其实际高度不匹配。
                • @Jerome 它只是一个更新内容大小的例子。您可以根据需要设置自己的内容大小以适应组件。
                【解决方案12】:

                我永远无法获得基于约束的自动布局来工作。由于我的视图已经是 UIScrollView 的子类,因此我通过覆盖 setContentView: 并忽略自动布局零高度 setContentSize: 消息来解决它。

                @interface MyView : UIScrollView {}
                @end
                
                @implementation MyView
                - (void)setContentSize:(CGSize)aSize {
                    if (aSize.height > 0)
                        [super setContentSize:aSize];
                }
                @end
                

                【讨论】:

                  【解决方案13】:

                  viewDidAppear 中设置 contentSize 至关重要。

                  但我也有 3.5 英寸屏幕和 4 英寸屏幕的变化。 4英寸的屏幕可以用,旧的不行。两者都是 iOS 7。奇怪的是轻描淡写!

                  【讨论】:

                    【解决方案14】:

                    最简单/最干净的方法是在 viewDidAppear 中设置 contentSize,这样您就可以消除自动布局的影响。这不涉及添加随机视图。然而,依靠加载顺序来实现工作可能不是最好的主意。

                    【讨论】:

                    • 完美回答我想要的,非常感谢。
                    【解决方案15】:

                    这里有两个问题。 (1) viewDidLoad 过早;您必须等到布局完成后。 (2)如果你想使用来自笔尖的滚动视图的自动布局,那么你必须使用约束来完全描述contentSize的大小(然后你根本没有在代码中设置contentSize ),或者,如果您想在代码中设置它,您必须防止滚动视图的子视图上的约束指示contentSize。听起来你想做后者。为此,您需要一个 UIView 作为滚动视图的唯一顶级子视图,并且在代码中您必须将其设置为使用自动布局,启用其autoresizingMask 并删除其其他外部约束。我在这里展示了一个如何做到这一点的例子:

                    https://github.com/mattneub/Programming-iOS-Book-Examples/blob/master/ch20p573scrollViewAutoLayout/ch20p573scrollViewAutoLayout/ViewController.m

                    但请注意下一个示例,它显示了如何完全使用约束,而不是 contentSize

                    【讨论】:

                    • “你必须使用约束来完整描述contentSize的大小(然后你根本没有在代码中设置contentSize)” - 这是问题的正确解决方案
                    • @Fervus 除了在 iOS 8 中,到目前为止,它已被破坏。
                    • @matt,您的链接已损坏。你能恢复它吗?
                    • @Samuel 我的书当前版本的示例在这里:github.com/mattneub/Programming-iOS-Book-Examples 现在有问题的以“bk2ch07”开头。
                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2013-03-24
                    • 1970-01-01
                    • 2017-04-27
                    相关资源
                    最近更新 更多