UIScrollView contentSize不起作用

时间:2012-10-11 18:39:42

标签: objective-c ios uiscrollview

我在我的笔尖UIScrollView中添加了view,并将其与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与框架相同。发生了什么事? 当我关闭AutoLayout时,这开始工作。为什么呢?

15 个答案:

答案 0 :(得分:78)

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

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

如果接近末尾的事情搞砸了(UIScrollView滚动的方向结束),请更改末尾的约束以使其具有最低优先级。

答案 1 :(得分:67)

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

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

Apple Doc

-(void)viewDidLayoutSubviews

调用以通知视图控制器其视图刚刚布置了其子视图。

<强>讨论

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

您的视图控制器可以覆盖此方法,以便在视图布局其子视图后进行更改。此方法的默认实现不执行任何操作。

答案 2 :(得分:20)

最简单/最干净的方法是在viewDidAppear中设置contentSize,以便否定autolayout的影响。这不涉及添加随机视图。但是,依靠加载顺序使实现工作可能不是最好的主意。

答案 3 :(得分:14)

在Interface Builder中使用AutoLayout与UIScrollViews的简单方法:

第1步:创建UIScrollView

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

UIView

(我们称之为-UIScrollView ---UIView -----Your other content )。

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

第4步(使用AutoLayout):contentView到其超级视图(contentView)创建明确的约束:连接4条边(顶部,前导,尾随,底部),然后给它一个你想要滚动的定义宽度和高度。

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

步骤4(不使用AutoLayout):使用IB将这两个新控件连接到视图控制器(按住Ctrl键并从每个控件拖动到视图控制器&#39; s .h @implementation) 。我们假设每个分别称为UIScrollViewscrollView。它应该是这样的:

contentView

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

@interface YourViewController : UIViewController

@property (strong, nonatomic) IBOutlet UIScrollView *scrollView;
@property (strong, nonatomic) IBOutlet UIView *contentView;

@end

答案 4 :(得分:13)

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

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

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

答案 5 :(得分:12)

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

夫特:

ForkJoinPool fjp = ForkJoinPool.common();
Runnable task = new Runnable(){
  public void run(){
    //Some cpu-intensive code
    ForkJoinPool.managedBlock(new ForkJoinPool.ManagedBlocker(){
      public boolean isReleasable(){
        //return true if an IO/blocking operation is to be done.
      }

      public boolean block(){
       //Do an IO Operation here
       //return true if all blocking code has finished execution.
       //return false if more blocking code is yet to execute.
      }

    });
    //Some more CPU intensive code here
  }
};
fjp.submit(task);

目标C:

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
    }
}

答案 6 :(得分:5)

您可以将这行代码用于* .m文件的

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

为此你需要以这种方式将UIScrollView的IBOutlet属性带入你的* .h文件:

IBOutlet UIScrollView *scroll;

从故事板连接。

或者,

您可以将此方法用于* .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 :(得分:3)

viewDidAppear中设置contentSize至关重要。

但我也有3.5英寸屏幕和4英寸屏幕的变化。 4英寸的屏幕工作,旧的屏幕没有。 iOS 7. Bizarre都是轻描淡写!

答案 8 :(得分:2)

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

 class MyScrollView:UIScrollView {

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

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

 }

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

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

答案 9 :(得分:1)

我永远无法根据工作约束进行自动布局。由于我的视图已经是UIScrollView的子类,我通过重写setContentView来解决它:并忽略自动布局零高度setContentSize:message。

@interface MyView : UIScrollView {}
@end

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

答案 10 :(得分:1)

如果您使用AutoLayout,设置contentSize的{​​{1}}非常简单,只需添加以下内容:

UIScrollView

答案 11 :(得分:1)

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

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

投票

答案 12 :(得分:1)

当标签的动态高度超出视图高度时仍然无法滚动。

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

enter image description here

在我的内容视图中,我有一张图片,下方有3个标签。每个标签根据文本的大小调整自己的高度(它们设置为自动换行,numberoflines = 0来实现此目的)。

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

为了解决这个问题,我说我需要在我的底部标签和内容视图之间设置底部空间到容器约束,并给它一个值40(任意选择它给它一个很好的余量)底部)。现在这意味着我的contentview调整其高度,以便在最后一个标签的底部与其自身之间留出一个空格,并且 它完全滚动

耶!

答案 13 :(得分:1)

试试这个...
UIView 一样添加所有约束(参见故事板中我的ViewControler的screenShot
enter image description here
现在技巧开始了。选择最后一个对象并选择其底部约束。 (参见上面的screenShot,Instagram按钮的底部约束(黄线))并更改大小检查器中的常量,如下面的截图。

enter image description here

我需要Constant = 8,但您可以根据自己的要求进行更改。 此常量是橙色按钮的底部和scrollView之间的空间。

修改

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

0)ViewController.view(可选
1)UIScrollView
2)UIView(重命名为“contentView”)
3)UIView(此视图是您的内容,将使 scrollView 滚动)

答案 14 :(得分:0)

我让Autolayout为分页滚动视图工作,其页面占据了屏幕的全宽。 页面会根据滚动视图的大小自动调整大小。我没有对较小宽度的滚动视图进行测试,但如果有效则请注释掉 - 我应该相信它。针对iOS 9,在Swift 2中编写代码,在awakeFromNib中使用了IB和自定义代码的混合。

步骤:

  • 定义全屏滚动视图。
  • 在滚动视图中,添加一个UIView(我称之为contentView},其滚动视图的顶部,尾部,底部和前缘均为零;高度等于滚动视图的高度; 但宽度是滚动视图的宽度乘以页数。如果您在视觉上这样做,您将看到内容视图超出了Inteface Builder中的滚动视图。
  • 对于contentView内的每个“页面”,添加Autolayout规则以将它们并排放置,但最重要的是,为每个规则赋予它们一个约束,使其宽度等于滚动视图,而不是内容视图。

以下示例代码。 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)
    }

}