使用自动布局来设置dynamicUIView以匹配容器视图

我有一个UIView在IB中有另一个UIView,我用它作为一个容器视图。 在代码中,我创build了三个不同的视图,然后根据应用程序的状态将适当的视图animation到容器的视图中。 三种不同意见中,只有一种在任何时候都是有效的。 问题是,当我在模拟器中运行不同的iPhone时,我的新的子视图不能缩放以匹配容器视图。 我正在使用自动布局。 出于testing目的,我已经设置了我的子视图,只是一个大的button,它的边缘限制在超级视图。 而容器视图也有它的边界限制到它的超视图。 我想要的是子视图匹配容器的视图。 即button拉伸容器视图的整个大小。 当在不同的iPhone上运行时,容器视图的大小以及子视图的大小应相对于不同iPhone的屏幕大小成比例地缩放。

下面是我用来初始化我的子视图的代码,并设置它相对于容器视图的约束。

UIView *containerView = self.subView; UIView *newSubview = [[mySubview alloc] init]; [newSubview setTranslatesAutoresizingMaskIntoConstraints:NO]; [self.containerView addSubview:newSubview]; [self.containerView addConstraint:[NSLayoutConstraint constraintWithItem:newSubview attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.containerView attribute:NSLayoutAttributeTop multiplier:1.0 constant:0]]; [self.containerView addConstraint:[NSLayoutConstraint constraintWithItem:newSubview attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.containerView attribute:NSLayoutAttributeLeading multiplier:1.0 constant:0]]; [self.containerView addConstraint:[NSLayoutConstraint constraintWithItem:newSubview attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self.containerView attribute:NSLayoutAttributeWidth multiplier:1.0 constant:0]]; [self.containerView addConstraint:[NSLayoutConstraint constraintWithItem:newSubview attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self.containerView attribute:NSLayoutAttributeHeight multiplier:1.0 constant:0]]; 

我似乎无法得到这个工作。 我对自动布局相当陌生,不确定自己做错了什么,并且想停止撞击这堵墙。 任何帮助将是了不起的。 🙂


************* 附加信息 **************


对不起,我没有尽我所能清楚说明我的问题。 所以这里有更多关于屏幕截图的信息。 首先,我将描述我在代码方面做了什么。

在AppDelegate.m中的didFinishLaunchingWithOptions中,我创build了MyViewController,

 self.myViewController = [[MyViewController alloc] initWithNibName:@"MyViewController" bundle:nil]; 

在MyViewController.m中的viewDidLoad中,我创build了mySubview并将其添加到我的containerView中,并为其创build约束,

 UIView *containerView = self.containerView; UIView *mySubview = [[MySubview alloc] init]; [mySubview setTranslatesAutoresizingMaskIntoConstraints:NO]; [containerView addSubview:mySubview]; NSDictionary *views = NSDictionaryOfVariableBindings(mySubview); [containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[mySubview]|" options:0 metrics:nil views:views]]; [containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[mySubview]|" options:0 metrics:nil views:views]]; 

最后,在MySubview.h的init中,我将nib添加为这样的子视图,

 - (id)init { if(self = [super init]) { NSArray *nibArray = [[NSBundle mainBundle]loadNibNamed:@"MySubview" owner:self options:nil]; [self addSubview:[nibArray objectAtIndex:0]]; } return self; } 

有几件事要注意,可能会有所帮助,

在MyViewController.xib中,我有一个UIView作为containerView使用。 它有一个IBOutlet UIView * containerView,是上面引用的一个。 我在IB中对containerView的唯一约束是,领先,尾随和底部空间到Superview和顶部空间到Superview = 44。

对于MySubview.xib,高度和宽度是300,(高度或宽度没有限制)。 我觉得这些尺寸应该不重要,因为mySubview应该被限制到containerView。

在MySubview.xib中,我有3个对象,topButton:height = 29,middleView:height = 242和bottomButton:height = 29.(参见附图)TopButton的引导,拖尾和顶部到Superview约束和bottom到middleView约束。 MiddleView具有超前视图约束和顶部到顶部button约束以及底部到底部button约束。 最后bottomButton具有前导,尾随和底部到Superview约束和顶部到中间视图约束。

我想要发生的是mySubview缩放以适应containerView,因为约束已经被创build和添加,相反,mySubview变得非常大,并剪辑containerView。

以下是一些屏幕截图:

MyViewController.xib,标题下方的蓝色矩形是我的容器视图,并具有IBOutlet容器视图。

http://i33.tinypic.com/14o3lmd.png

MySubview.xib

http://i37.tinypic.com/344ukk3.png

最后,结果是错误的。

http://i34.tinypic.com/nbyqua.png

相反,我会想这个,我已经伪造,只是为了获得屏幕截图。

在iPhone 4上,

http://tinypic.com/r/w9fp5e/4

在iPhone 5上,

http://tinypic.com/r/2z8nldv/4

正如你可以在假屏幕截图中看到的,即使containerView缩放了一下以调整不同的手机屏幕尺寸,mySubview也会缩放以适应containerView。

希望我没有过多的信息。 任何帮助将是了不起的。 我觉得我很接近,但是必须失去一个关键的一步。 Grrrrr。

一些想法:

  1. 这基本上看起来不错,除了一些variables名称怪异:您的本地variables, containerView等于self.subView ,但所有其他行引用不同的variables,一个类属性, self.containerView 。 您是否忽略了设置containerView类属性的行? 但是当我解决这个问题时,你的代码对我来说工作得很好。

  2. 确保在设置约束后不要立即查看frame ,因为更改不会反映在frame设置中。 你可以做一个[containerView layoutIfNeeded]; 如果你想迫使它基于约束重新布置一切。 此外,如果你想确认frame设置,最好延迟查看这些值,直到viewDidAppear (即viewDidLoad在视图构build过程中为时尚早)。

  3. 在你的代码(和你的问题无关),但是当我设置容器视图中的约束,我经常会设置不仅NSLayoutAttributeTopNSLayoutAttributeLeading ,就像你做的,但也NSLayoutAttributeBottomNSLayoutAttributeTrailing (而不是NSLayoutAttributeWidthNSLayoutAttributeHeight )。 它与你的代码完成同样的事情,但是当使用非零值时,它是一个更直观的分数。

    无论如何,我只是做了下面的代码,排列你的,它工作正常:

     - (IBAction)didTouchUpInsideAddView:(id)sender { UIView *containerView = self.containerView; UIView *newSubview = [[UIView alloc] initWithFrame:CGRectZero]; // initializing with CGRectZero so we can see it change newSubview.translatesAutoresizingMaskIntoConstraints = NO; newSubview.backgroundColor = [UIColor lightGrayColor]; [containerView addSubview:newSubview]; [containerView addConstraint:[NSLayoutConstraint constraintWithItem:newSubview attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:containerView attribute:NSLayoutAttributeTop multiplier:1.0 constant:0.0]]; [containerView addConstraint:[NSLayoutConstraint constraintWithItem:newSubview attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:containerView attribute:NSLayoutAttributeLeading multiplier:1.0 constant:0.0]]; [containerView addConstraint:[NSLayoutConstraint constraintWithItem:newSubview attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:containerView attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0.0]]; [containerView addConstraint:[NSLayoutConstraint constraintWithItem:newSubview attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:containerView attribute:NSLayoutAttributeTrailing multiplier:1.0 constant:0.0]]; // the frame is still `CGRectZero` at this point NSLog(@"newSubview.frame before = %@", NSStringFromCGRect(newSubview.frame)); // if not doing this in `viewDidLoad` (eg you're doing this in // `viewDidAppear` or later), you can force `layoutIfNeeded` if you want // to look at `frame` values. Generally you don't need to do this unless // manually inspecting `frame` values or when changing constraints in a // `animations` block of `animateWithDuration`. [containerView layoutIfNeeded]; // everything is ok here NSLog(@"containerView.bounds after = %@", NSStringFromCGRect(containerView.bounds)); NSLog(@"newSubview.frame after = %@", NSStringFromCGRect(newSubview.frame)); } 
  4. 您可以使用视觉格式语言简化一些代码,例如:

     NSDictionary *views = NSDictionaryOfVariableBindings(newSubview); [containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[newSubview]|" options:0 metrics:nil views:views]]; [containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[newSubview]|" options:0 metrics:nil views:views]]; 

    我发现使用可视化格式语言很容易获得约束。 less一点错误倾向(至less对我而言)。 但是,有一些约束无法用视觉格式语言来表示,在这种情况下,我会回到您所概述的语法。

  5. 在你修改的问题中,你向我们展示了一个你的子视图的init方法,它还有一个 addSubview 。 你也必须在那里设置约束。 底线,无论你做什么addSubview ,你必须设置你的约束,例如

     - (id)init { if(self = [super init]) { NSArray *nibArray = [[NSBundle mainBundle]loadNibNamed:@"MySubview" owner:self options:nil]; UIView *subview = [nibArray objectAtIndex:0]; subview.translatesAutoresizingMaskIntoConstraints = NO; [self addSubview:subview]; NSDictionary *views = NSDictionaryOfVariableBindings(subview); [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[subview]|" options:0 metrics:nil views:views]]; [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[subview]|" options:0 metrics:nil views:views]]; } return self; } 

在这个问题中,你声明“我的新的子视图不能缩放到与容器视图匹配” – 但是从我认为它们的描述来看 – 问题是你的容器视图没有固定的大小。

我认为如果你设置你的容器视图有一个固定的宽度和高度应该这样做,你可能还需要调用

 [self.containerView layoutSubviews] 

在更新约束后强制resize。

我也build议你交换使用基于文本的格式,你可以换出上面的行,像“H:| [newSubview] |” 和“V:| [newSubview] |”