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

Ios 从XIB以编程方式调整自定义UIView的大小,ios,objective-c,uiview,resize,autolayout,Ios,Objective C,Uiview,Resize,Autolayout,我有以下问题:我在XIB文件中创建了一个自定义UIView类及其布局。假设我的自定义视图在XIB中的大小是150 x 50。我已经启用了sizeClasses(wAny hAny)和AutoLayout。在模拟度量中,我设置了Size=Freeform,Status Bar=None,allother=推断的 我的自定义UIView类中的代码如下所示: #import "CustomView.h" @implementation CustomView #pragma mark - Objec

我有以下问题:我在
XIB
文件中创建了一个自定义
UIView
类及其布局。假设我的自定义视图在XIB中的大小是150 x 50。我已经启用了
sizeClasses
(wAny hAny)和
AutoLayout
。在模拟度量中,我设置了
Size=Freeform
Status Bar=None
,all
other=推断的

我的自定义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
_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]];
-(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
}
在我的
UIViewController
中,我想添加这个自定义的
UIView
,我制作了一个虚拟UIView(我在Interface Builder中设置了它的大小),在这里我想添加我的
CustomView
,并且我希望我的
CustomView
符合我的容器视图的范围

我试着这样做:

#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
_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]];
-(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
}
但是没有运气。假设我的容器视图是300 x 100,当我将自定义
UIView
添加到其中时,我的自定义视图仍然是150 x 50

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

  • 自动布局
    约束
  • 在初始化我的自定义
    ui视图时使用
    initWithFrame
但同样,运气不好。自定义视图始终为150 x 50

有人能向我解释一下,我如何通过编程方式添加在
XIB
中制作的自定义
UIView
,并使用
autoLayout
约束调整其大小吗

非常感谢

编辑#1:尝试在我的CustomView上运行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 )>
在他的报告中:

- (void) stretchToSuperView:(UIView*) view;
方法,一切都像我预期的那样


多亏了@Andrea.

我想主要的问题是在将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];
    }

}
[编辑]
您的设置代码应该如下所示:

请注意,我在拉伸视图中添加了
view.translatesAutoResizezingMacSkinToConstraints=NO

[编辑2]
我会按要求详细说明我的答案。使用autolayout,当您添加视图而不设置约束时,autolayout会自动将自动调整大小的遮罩转换为约束,其默认属性为
UIViewAutoResizingOne
,表示不自动调整大小。
您的XIB视图被添加到其父视图中,没有任何约束,也不可能自动调整大小,从而保持其原始大小。由于您希望视图根据视图调整大小,因此有两种选择:

  • 将xib视图的自动调整大小遮罩更改为灵活的宽度和高度,但它们需要与父级大小匹配,否则将无法获得完整的遮罩
  • 添加一些约束,约束两个视图根据父视图的更改进行相应的更改。在XIB视图和它的父视图之间,尾随/前导和顶部/底部之间的空间是0。就像你在他们的边界上涂上胶水一样。要做到这一点,您需要将自动转换大小调整掩码设置为“约束”为“否”,否则在日志中发布时可能会出现一些冲突。


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

在代码中,您应该有如下内容:

#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
_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]];
-(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
}
首先,将
IBOutlet
添加到要更改的宽度约束,无论是在viewController中还是在
CustomView
中(我真的不知道您在哪里有计算约束值的逻辑)

然后,在要更新常量值的方法中,您将得到如下内容:

#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
_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]];
-(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
}

希望这对你有用。祝你好运

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)
        }
    }
静态公共函数stretchToSuperView(视图:UIView) { view.translatesAutoresizingMaskIntoConstraints=false var d=字典() d[“视图”]=视图 对于[“H”、“V”轴]{ let format=“\(轴):|[视图]|” let constraints=NSLayoutConstraint.constraints(带VisualFormat:format,选项:NSLayoutFormatOptions(rawValue:0),度量:[:],视图:d) view.superview?.addConstraints(约束) } }
注意:只需使用参数作为子视图调用函数


这有助于我解决swift 4.0中的.xib重新调整问题。

在对约束进行更改后,是否调用
layoutifneed
?你能把代码贴在你改变宽度和高度的地方吗?此外,如果视图在情节提要中具有高度和宽度约束,则将约束添加到
contentView
将使约束崩溃,因为它们将相互冲突。@CatalinaT。谢谢你的回答。我没有打电话给layoutifneed,但我现在已经试过了,没有任何变化_vContainer是位于屏幕中央的虚拟视图。我的想法是将我的CustomView添加到该虚拟视图中,并且我的CustomView具有与虚拟视图相同的大小。这就是为什么我在上面写了4个约束,我说我的CustomView应该与dummy view的所有四个边对齐。间接地,我用这种方式设置CustomView的宽度和高度。但是,没有运气。CustomView的大小始终与XIB(150 x 50)相同。我写了vCustomView.translatesAutoResizezingmaskintoConstraints=NO;在我添加Cu之前