如何动态设置UIScrollView的内容大小

时间:2012-05-09 15:04:35

标签: iphone objective-c uiview uiscrollview

我对UIScrollview提出了疑问。

故事是我有一个名为ChartsView的UIView我自己通过覆盖方法drawRect()重新绘制它。绘图的内容是动态生成的。所以直到运行时我才知道它的大小。问题是如何/在哪里可以动态设置其超级视图(scrollView)的内容大小?有什么想法吗?

    - (void)viewDidLoad
    {
        [super viewDidLoad];

// not this way. it's fixed size.....
        ChartsView *chartsView = [[ChartsView alloc]initWithFrame:CGRectMake(0, 0, 320, 800)]; 

        self.scrollView.contentSize = chartsView.frame.size;

        [self.scrollView addSubview:chartsView];

    }

12 个答案:

答案 0 :(得分:58)

一个更简单的方法

- (void)viewDidLoad
{
    float sizeOfContent = 0;
    UIView *lLast = [scrollView.subviews lastObject];
    NSInteger wd = lLast.frame.origin.y;
    NSInteger ht = lLast.frame.size.height;

    sizeOfContent = wd+ht;

    scrollView.contentSize = CGSizeMake(scrollView.frame.size.width, sizeOfContent);
}

答案 1 :(得分:10)

