我如何自动调整大小一个UIScrollView,以适应其内容

问题描述 投票:120回答:20

有没有一种方法,使UIScrollView自动调整到它的滚动内容的高度(或宽度)?

就像是:

[scrollView setContentSize:(CGSizeMake(320, content.height))];
iphone ios objective-c cocoa-touch uiscrollview
20个回答
297
投票

最好的方法,我曾经遇到过更新基于其子视图包含一个UIScrollView的内容大小:

Objective-C的

CGRect contentRect = CGRectZero;

for (UIView *view in self.scrollView.subviews) {
    contentRect = CGRectUnion(contentRect, view.frame);
}
self.scrollView.contentSize = contentRect.size;

迅速

var contentRect = CGRect.zero

for view in mainScrollView.subviews {
   contentRect = contentRect.union(view.frame)
}
mainScrollView.contentSize = contentRect.size

3
投票

我有另一种解决方案提出了基于@ emenegro的解决方案

NSInteger maxY = 0;
for (UIView* subview in scrollView.subviews)
{
    if (CGRectGetMaxY(subview.frame) > maxY)
    {
        maxY = CGRectGetMaxY(subview.frame);
    }
}
maxY += 10;
[scrollView setContentSize:CGSizeMake(scrollView.frame.size.width, maxY)];

基本上,我们找出哪些元素是最远向下视图中,并添加了10px的填充至底部


3
投票

因为滚动型可具有其他scrollViews或不同深入子视图树中,在深度运行递归是优选的。 enter image description here

斯威夫特2

extension UIScrollView {
    //it will block the mainThread
    func recalculateVerticalContentSize_synchronous () {
        let unionCalculatedTotalRect = recursiveUnionInDepthFor(self)
        self.contentSize = CGRectMake(0, 0, self.frame.width, unionCalculatedTotalRect.height).size;
    }

    private func recursiveUnionInDepthFor (view: UIView) -> CGRect {
        var totalRect = CGRectZero
        //calculate recursevly for every subView
        for subView in view.subviews {
            totalRect =  CGRectUnion(totalRect, recursiveUnionInDepthFor(subView))
        }
        //return the totalCalculated for all in depth subViews.
        return CGRectUnion(totalRect, view.frame)
    }
}

用法

scrollView.recalculateVerticalContentSize_synchronous()

2
投票

或者只是做:

int y = CGRectGetMaxY(((UIView*)[_scrollView.subviews lastObject]).frame); [_scrollView setContentSize:(CGSizeMake(CGRectGetWidth(_scrollView.frame), y))];

(该解决方案是由我添加在本页面评论。让19升票此评论之后,我决定加入这个解决方案,为社会造福的正式答案!)


1
投票

大小取决于它里面装的内容,剪辑选项。如果它的一个TextView,那么它也依赖于包装,有多少行文字,字体大小,等而上。几乎不可能为你计算你自己。好消息是,该视图被加载后计算,并在viewWillAppear中。在此之前,这一切都未知的,并且内容的大小将是相同的帧大小。但是,在viewWillAppear中方法和后(如viewDidAppear)的含量大小将是实际的。


1
投票

包装里希的代码,我创建的内容自动调整大小完全自定义的UIScrollView类!

SBScrollView.h

@interface SBScrollView : UIScrollView
@end

SBScrollView.m:

@implementation SBScrollView
- (void) layoutSubviews
{
    CGFloat scrollViewHeight = 0.0f;
    self.showsHorizontalScrollIndicator = NO;
    self.showsVerticalScrollIndicator = NO;
    for (UIView* view in self.subviews)
    {
        if (!view.hidden)
        {
            CGFloat y = view.frame.origin.y;
            CGFloat h = view.frame.size.height;
            if (y + h > scrollViewHeight)
            {
                scrollViewHeight = h + y;
            }
        }
    }
    self.showsHorizontalScrollIndicator = YES;
    self.showsVerticalScrollIndicator = YES;
    [self setContentSize:(CGSizeMake(self.frame.size.width, scrollViewHeight))];
}
@end

如何使用: 只要.h文件导入到您的视图控制器,并声明SBScrollView实例,而不是正常的UIScrollView之一。


1
投票

设置动态内容的大小是这样的。

 self.scroll_view.contentSize = CGSizeMake(screen_width,CGRectGetMaxY(self.controlname.frame)+20);

1
投票

对于swift4使用减少:

self.scrollView.contentSize = self.scrollView.subviews.reduce(CGRect.zero, {
   return $0.union($1.frame)
}).size

0
投票

它取决于真正的内容:content.frame.height可能给你你想要什么?如果要看内容是一个单一的东西,或事物的集合。


0
投票

我还发现利维坦的回答最好的工作。然而,这是计算一个奇怪的高度。当通过子视图循环,如果滚动视图设置为显示滚动的指标,这些将是子视图的在数组中。在这种情况下,解决的办法是循环之前暂时禁用滚动指标,然后重新建立他们以前的可见性设置。

-(void)adjustContentSizeToFit是的UIScrollView的自定义子类的公共方法。

-(void)awakeFromNib {    
    dispatch_async(dispatch_get_main_queue(), ^{
        [self adjustContentSizeToFit];
    });
}

-(void)adjustContentSizeToFit {

    BOOL showsVerticalScrollIndicator = self.showsVerticalScrollIndicator;
    BOOL showsHorizontalScrollIndicator = self.showsHorizontalScrollIndicator;

    self.showsVerticalScrollIndicator = NO;
    self.showsHorizontalScrollIndicator = NO;

    CGRect contentRect = CGRectZero;
    for (UIView *view in self.subviews) {
        contentRect = CGRectUnion(contentRect, view.frame);
    }
    self.contentSize = contentRect.size;

    self.showsVerticalScrollIndicator = showsVerticalScrollIndicator;
    self.showsHorizontalScrollIndicator = showsHorizontalScrollIndicator;
}

