2015-03-23 3 views
12

У меня есть следующая проблема: Я создал пользовательский класс UIView и его расположение в файле XIB. Предположим, что размер моего пользовательского представления в XIB составляет 150 x 50. Я включил sizeClasses (wAny hAny) и AutoLayout. В моделируемых показателях я установил Size = Freeform, Status Bar = None, все other = Inferred.Программно изменить размер пользовательского UIView из XIB

код из моего класса пользовательского 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 где я хочу, чтобы добавить этот обычай UIView, я сделал манекен UIView (размер которых я поставил в Interface Builder), где I хочу добавить CustomView и Я бы хотел, чтобы мой CustomView соответствовал границам моего вида контейнера.

Я пытаюсь сделать это так:

_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]]; 

но не повезло. Предположим, что мой контейнерный вид - 300 x 100, когда я добавляю свой пользовательский UIView, мой пользовательский вид по-прежнему 150 x 50.

Я пытался работать без вида контейнера - добавить мой пользовательский объект UIView непосредственно self.view моего UIViewController и установить его ширину и высоту с:

  • autoLayout ограничений
  • с помощью initWithFrame когда инициализация моего заказа UIView

но опять же - не повезло. Пользовательский вид всегда 150 х 50.

Может кто-нибудь объяснить мне, как я могу программно добавить мой заказ UIView сделал в XIB и изменить его с помощью autoLayout ограничений?

Большое спасибо заранее.

Edit # 1: Ошибка я получаю при попытке запуска кода Андреа на моей CustomView

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)> 

Edit # 2: Это работает!

После @Andrea добавил:

view.translatesAutoresizingMaskIntoConstraints = NO; 

в его:

- (void) stretchToSuperView:(UIView*) view; 

метод, все работает, как я ожидал.

Благодаря @Andrea.

+0

Вы вызываете 'layoutIfNeeded' после внесения изменений в ограничения? Не могли бы вы разместить код, в котором вы измените ширину и высоту? Кроме того, если представление имеет ограничения высоты и ширины в раскадровке, добавление ограничений в 'contentView' приведет к сбою ограничений, поскольку они будут противоречивыми. –

+0

@CatalinaT. Спасибо за ваш ответ. Я не называл layoutIfNeeded, но теперь я попытался с ним, он не вносит никаких изменений. _vContainer - это фиктивный вид, который находится в центре экрана. Моя идея состоит в том, чтобы добавить мой CustomView в это фиктивное представление и что мой CustomView имеет тот же размер, что и фиктивный вид. Вот почему я написал четыре ограничения выше, где я говорю, что мой CustomView должен быть выровнен со всеми четырьмя сторонами фиктивного представления. Косвенно, я устанавливаю ширину и высоту CustomView таким образом. Но, не повезло. CustomView всегда имеет тот же размер, что и XIB (150 x 50). – uerceg

ответ

16

Я полагаю, что основная проблема заключается в том, что вы не используете автоматическую компоновку при добавлении xib в представление контента.
После добавления подвид в вас инициализации методы пожалуйста вызвать этот метод, передавая вид на 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]; 
    } 

} 

[EDIT]
Ваш код установки должен выглядеть так:

- (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;
[EDIT 2]
Я попробую уточнить свой ответ в соответствии с просьбой. Использование автоопределения при добавлении представления без ограничений по умолчанию автозапуск автоматически преобразует авторезистирующие маски в ограничения, по умолчанию их свойство равно UIViewAutoresizingNone, что означает, что вы не выполняете автореализацию.
Ваш XIB-просмотр был добавлен к его родительскому объекту без ограничений и без возможности авторазрешения, сохраняя при этом свой первоначальный размер. Так как вы хотите, чтобы ваш взгляд, чтобы изменить соответствующим образ на ваш взгляд, у вас есть два варианта:

  • Изменить в ходе автоматических масок вашего взгляда XIb к гибким ширинам и высотам, но они должны соответствовать родительскому размеру или вы не будете иметь полная обложка
  • Добавьте некоторые ограничения, которые ограничивают два вида изменения в соответствии с родительскими изменениями. И вы достигаете этого высказывания между представлением XIB и его родительским представлением, пространство между трейлингом/ведущим и top/botton равно 0. Похоже, вы кладете некоторый клей на свои границы. Для этого вам нужно установить маску изменения размера автотрансляции в значение НЕТ, или вы можете столкнуться с некоторыми конфликтами, когда вы разместили в журнале.

Что вы делаете позже добавляет ограничения к виду (что хозяйничает вид XIB) его надтаблицы, но не было никаких ограничений между XIB и его родителем, таким образом autolayout не знает, как для изменения размера представления XIB.
Каждое представление в иерархии представлений должно иметь свои собственные ограничения.
Надеюсь, это поможет лучше понять.

+0

Я написал _vCustomView.translatesAutoresizingMaskIntoConstraints = NO; прежде чем я добавлю свой CustomView в фиктивный контейнер. Разве этого недостаточно, чтобы программным образом использовать ограничения автоопределения для моего объекта CustomView? Впоследствии я попытался с этими 4 ограничениями, чтобы мой CustomView соответствовал виду контейнера-контейнера, но, как сказано, не повезло. Я попытался вызвать ваш метод после добавления моего объекта CustomView в фиктивный контейнер и установки его четырех ограничений, но не удачи - тот же результат. CustomView по-прежнему 150 x 50 и не такой большой, как фиктивный контейнер (как я думаю, он должен быть). – uerceg

+0

Я говорю об этом методе '- (void) setup' после добавления xib в качестве подзона, который я опубликовал. Это ваше xib-представление, в котором отсутствуют ограничения. – Andrea

+0

Отметьте мое редактирование # 1. – uerceg

1

В своем коде вы должны иметь что-то вроде этого:

Во-первых, IBOutlet к ширине ограничения вы хотите изменить, либо в ViewController или в вашем 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 
} 

Надеется, что это работает для вас. Удачи!

+0

Андреа помог мне с ответом, но большое спасибо вам за готовность помочь. С наилучшими пожеланиями. – uerceg

+0

Простое и элегантное решение для меня, спасибо! – inix

0

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) 
     } 
    } 

Примечание: Просто вызовите функцию с аргументом, как ваш подвид.

Это помогает мне решить проблему с заменой .xib в swift 4.0.

Смежные вопросы