不能100%保证scrollView.subviews数组中的最后一个对象将返回滚动视图中最高的y-origin对象。子视图数组由Z-Index排列(即子视图数组中的最后一个对象将是堆叠最高的对象,并且将成为滚动视图子视图中的最顶层子视图。相反,它更准确地使用一个基本的排序函数,用于遍历子视图并获取具有最高y源的对象。

这是swift 3中的一个基本功能,可以这样做:

func calculateContentSize(scrollView: UIScrollView) -> CGSize {
    var topPoint = CGFloat()
    var height = CGFloat()

    for subview in scrollView.subviews {
        if subview.frame.origin.y > topPoint {
            topPoint = subview.frame.origin.y
            height = subview.frame.size.height
        }
    }
    return CGSize(width: scrollView.frame.size.width, height: height + topPoint)
}

用法(在viewDidLayoutSubviews或内容大小更新时):

scrollView.contentSize = calculateContentSize(scrollView: scrollView)

UPDATE SWIFT 4

这是swift 4中更加简洁的版本

extension UIScrollView {
    func updateContentView() {
        contentSize.height = subviews.sorted(by: { $0.frame.maxY < $1.frame.maxY }).last?.frame.maxY ?? contentSize.height
    }
}

用法:

myScrollView.updateContentView()

答案 2 :(得分:6)

swift (2.0)

@IBOutlet weak var btnLatestButton: UIButton!

override func viewDidLoad() {
    super.viewDidLoad()

    let height = btnLatestButton.frame.size.height
    let pos = btnLatestButton.frame.origin.y
    let sizeOfContent = height + pos + 10
    scrollview.contentSize.height = sizeOfContent

}

当然,您可以在滚动视图中获得固定数量的观看次数。 IOS Rocks方法可用但对我不好,创造了更多空间,然后我需要。

    let lastView : UIView! = scrollview.subviews.last
    let height = lastView.frame.size.height
    let pos = lastView.frame.origin.y
    let sizeOfContent = height + pos + 10
    scrollview.contentSize.height = sizeOfContent

答案 3 :(得分:3)

感谢IOS Rocks和CularBytes对此的引导。我发现上述解决方案存在两个问题(对我而言):

  1. 我总是有一个容器UIView作为我的UIScrollView的唯一子项,所以我必须更新我查找该子项UIView中最后一个视图的方式(见下文)
  2. 我在UIScrollView中偏移了我的内容,因此需要计算最后一个UIView的绝对位置(因此,相对于窗口而不是父视图)
  3. 另外我使用autolayout来固定UIScrollView的两侧,所以我不需要担心宽度(就像CularBytes一样)。

    这是我想出的并且有效(在Swift 3.0中):

    func setScrollViewContentSize() {
    
        var height: CGFloat
        let lastView = self.myScrollView.subviews[0].subviews.last!
        print(lastView.debugDescription) // should be what you expect
    
        let lastViewYPos = lastView.convert(lastView.frame.origin, to: nil).y  // this is absolute positioning, not relative
        let lastViewHeight = lastView.frame.size.height
    
        // sanity check on these
        print(lastViewYPos)
        print(lastViewHeight)
    
        height = lastViewYPos + lastViewHeight
    
        print("setting scroll height: \(height)")
    
        myScrollView.contentSize.height = height
    }
    

    我在viewDidAppear()方法中调用此方法。

答案 4 :(得分:1)

试试这个

- (void)viewDidLoad
        {
            [super viewDidLoad];

    // not this way. it's fixed size.....
            ChartsView *chartsView = [[ChartsView alloc]initWithFrame:CGRectMake(0, 0, 320, 800)]; 

            self.scrollView.contentSize = chartsView.frame.size;
            [self.scrollView setNeedsDisplay];
            [self.scrollView addSubview:chartsView];

    }

答案 5 :(得分:1)

试试这个 -

- (void)viewDidLoad
    {
        [super viewDidLoad];

// not this way. it's fixed size.....
        ChartsView *chartsView = [[ChartsView alloc]initWithFrame:CGRectMake(0, 0, 320, 800)]; 

        //self.scrollView.contentSize = chartsView.frame.size;
        [self.scrollView setContentSize:CGSizeMake(chartsView.frame.size.width, chartsView.frame.size.height)];
        [self.scrollView addSubview:chartsView];

    }

答案 6 :(得分:1)

在情节提要中使用滚动视图时,最好根据滚动视图中显示的视图数来计算内容大小,而不是通过编程将内容大小设置为静态值。 这是动态获取内容大小的步骤。

第1步: 添加Scrollview以在情节提要中查看,并添加开头,结尾,顶部和底部约束(所有值为零)。

第2步: 不要在直接滚动视图中直接添加所需的视图,首先要在滚动视图中添加一个视图(这将是我们所有UI元素的内容视图)。在此视图中添加以下约束。 前导,尾随,顶部和底部约束(所有值均为零)。 在主视图(即包含滚动视图)中添加相等的高度,相等的宽度。对于相等的高度,将优先级设置为低。 (这是设置内容大小的重要步骤)。 此内容视图的高度将根据添加到该视图的视图数确定。假设您添加的最后一个视图是一个标签,并且其Y位置是420,高度是20,那么您的内容视图将是440。

第3步::根据需要向在内容视图中添加的所有视图添加约束。

What does "static" mean in C?

enter image description here

参考:enter image description here

答案 7 :(得分:1)

SWIFT 5

您还可以通过调整 UIScrollView 以编程方式更新 UIScrollView.contentLayoutGuide 的 contentView,以下是将 contentview 限制为 yourView 高度的示例:

self.scrollView.translatesAutoresizingMaskIntoConstraints = false
self.scrollView.translatesAutoresizingMaskIntoConstraints = false
self.scrollView.heightAnchor.constraint(equalTo: self.view.heightAnchor).isActive = true
self.scrollView.widthAnchor.constraint(equalTo: self.view.widthAnchor).isActive = true
self.scrollView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
self.scrollView.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true

self.scrollView.contentLayoutGuide.heightAnchor.constraint(equalTo: yourView.heightAnchor, multiplier: 1).isActive = true
self.scrollView.contentLayoutGuide.widthAnchor.constraint(equalTo: self.view.widthAnchor, multiplier: 1).isActive = true
self.scrollView.contentLayoutGuide.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
self.scrollView.contentLayoutGuide.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true

答案 8 :(得分:0)

这是Swift 3上的扩展

extension UIScrollView {
    func updateContentViewSize() {
        var newHeight: CGFloat = 0
        for view in subviews {
            let ref = view.frame.origin.y + view.frame.height
            if ref > newHeight {
                newHeight = ref
            }
        }
        let oldSize = contentSize
        let newSize = CGSize(width: oldSize.width, height: newHeight + 100)
        contentSize = newSize
    }
}

答案 9 :(得分:0)

动态计算UIScrollview contentSize(取决于子视图框架)

迅速:

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

答案 10 :(得分:0)

override func viewDidAppear(_ animated: Bool) {
    var height: CGFloat
    let lastView = self.scrollView.subviews[0].subviews.last!

    let lastViewYPos = lastView.convert(lastView.frame.origin, to: nil).y  
    let lastViewHeight = lastView.frame.size.height

    height = lastViewYPos + lastViewHeight
    scrollView.contentSize.height = height
}

答案 11 :(得分:0)

将contentInset与

一起使用

故事板

以编程方式

关注this works best