如何自动调整UIScrollView的大小来适应内容
有没有办法使UIScrollView
自动调整到其滚动内容的高度(或宽度)?
就像是:
[scrollView setContentSize:(CGSizeMake(320, content.height))];
我曾遇到过的最好的方法来更新基于其子视图的UIScrollView
的内容大小:
CGRect contentRect = CGRectZero; for (UIView *view in self.scrollView.subviews) { contentRect = CGRectUnion(contentRect, view.frame); } self.scrollView.contentSize = contentRect.size;
UIScrollView自动不知道其内容的高度。 你必须为自己计算高度和宽度
用类似的东西来做
CGFloat scrollViewHeight = 0.0f; for (UIView* view in scrollView.subviews) { scrollViewHeight += view.frame.size.height; } [scrollView setContentSize:(CGSizeMake(320, scrollViewHeight))];
但是这只有在观点是一个在另一个之下的时候才有用。 如果您有一个彼此相邻的视图,则只需添加一个视图的高度,即使您不想将滚动条的内容设置得比实际大。
我把这个添加到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; }
解决scheme,如果您使用自动布局:
-
将涉及的所有视图设置为将“TransAutoresizingMaskIntoConstraints”
translatesAutoresizingMaskIntoConstraints
为“NO
”。 -
使用滚动视图外部的约束来定位和调整滚动视图的大小。
-
使用约束来布局滚动视图中的子视图, 确保约束与滚动视图的所有四个边连接,并且不依赖滚动视图来获取它们的大小。
来源: https : //developer.apple.com/library/ios/technotes/tn2154/_index.html
这是迅速接受的答案任何人都懒得转换它:)
var contentRect = CGRectZero for view in self.scrollView.subviews { contentRect = CGRectUnion(contentRect, view.frame) } self.scrollView.contentSize = contentRect.size
以下扩展将有助于Swift 。
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.hidden { 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
省略了隐藏的视图,隐藏了滚动指标后进行计算。
此外,还有一个可选的函数参数,您可以通过将parameter passing给函数来添加偏移值。
这里是@ leviatan的答案Swift 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()
非常好用!
你可以通过计算哪个孩子“进一步”来获得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))];
通过这样做,项目(子视图)不需要直接堆叠在一起。
来自@leviathan的最好和最好的解决scheme。 只需使用FP(函数式编程)方法即可快速翻译。
self.scrollView.contentSize = self.scrollView.subviews.reduce(CGRect(), { CGRectUnion($0, $1.frame) }.size
由于scrollView可以有其他的scrollViews或不同的inDepth子视图树,所以recursion运行深度优先。
Swift 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()
我提出了另一个基于@ emenegro解决scheme的解决scheme
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的填充
或者只是:
int y = CGRectGetMaxY(((UIView*)[_scrollView.subviews lastObject]).frame); [_scrollView setContentSize:(CGSizeMake(CGRectGetWidth(_scrollView.frame), y))];
(这个解决scheme是我在本页添加的,在得到19票的评论后,我决定增加这个解决scheme作为正式的答案,为了社区的利益!)
大小取决于内部加载的内容和剪辑选项。 如果它的textview,那么它也取决于包装,多less行文字,字体大小,等等。 你几乎不可能计算自己。 好消息是,它是在视图加载和viewWillAppear之后计算的。 在此之前,这一切都是未知的,内容大小将与帧大小相同。 但是,在viewWillAppear方法和之后(比如viewDidAppear),内容大小将是实际的。
包装Richy的代码我创build了一个自定义的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。
像这样设置dynamic内容大小。
self.scroll_view.contentSize = CGSizeMake(screen_width,CGRectGetMaxY(self.controlname.frame)+20);
它真的取决于内容:content.frame.height可能会给你你想要的? 取决于内容是单一的东西,还是一堆东西。
我也发现利维坦的答案是最好的。 但是,它正在计算一个奇怪的高度。 在循环浏览子视图时,如果将scrollview设置为显示滚动指示符,则这些指标将位于子视图数组中。 在这种情况下,解决方法是在循环之前临时禁用滚动指示器,然后重新build立以前的可见性设置。
-(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; }
我认为这可以是更新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 } }
为什么不单行代码?
_yourScrollView.contentSize = CGSizeMake(0, _lastView.frame.origin.y + _lastView.frame.size.height);