带有 iOS 自动布局约束的 UIScrollView:子视图的大小错误 [英] UIScrollView with iOS Auto Layout Constraints: Wrong size for subviews

查看:35
本文介绍了带有 iOS 自动布局约束的 UIScrollView:子视图的大小错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在代码中生成视图.这是我的视图对象的层次结构

I'm trying to generate a view in code. Here's the hierachy of my view object

  • UIScrollView
    • UIView
      • 界面按钮

      ScrollView 应该与窗口大小相同.按钮应尽可能大.我正在使用 iOS 自动布局,所以我所有对象的约束字符串看起来像这样

      The ScrollView should be the same size as the window. The button should be as big as possible. I'm using iOS auto layout, so the constraint strings for all of my objects look like this

      H:|[object]|
      V:|[object]|
      

      我还将每个对象的 translatesAutoresizingMaskIntoConstraints 设置为 NO.

      I've also set translatesAutoresizingMaskIntoConstraints to NO for each object.

      问题是按钮只获得默认按钮大小.它的父视图对象 (UIView) 仅获得其子视图所需的大小.

      The problem is that the button only gets the default button-size. Its parent view object (UIView) only gets the size its subviews need.

      红色:UIScrollView/黄色:UIView

      如何强制这些视图与滚动视图一样大?

      How can I force those views to be as big as the scrollView?

      当我使用 UIView 而不是 UIScrollView 时,一切都很好......

      When I use a UIView instead of th UIScrollView everything works great...

      这里有一些代码:

          - (void) viewDidLoad {
      
              [super viewDidLoad];
      
              // SCROLL VIEW
              UIScrollView* scrollView = [UIScrollView new];
              scrollView.backgroundColor=[UIColor redColor];
              scrollView.translatesAutoresizingMaskIntoConstraints = NO;
      
              //CONTAINER VIEW
              UIView *containerView = [UIView new];
              containerView.translatesAutoresizingMaskIntoConstraints = NO;
              containerView.backgroundColor = [UIColor yellowColor];
              [scrollView addSubview:containerView];
      
              // CONSTRAINTS SCROLL VIEW - CONTAINER VIEW
              [scrollView addConstraints:
               [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[containerView]|"
                                                       options:0 metrics:nil
                                                         views:@{@"containerView":containerView}]];
              [scrollView addConstraints:
               [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[containerView]|"
                                                       options:0 metrics:nil
                                                         views:@{@"containerView":containerView}]];
      
              // BUTTON
              UIButton* button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
              button.translatesAutoresizingMaskIntoConstraints = NO;
              [button setTitle:@"I'm way to small" forState:UIControlStateNormal];
              [containerView addSubview:button];
      
              // CONSTRAINTS CONTAINER VIEW - BUTTON
              [containerView addConstraints:
               [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[button]|"
                                                       options:0 metrics:nil
                                                         views:@{@"button":button}]];
              [containerView addConstraints:
               [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[button]|"
                                                       options:0 metrics:nil
                                                         views:@{@"button":button}]];
              self.view = scrollView;
      
          }
      

      更新:我真的不知道,为什么会这样.如果您在 IB 中设置视图,连接插座并在代码中实例化视图,则滚动视图的行为类似于普通视图(垂直反弹).它的 contentSize 计算不正确.更多这里.但是如何正确做呢?

      UPDATE: I really don't know, why this is happening. If you set up the view in IB, connect the outlets and instanciate the view in code, the scrollview behaves like a normal view (which bounces vertically). Its contentSize is not calculated correctly. More here. But how to do it correctly?

      推荐答案

      几点观察:

      1. 滚动视图中子视图的约束与其他视图中的约束不同.它们用于设置滚动视图的 contentSize.(请参阅 TN2154.)那样,您会在滚动视图上扔一堆东西,为里面的东西设置约束,contentSize 会为你计算出来.这是一个非常酷的功能,但它与您在这里尝试做的事情背道而驰.

      1. Constraints for subviews in scroll views don't work like constraints in other views. They're used to set the contentSize of the scroll view. (See TN2154.) That way, you throw a bunch of stuff on a scroll view, set the constraints for the stuff inside it, and the contentSize is calculated for you. It's very cool feature, but it's antithetical to what you're trying to do here.

      更糟糕的是,除非您为按钮的宽度和高度设置明确的约束,否则按钮将根据其内容调整大小.

      Worse, buttons will, unless you set an explicit constraint for their width and height of a button, will resize according to their content.

      这两个观察结果的最终结果是您现有的约束说(a)将我的容器设置为我的按钮的大小;(b)让我的按钮动态调整自身大小以适应文本的大小;和(c) 根据我的容器大小(也就是按钮的大小)设置我的滚动视图的 contentSize."

      The net effect of these two observations is that your existing constraints say "(a) set my container to be the size of my button; (b) let my button resize itself dynamically to the size of the text; and (c) set my scrollview's contentSize according to the size of my container (which is the size of the button)."

      我不清楚业务问题是什么.但是这里有一些限制可以实现我认为您的技术问题是:

      I'm unclear as to what the business problem is. But here are some constraints that achieve what I think your technical question was:

      - (void)viewDidLoad
      {
          [super viewDidLoad];
      
          UIView *view = self.view;
      
          UIScrollView *scrollView = [[UIScrollView alloc] init];
          scrollView.backgroundColor = [UIColor redColor]; // just so I can see it
          scrollView.translatesAutoresizingMaskIntoConstraints = NO;
          [self.view addSubview:scrollView];
      
          UIView *containerView = [[UIView alloc] init];
          containerView.backgroundColor = [UIColor yellowColor]; // just so I can see it
          containerView.translatesAutoresizingMaskIntoConstraints = NO;
          [scrollView addSubview:containerView];
      
          UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
          button.translatesAutoresizingMaskIntoConstraints = NO;
          [button setTitle:@"I'm the right size" forState:UIControlStateNormal];
          [containerView addSubview:button];
      
          NSDictionary *views = NSDictionaryOfVariableBindings(scrollView, button, view, containerView);
      
          // set the scrollview to be the size of the root view
      
          [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[scrollView]|"
                                                                            options:0
                                                                            metrics:nil
                                                                              views:views]];
      
          [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[scrollView]|"
                                                                            options:0
                                                                            metrics:nil
                                                                              views:views]];
      
          // set the container to the size of the main view, and simultaneously
          // set the scrollview's contentSize to match the size of the container
      
          [view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[containerView(==view)]|"
                                                                             options:0
                                                                             metrics:nil
                                                                               views:views]];
      
          [view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[containerView(==view)]|"
                                                                             options:0
                                                                             metrics:nil
                                                                               views:views]];
      
          // set the button size to be the size of the container view
      
          [containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[button(==containerView)]"
                                                                                options:0
                                                                                metrics:nil
                                                                                  views:views]];
      
          [containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[button(==containerView)]"
                                                                                options:0
                                                                                metrics:nil
                                                                                  views:views]];
      
      }
      

      坦率地说,我不了解您的 UI 的商业意图,因为这感觉像是为了实现非常简单的 UI 而对自动布局进行了扭曲.如果您有屏幕大小"的内容(除非您通过按钮分页),我不知道为什么您有滚动视图.我不知道为什么你会有一个包含单个项目的内容视图.我不明白你为什么要使用全屏按钮(当时我只是在根视图上放了一个点击手势,然后就结束了).

      Frankly, I don't understand the business intent of your UI, as this feels like a contortion of auto layout to achieve a very simply UI. I don't know why you have a scroll view if you have "screen sized" content in it (unless you were paging through buttons). I don't know why you'd have a content view with a single item in it. I don't understand why you're using a full-screen button (I'd just put a tap gesture on the root view at that point and call it a day).

      我假设您有充分的理由这样做,但备份可能是有意义的,询问您想要的用户体验是什么,然后重新解决问题,看看是否有更有效的方法来实现想要的效果.

      I'll assume you have good reasons for all of this, but it might make sense to back up, ask what is your desired user experience is, and then approach the problem fresh to see if there's a more efficient way to achieve the desired effect.

      这篇关于带有 iOS 自动布局约束的 UIScrollView:子视图的大小错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