UIScrollView 的内容大小上的 SizeToFit
Posted
技术标签:
【中文标题】UIScrollView 的内容大小上的 SizeToFit【英文标题】:SizeToFit on a UIScrollView's content size 【发布时间】:2010-10-25 20:49:54 【问题描述】:UIView 有一个 SizeToFit 方法,它可以使 UIView 适合它的所有子视图。有没有类似的东西,它只会返回它计算的大小而不修改任何视图的框架。
我在 UIScrollView 上有几个子视图,我想对滚动视图的 contentSize 执行 SizeToFit,而不是它的框架。我必须在 contentSize 上做,因为我不想增加 UIScrollView 的“真实”大小,并且内容是动态异步加载的,所以当我将子视图添加到 UIScrollView 时我不能手动做.
【问题讨论】:
开始赏金。目前,我最好的答案是遍历子视图并查看它们的框架。我想知道是否有更好的方法。 SizeThatFits:似乎没有帮助。 尝试覆盖 sizeThatFits: 以进行所需的计算。 Swift extension 【参考方案1】:目前,这是我拥有的最好的:
CGRect contentRect = CGRectZero;
for (UIView *view in self.subviews)
contentRect = CGRectUnion(contentRect, view.frame);
self.contentSize = contentRect.size;
【讨论】:
这个方法很棒,但是......由于某种原因,如果手机处于横向模式,它对我不起作用。有什么想法吗? 如果滚动条设置为显示,此解决方案不考虑已经作为 UIScrollView 子视图存在的 UIImageViews(请参阅this SO post)。过滤掉这些的一种方法是将用户想要包含在 for 循环计算中的子视图的 tag 属性设置为相同的非零值,并使用 if 语句进行过滤。 @adamjansch 或使用isKindOfClass:
代替tag
s。或使用:[self.subviews filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"class = %@", [UILabel class]]];
- 不正确,因为它使用 class
而不是 isKindOfClass:
,但对于大多数用途来说已经足够了。【参考方案2】:
如果你的函数被频繁调用,你就不想每次都迭代子视图。相反,每当添加子视图时,将当前 contentSize 与新子视图的框架合并。
- (void)didAddSubview:(UIView *)subview
CGRect tmp;
tmp.origin = CGPointZero;
tmp.size = self.contentSize;
tmp = CGRectUnion(tmp,subview.frame);
self.contentSize = tmp.size;
【讨论】:
在某些情况下可能是一个很好的解决方案。不幸的是,我的子视图经常调整大小。所以就我而言,这不是一个好的解决方案。 @WilliamJockusch 如果子视图经常调整大小,您可以为frame
或bounds
添加一个KVO 观察者并相应地更新contentSize
。这会很棘手,但根据子视图的数量,可能是值得的。【参考方案3】:
在ScrollView ContentSize 找到了一个解决方案,您将能够找到子视图的大小并找到组合的内容大小,还可以选择说明子视图是水平排列还是垂直排列。
这是上面链接中的代码:
@interface UIScrollView(auto_size)
- (void) adjustHeightForCurrentSubviews: (int) verticalPadding;
- (void) adjustWidthForCurrentSubviews: (int) horizontalPadding;
- (void) adjustWidth: (bool) changeWidth andHeight: (bool) changeHeight withHorizontalPadding: (int) horizontalPadding andVerticalPadding: (int) verticalPadding;
@end
@implementation UIScrollView(auto_size)
- (void) adjustWidth: (bool) changeWidth andHeight: (bool) changeHeight withHorizontalPadding: (int) horizontalPadding andVerticalPadding: (int) verticalPadding
float contentWidth = horizontalPadding;
float contentHeight = verticalPadding;
for (UIView* subview in self.subviews)
[subview sizeToFit];
contentWidth += subview.frame.size.width;
contentHeight += subview.frame.size.height;
contentWidth = changeWidth ? contentWidth : self.superview.frame.size.width;
contentHeight = changeHeight ? contentHeight : self.superview.frame.size.height;
NSLog(@"Adjusting ScrollView size to %fx%f, verticalPadding=%d, horizontalPadding=%d", contentWidth, contentHeight, verticalPadding, horizontalPadding);
self.contentSize = CGSizeMake(contentWidth, contentHeight);
- (void) adjustHeightForCurrentSubviews: (int) verticalPadding
[self adjustWidth:NO andHeight:YES withHorizontalPadding:0 andVerticalPadding:verticalPadding];
- (void) adjustWidthForCurrentSubviews: (int) horizontalPadding
[self adjustWidth:YES andHeight:NO withHorizontalPadding:horizontalPadding andVerticalPadding:0];
@end
另外,请务必查看博客页面上的 cmets,因为它提供了替代解决方案。
-anoop
【讨论】:
【参考方案4】:我做了一个设置scrollView内容大小的功能试试看
首先编写这个函数...
-(void)setContentSizeOfScrollView:(UIScrollView*)scroll
CGRect rect = CGRectZero;
for(UIView * vv in [scroll subviews])
rect = CGRectUnion(rect, vv.frame);
[scroll setContentSize:CGSizeMake(rect.size.width, rect.size.height)];
然后在添加所有元素后调用此函数并将滚动视图作为参数传递.....
[self setContentSizeOfScrollView:self.YourScrollView];
我 100% 确信它会起作用.........
【讨论】:
【参考方案5】:这是 Swift 3.0 的答案
override func viewDidLayoutSubviews()
super.viewDidLayoutSubviews()
var contentRect: CGRect = CGRect.zero
for view in self.scrollView.subviews
debugPrint("view frame \(view.frame)")
contentRect = contentRect.union(view.frame)
debugPrint("frame \(contentRect)")
self.scrollView.contentSize = contentRect.size
debugPrint("content size \(self.scrollView.contentSize)")
【讨论】:
【参考方案6】:虽然William's answer 非常有用,但它并不能完美地工作,因为滚动条也是滚动视图的子视图。事实证明,诀窍是在计算内容大小之前隐藏它们。下面是 Swift 3 代码的样子:
override func viewDidLayoutSubviews()
scrollView.layoutSubviews()
// disable scrollbars so they don't interfere during resizing
scrollView.showsVerticalScrollIndicator = false
scrollView.showsHorizontalScrollIndicator = false
scrollView.contentSize = scrollView.subViewArea()
// re-enable the scrollbars
scrollView.showsVerticalScrollIndicator = true
scrollView.showsHorizontalScrollIndicator = true
您还需要在项目的某处添加以下扩展:
extension UIScrollView
func subViewArea() -> CGSize
var rect = CGRect.zero
for subview in subviews
rect = rect.union(subview.frame)
return rect.size
【讨论】:
【参考方案7】:将 UIView 放入具有相同宽度和高度的 UIScrollView 中,并将所有子视图添加到 IT 而不是滚动视图。然后将滚动视图上的 clipToBounds 属性设置为 TRUE,并在 UIView 上调用 sizeToFit。您还可以将 UIView 的背景的不透明度设置为 0,使其不可见,但仍显示其子视图。
【讨论】:
我刚刚意识到它应该是相反的:封闭视图应该是 UIView,而内部(更大)视图应该是透明的 UIScrollView。那么它应该可以工作了。 你确定吗,你在回答中写的有道理,我虽然知道你在那里所说的,但似乎有点“不恰当” 抱歉反应迟了...上周我在自己的项目中部分使用了上述解决方案。不幸的是,sizeToFit 似乎对 UIView 中的 UIScrollView 没有任何影响。因此,在将所有子视图添加到其中之后,我手动设置了它的 contentSize。这样做它甚至不再需要封闭的 UIView。 您可以使用 for 循环遍历 UIScrollView 的所有子视图并总结它们的宽度/高度属性,然后手动将滚动视图的 contentSize 设置为该值。【参考方案8】:在 swift 2.1 中,将其添加到您的视图控制器中:
override func viewDidLayoutSubviews()
super.viewDidLayoutSubviews()
let aggregateView = contentView.subviews.reduce(CGRect())
aggRect, view in aggRect.union(view.frame)
scrollView.contentSize = aggregateView.size
【讨论】:
【参考方案9】:联合框架大小来计算内容大小是不够的。因为有时,您的子视图需要重叠,有时您的子视图之间有边距。您必须知道并计算子视图的来源。
联合方法为 A 和 B 设计提供相同的内容高度。但是如果你知道最大的最后一个子视图,你可以计算出正确的内容高度:
这个扩展可以计算真实的内容高度。
extension UIScrollView
func adjustContentHeight(bottomPadding: Int = 0)
var lastSub: CGRect = .zero
self.subviews.forEach(
let sub = $0.frame
if(sub.maxY > lastSub.maxY)
lastSub = sub
)
self.contentSize.height = lastSub.maxY + CGFloat(bottomPadding)
【讨论】:
【参考方案10】:Swift 2 扩展:
用法:
scrollView.contentResize
scrollView.contentWidthResize
scrollView.contentHeightResize
extension UIScrollView
///Will resize content size to fit all subviews.
func contentResize()
var w = CGFloat(0)
var h = CGFloat(0)
for view in self.subviews
let fw = view.frame.origin.x + view.frame.width
let fh = view.frame.origin.y + view.frame.height
w = max(fw, w)
h = max(fh, h)
contentSize = CGSize(width: w, height: h)
///Will resize content width size to fit all subviews.
func contentWidthResize()
var w = CGFloat(0)
for view in self.subviews
let fw = view.frame.origin.x + view.frame.width
w = max(fw, w)
contentSize.width = w
///Will resize content height size to fit all subviews.
func contentHeightResize()
var h = CGFloat(0)
for view in self.subviews
let fh = view.frame.origin.y + view.frame.height
h = max(fh, h)
contentSize.height = h
【讨论】:
view.w
和 view.h
未定义为 mate。
@YoussefSami 已编辑...,如果您觉得有用,请考虑删除不赞成票并投票,感谢您提供的信息。以上是关于UIScrollView 的内容大小上的 SizeToFit的主要内容,如果未能解决你的问题,请参考以下文章