【发布时间】:2011-02-26 00:31:47
【问题描述】:
有没有办法让UIScrollView 自动调整到它正在滚动的内容的高度(或宽度)?
类似:
[scrollView setContentSize:(CGSizeMake(320, content.height))];
【问题讨论】:
标签: iphone ios objective-c cocoa-touch uiscrollview
有没有办法让UIScrollView 自动调整到它正在滚动的内容的高度(或宽度)?
类似:
[scrollView setContentSize:(CGSizeMake(320, content.height))];
【问题讨论】:
标签: iphone ios objective-c cocoa-touch uiscrollview
import UIKit
class DynamicSizeScrollView: UIScrollView {
var maxHeight: CGFloat = UIScreen.main.bounds.size.height
var maxWidth: CGFloat = UIScreen.main.bounds.size.width
override func layoutSubviews() {
super.layoutSubviews()
if !__CGSizeEqualToSize(bounds.size,self.intrinsicContentSize){
self.invalidateIntrinsicContentSize()
}
}
override var intrinsicContentSize: CGSize {
let height = min(contentSize.height, maxHeight)
let width = min(contentSize.height, maxWidth)
return CGSize(width: width, height: height)
}
}
【讨论】:
我遇到过的根据包含的子视图更新UIScrollView 的内容大小的最佳方法:
Objective-C
CGRect contentRect = CGRectZero;
for (UIView *view in self.scrollView.subviews) {
contentRect = CGRectUnion(contentRect, view.frame);
}
self.scrollView.contentSize = contentRect.size;
斯威夫特
let contentRect: CGRect = scrollView.subviews.reduce(into: .zero) { rect, view in
rect = rect.union(view.frame)
}
scrollView.contentSize = contentRect.size
【讨论】:
viewDidLayoutSubviews 中运行它,所以自动布局会完成,在 iOS7 中它运行良好,但是由于某种原因测试 os iOS6 自动布局没有完成工作,所以我的高度有些错误值,所以我切换到viewDidAppear 现在工作正常.. 只是指出也许有人需要这个。谢谢
以下扩展将有助于 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.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 中的隐藏视图,并且在滚动指示器设置为隐藏后执行计算。
此外,还有一个可选的函数参数,您可以通过将参数传递给函数来添加偏移值。
【讨论】:
对于使用 reduce 的 swift4:
self.scrollView.contentSize = self.scrollView.subviews.reduce(CGRect.zero, {
return $0.union($1.frame)
}).size
【讨论】:
这是对@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()
非常容易使用!
【讨论】:
因为一个scrollView可以有其他scrollViews或者不同的inDepth subViews树,递归深度运行是更可取的。
斯威夫特 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()
【讨论】:
来自@leviathan 的出色和最佳解决方案。只需使用 FP(函数式编程)方法翻译成 swift。
self.scrollView.contentSize = self.scrollView.subviews.reduce(CGRect(), {
CGRectUnion($0, $1.frame)
}.size
【讨论】:
self.contentSize = self.subviews.reduce(CGRect(), { $0.union($1.frame) }).size
像这样设置动态内容大小。
self.scroll_view.contentSize = CGSizeMake(screen_width,CGRectGetMaxY(self.controlname.frame)+20);
【讨论】:
对于那些懒得转换它的人来说,这是迅速接受的答案:)
var contentRect = CGRectZero
for view in self.scrollView.subviews {
contentRect = CGRectUnion(contentRect, view.frame)
}
self.scrollView.contentSize = contentRect.size
【讨论】:
为什么不是单行代码??
_yourScrollView.contentSize = CGSizeMake(0, _lastView.frame.origin.y + _lastView.frame.size.height);
【讨论】:
或者干脆做:
int y = CGRectGetMaxY(((UIView*)[_scrollView.subviews lastObject]).frame); [_scrollView setContentSize:(CGSizeMake(CGRectGetWidth(_scrollView.frame), y))];
(此解决方案是我在此页面中添加的评论。在获得 19 票赞成此评论后,我决定将此解决方案添加为正式答案,以造福社区!)
【讨论】:
我认为这可能是一种更新 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
}
}
【讨论】:
我还发现 leviathan 的回答效果最好。然而,它正在计算一个奇怪的高度。循环遍历子视图时,如果将滚动视图设置为显示滚动指示器,则它们将位于子视图数组中。在这种情况下,解决方案是在循环之前暂时禁用滚动指示器,然后重新建立它们之前的可见性设置。
-(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;
}
【讨论】:
我根据@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 的内边距
【讨论】:
在所有涉及的视图上将translatesAutoresizingMaskIntoConstraints 设置为NO。
使用滚动视图外部的约束来定位和调整滚动视图的大小。
使用约束在滚动视图中布置子视图,确保约束绑定到滚动视图的所有四个边缘,并且不要依赖滚动视图来获取它们大小。
来源: https://developer.apple.com/library/ios/technotes/tn2154/_index.html
【讨论】:
您可以通过计算哪个孩子“到达更远”来获取 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))];
通过这种方式,项目(子视图)不必直接堆叠在另一个之下。
【讨论】:
我将此添加到 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;
}
【讨论】:
self.scrollView.showsHorizontalScrollIndicator = NO;self.scrollView.showsVerticalScrollIndicator = NO;和self.scrollView.showsHorizontalScrollIndicator = YES;self.scrollView.showsVerticalScrollIndicator = YES;的结尾?
包装 Richy 的代码我创建了一个自定义 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 实例。
【讨论】:
大小取决于其中加载的内容和剪辑选项。如果它是一个文本视图,那么它还取决于换行、文本行数、字体大小等等。你几乎不可能自己计算。好消息是,它是在视图加载后在 viewWillAppear 中计算的。在此之前,一切都是未知的,并且内容大小将与帧大小相同。但是,在 viewWillAppear 方法和之后(例如 viewDidAppear),内容大小将是实际的。
【讨论】:
UIScrollView 不会自动知道其内容的高度。你必须自己计算高度和宽度
用类似的东西来做
CGFloat scrollViewHeight = 0.0f;
for (UIView* view in scrollView.subviews)
{
scrollViewHeight += view.frame.size.height;
}
[scrollView setContentSize:(CGSizeMake(320, scrollViewHeight))];
但这只有在视图低于另一个时才有效。如果您有一个相邻的视图,并且您不想将滚动条的内容设置为大于实际值,则只需添加一个的高度。
【讨论】:
int y = CGRectGetMaxY(((UIView*)[_scrollView.subviews lastObject]).frame); [_scrollView setContentSize:(CGSizeMake(CGRectGetWidth(_scrollView.frame), y))];
这真的取决于内容: content.frame.height 可能会给你你想要的?取决于内容是单个事物还是事物的集合。
【讨论】: