以编程方式从XIB调整自定义UIView的大小

时间:2015-03-23 08:10:41

标签: ios objective-c uiview resize autolayout

我遇到以下问题:我在UIView文件中创建了一个自定义XIB类及其布局。假设我在XIB中的自定义视图的大小是150 x 50.我启用了sizeClasses(wAny hAny)和AutoLayout。在模拟指标中,我设置了Size = FreeformStatus Bar = None,所有other = Inferred

我的自定义UIView类的代码如下所示:

#import "CustomView.h"

@implementation CustomView

#pragma mark - Object lifecycle

- (id)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];

    if (self) {
        [self setup];
    }

    return self;
}

- (id)initWithCoder:(NSCoder *)aDecoder {
    self = [super initWithCoder:aDecoder];

    if (self) {
        [self setup];
    }

    return self;
}

#pragma mark - Private & helper methods

- (void)setup {
    if (self.subviews.count == 0) {
        [[NSBundle mainBundle] loadNibNamed:@"CustomView" owner:self options:nil];
        self.bounds = self.view.bounds;
        [self addSubview:self.view];
    }
}

@end

在我要添加此自定义UIViewController的{​​{1}}中,我创建了虚拟UIView(我在Interface Builder中设置了这个大小),我想在其中添加UIView我希望我的CustomView符合容器视图的范围

我试图这样做:

CustomView

但没有运气。假设我的容器视图为300 x 100,当我向其添加自定义_vCustomView = [[CustomView alloc] init]; _vCustomView.translatesAutoresizingMaskIntoConstraints = NO; [_vContainer addSubview:_vCustomView]; [_vContainer addConstraint:[NSLayoutConstraint constraintWithItem:_vCustomView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:_vContainer attribute:NSLayoutAttributeLeft multiplier:1.0 constant:0.0]]; [_vContainer addConstraint:[NSLayoutConstraint constraintWithItem:_vCustomView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:_vContainer attribute:NSLayoutAttributeRight multiplier:1.0 constant:0.0]]; [_vContainer addConstraint:[NSLayoutConstraint constraintWithItem:_vCustomView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:_vContainer attribute:NSLayoutAttributeTop multiplier:1.0 constant:0.0]]; [_vContainer addConstraint:[NSLayoutConstraint constraintWithItem:_vCustomView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:_vContainer attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0.0]]; 时,我的自定义视图仍为150 x 50

我试图在没有容器视图的情况下工作 - 将我的自定义UIView对象直接添加到我的UIView的self.view中,并使用以下内容设置它的宽度和高度:

  • UIViewController约束
  • 在初始化自定义autoLayout
  • 时使用initWithFrame

但又一次 - 没有运气。自定义视图始终为150 x 50。

有人可以向我解释如何以编程方式添加UIView中的自定义UIView并使用XIB约束调整其大小?

非常感谢提前。

编辑#1:尝试在我的CustomView上运行Andrea代码时遇到错误

autoLayout

编辑#2:它有效!

@Andrea补充道:

Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) 
(
    "<NSLayoutConstraint:0x17489b760 V:[UIView:0x17418d820(91)]>",
    "<NSLayoutConstraint:0x170c9bf80 V:|-(0)-[CustomView:0x1741da7c0]   (Names: '|':CustomView:0x1741da8b0 )>",
    "<NSLayoutConstraint:0x170c9bfd0 V:[CustomView:0x1741da7c0]-(0)-|   (Names: '|':CustomView:0x1741da8b0 )>",
    "<NSLayoutConstraint:0x170c9be90 V:|-(0)-[CustomView:0x1741da8b0]   (Names: '|':UIView:0x17418d820 )>",
    "<NSLayoutConstraint:0x170c9bee0 CustomView:0x1741da8b0.bottom == UIView:0x17418d820.bottom>",
    "<NSAutoresizingMaskLayoutConstraint:0x170c9dba0 h=--& v=--& CustomView:0x1741da7c0.midY == + 25.0>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x170c9bfd0 V:[CustomView:0x1741da7c0]-(0)-|   (Names: '|':CustomView:0x1741da8b0 )>

在他的:

view.translatesAutoresizingMaskIntoConstraints = NO;

方法,一切都像我预期的那样。

感谢@Andrea。

3 个答案:

答案 0 :(得分:18)

我猜主要的问题是,当您将xib添加到内容视图中时,不要使用自动布局 在init方法中添加子视图后,请调用该方法,传递xib的视图:

- (void) stretchToSuperView:(UIView*) view {
    view.translatesAutoresizingMaskIntoConstraints = NO;
    NSDictionary *bindings = NSDictionaryOfVariableBindings(view);
    NSString *formatTemplate = @"%@:|[view]|";
    for (NSString * axis in @[@"H",@"V"]) {
        NSString * format = [NSString stringWithFormat:formatTemplate,axis];
        NSArray * constraints = [NSLayoutConstraint constraintsWithVisualFormat:format options:0 metrics:nil views:bindings];
        [view.superview addConstraints:constraints];
    }

}

<强> [编辑]
您的设置代码应如下所示:

- (void)setup {
    if (self.subviews.count == 0) {
        [[NSBundle mainBundle] loadNibNamed:@"CustomView" owner:self options:nil];
        self.bounds = self.view.bounds;
        [self addSubview:self.view];
        [self stretchToSuperView:self.view];
    }
}

注意我已添加view.translatesAutoresizingMaskIntoConstraints = NO;内部拉伸视图
[编辑2]
我会按照要求详细说明我的答案。使用autolayout,当您添加视图而不设置约束时,autolayout会自动将自动调整蒙版转换为约束,它们的默认属性为UIViewAutoresizingNone,这意味着不会自动调整大小。
您的XIB视图已添加到其父级而没有约束,并且没有自动大小的可能性,因此保持其原始大小。由于您希望视图根据视图调整大小,因此您有两种选择:

  • 将xib视图的自动调整遮罩更改为灵活的宽度和高度,但它们需要与父级相匹配,否则您将无法完整覆盖
  • 添加一些限制两个视图的约束,以相应地更改父更改。你在XIB视图和它的父视图之间实现了这个说法,尾随/前导和顶部/底部之间的空间是0.就像你在他们的边界上放了一些胶水。为此,您需要将自动转换大小调整掩码设置为NO,否则您可能会在日志中发布一些冲突。

您稍后要做的是将视图(托管XIB视图)的约束添加到其超级视图,但XIB与其父视图之间没有约束,因此autolayout不知道如何调整XIB视图的大小。
视图层次结构中的每个视图都应该有自己的约束。
希望这有助于更好地理解。

答案 1 :(得分:1)

在你的代码中你应该有这样的东西:

首先,要在viewController或IBOutlet中更改宽度约束的CustomView(我不知道你在哪里有逻辑来计算约束值)。

@property (nonatomic, weak) IBOutlet NSLayoutConstraint *widthConstraint;

然后,在你想要更新常数值的方法中,你会有这样的事情:

-(void)updateWidth {
    [self.widthConstraint setConstant:newConstant];
    [self.view layoutIfNeeded]; // self.view must be an ancestor of the view

    //If you need the changes animated, call layoutIfNeeded in an animation block
}

希望这适合你。祝你好运!

答案 2 :(得分:1)

Swift 4.0函数伸展到超级视图:

代码段:

static public func stretchToSuperView(view:UIView)
    {
        view.translatesAutoresizingMaskIntoConstraints = false
        var d = Dictionary<String,UIView>()
        d["view"] = view
        for axis in ["H","V"] {
            let format = "\(axis):|[view]|"
            let constraints = NSLayoutConstraint.constraints(withVisualFormat: format, options: NSLayoutFormatOptions(rawValue: 0), metrics: [:], views: d)
            view.superview?.addConstraints(constraints)
        }
    }

注意:只需使用参数作为子视图调用该函数。

这有助于我解决swift 4.0中的.xib resing问题。