【问题标题】:SizeToFit on a UIScrollView's content sizeUIScrollView 的内容大小上的 SizeToFit
【发布时间】:2010-10-25 20:49:54
【问题描述】:

UIView 有一个 SizeToFit 方法,它可以使 UIView 适合它的所有子视图。有没有类似的东西,它只会返回它计算的大小而不修改任何视图的框架。

我在 UIScrollView 上有几个子视图,我想对滚动视图的 contentSize 执行 SizeToFit,而不是它的框架。我必须在 contentSize 上做,因为我不想增加 UIScrollView 的“真实”大小,并且内容是动态异步加载的,所以当我将子视图添加到 UIScrollView 时我不能手动做.

【问题讨论】:

  • 开始赏金。目前,我最好的答案是遍历子视图并查看它们的框架。我想知道是否有更好的方法。 SizeThatFits:似乎没有帮助。
  • 尝试覆盖 sizeThatFits: 以进行所需的计算。

标签: objective-c uiview uiscrollview


【解决方案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: 代替tags。或使用:[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 如果子视图经常调整大小,您可以为framebounds 添加一个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.wview.h 未定义为 mate。
              • @YoussefSami 已编辑...,如果您觉得有用,请考虑删除不赞成票并投票,感谢您提供的信息。
              猜你喜欢
              • 2012-02-17
              • 1970-01-01
              • 1970-01-01
              • 2020-05-05
              • 1970-01-01
              • 1970-01-01
              • 2021-03-29
              • 2011-11-11
              相关资源
              最近更新 更多