62

我把 aUIScrollView放在我的 nib'sview中,并将它链接到 aIBOutlet属性。

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

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

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

4

15 回答 15

85

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

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

如果接近尾端的事情搞砸了(无论你UIScrollView滚动哪个方向的尾端),请更改最后的约束以具有最低的优先级。

于 2012-10-11T18:44:08.700 回答
71

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

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

苹果文档

-(void)viewDidLayoutSubviews

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

讨论

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

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

于 2014-03-31T11:46:39.540 回答
21

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

于 2013-03-05T01:01:31.867 回答
16

使用此代码。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;
                       });
}
于 2016-09-02T12:45:29.203 回答
15

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

第 1 步:创建一个UIScrollView

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

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

(我们称它为contentView)。

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

第 4 步(使用 AutoLayout):创建从您的contentView到其父视图(the 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;
}
于 2014-05-12T04:26:19.937 回答
14

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

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

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

于 2012-11-25T15:31:55.507 回答
5

您可以在 *.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

于 2015-04-17T13:48:03.553 回答
3

设置 contentSizeviewDidAppear至关重要。

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

于 2013-12-13T20:53:34.183 回答
1

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

@interface MyView : UIScrollView {}
@end

@implementation MyView
- (void)setContentSize:(CGSize)aSize {
    if (aSize.height > 0)
        [super setContentSize:aSize];
}
@end
于 2014-01-18T17:48:09.617 回答
1

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

观看视频后,您肯定会开始喜欢 Interface Builder。

投票

于 2014-08-27T22:15:54.860 回答
1

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

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

在此处输入图像描述

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

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

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

耶!

于 2015-11-10T01:22:45.987 回答
1

试试这个......
像你一样添加所有约束UIView (参见我在 Storyboard 中的 ViewControler 的屏幕截图) 现在技巧开始了。选择最后一个对象并选择其底部约束。(参见上面的屏幕截图,Instagram 按钮的底部约束(黄线))并在尺寸检查器中更改常量,如下图所示。
在此处输入图像描述

在此处输入图像描述

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

编辑

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

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

于 2016-06-06T09:05:04.007 回答
1

我终于找到了自己的解决方案来解决这个问题,因为在我的情况下,我无法使用视图控制器的生命周期。创建您自己的滚动视图子类并使用它来代替 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 = ...
于 2019-09-21T15:40:45.937 回答
0

如果您使用AutoLayout一种非常简单的方法来设置contentSizea UIScrollView,只需添加如下内容:

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];
于 2014-03-27T18:44:51.677 回答
0

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

脚步:

  • 定义全屏滚动视图。
  • 在滚动视图中,添加一个UIView(我称为 mine 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)
    }

}
于 2016-05-02T14:12:58.917 回答