0
投票

我认为这是可以更新UIScrollView的内容视图大小的一种巧妙的方法。

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 + 20)
        contentSize = newSize
    }
}

75
投票

UIScrollView中不会自动知道其内容的高度。你必须计算自己的高度和宽度

喜欢的东西做

CGFloat scrollViewHeight = 0.0f;
for (UIView* view in scrollView.subviews)
{
   scrollViewHeight += view.frame.size.height;
}

[scrollView setContentSize:(CGSizeMake(320, scrollViewHeight))];

但是,这只是工作,如果该意见是一个在另一个之下。如果你有彼此相邻的一个观点,你只需要添加一个高度,如果你不希望设置滚动大于它确实是内容。


0
投票

为什么不一行代码?

_yourScrollView.contentSize = CGSizeMake(0, _lastView.frame.origin.y + _lastView.frame.size.height);

39
投票

解决方法如果您正在使用自动布局:

  • 设置translatesAutoresizingMaskIntoConstraintsNO所涉及的所有意见。
  • 位置以及与外部滚动视图限制大小滚动视图。
  • 使用约束来滚动视图中铺陈子视图,为确保限制配合滚动视图的所有四个边缘,不靠滚动视图来获取它们的大小。

来源:https://developer.apple.com/library/ios/technotes/tn2154/_index.html


35
投票

我说这Espuz和JCC的答案。它使用子视图的y位置,并且不包括滚动条。编辑用途是可见的最低子画面的底部。

+ (CGFloat) bottomOfLowestContent:(UIView*) view
{
    CGFloat lowestPoint = 0.0;

    BOOL restoreHorizontal = NO;
    BOOL restoreVertical = NO;

    if ([view respondsToSelector:@selector(setShowsHorizontalScrollIndicator:)] && [view respondsToSelector:@selector(setShowsVerticalScrollIndicator:)])
    {
        if ([(UIScrollView*)view showsHorizontalScrollIndicator])
        {
            restoreHorizontal = YES;
            [(UIScrollView*)view setShowsHorizontalScrollIndicator:NO];
        }
        if ([(UIScrollView*)view showsVerticalScrollIndicator])
        {
            restoreVertical = YES;
            [(UIScrollView*)view setShowsVerticalScrollIndicator:NO];
        }
    }
    for (UIView *subView in view.subviews)
    {
        if (!subView.hidden)
        {
            CGFloat maxY = CGRectGetMaxY(subView.frame);
            if (maxY > lowestPoint)
            {
                lowestPoint = maxY;
            }
        }
    }
    if ([view respondsToSelector:@selector(setShowsHorizontalScrollIndicator:)] && [view respondsToSelector:@selector(setShowsVerticalScrollIndicator:)])
    {
        if (restoreHorizontal)
        {
            [(UIScrollView*)view setShowsHorizontalScrollIndicator:YES];
        }
        if (restoreVertical)
        {
            [(UIScrollView*)view setShowsVerticalScrollIndicator:YES];
        }
    }

    return lowestPoint;
}

13
投票

这里是迅速的人谁是懒得把它转换接受的答案:)

var contentRect = CGRectZero
for view in self.scrollView.subviews {
    contentRect = CGRectUnion(contentRect, view.frame)
}
self.scrollView.contentSize = contentRect.size

8
投票

这里的@ leviatan的答案的斯威夫特3调整:

延期

import UIKit


extension UIScrollView {

    func resizeScrollViewContentSize() {

        var contentRect = CGRect.zero

        for view in self.subviews {

            contentRect = contentRect.union(view.frame)

        }

        self.contentSize = contentRect.size

    }

}

用法

scrollView.resizeScrollViewContentSize()

非常好用!


6
投票

下面的扩展将是斯威夫特的帮助。

extension UIScrollView{
    func setContentViewSize(offset:CGFloat = 0.0) {
        // dont show scroll indicators
        showsHorizontalScrollIndicator = false
        showsVerticalScrollIndicator = false

        var maxHeight : CGFloat = 0
        for view in subviews {
            if view.isHidden {
                continue
            }
            let newHeight = view.frame.origin.y + view.frame.height
            if newHeight > maxHeight {
                maxHeight = newHeight
            }
        }
        // set content size
        contentSize = CGSize(width: contentSize.width, height: maxHeight + offset)
        // show scroll indicators
        showsHorizontalScrollIndicator = true
        showsVerticalScrollIndicator = true
    }
}

逻辑是给定的答案是相同的。然而,它省略了UIScrollView内隐藏视图和计算后设置隐藏滚动指标进行。

此外,还有一个可选的功能参数,你就可以通过传递参数给函数添加的偏移值。


5
投票

从@leviathan大和最佳的解决方案。只需使用FP(函数式编程)的方式来转换迅速。

self.scrollView.contentSize = self.scrollView.subviews.reduce(CGRect(), { 
  CGRectUnion($0, $1.frame) 
}.size

4
投票

您可以通过计算进去的UIScrollView内容的高度子“达到进一步加强”。为了计算这个你必须要考虑到原点Y(启动)和项目的高度。

float maxHeight = 0;
for (UIView *child in scrollView.subviews) {
    float childHeight = child.frame.origin.y + child.frame.size.height;
    //if child spans more than current maxHeight then make it a new maxHeight
    if (childHeight > maxHeight)
        maxHeight = childHeight;
}
//set content size
[scrollView setContentSize:(CGSizeMake(320, maxHeight))];

通过这样做,让项目(子视图)不必直接堆叠在另一个。

© www.soinside.com 2019 - 2024. All rights reserved.