Подтвердить что ты не робот

Использовать автозапуск для установки динамического UIView для соответствия представлению контейнера

У меня есть UIView в IB, в котором есть еще один UIView, который я использую в виде контейнера. В коде я создаю три разных представления, а затем анимируем соответствующий вид контейнера в зависимости от состояния приложения. Только одно из трех разных видов будет действительным в любой момент времени. Проблема в том, что когда я запускаю на другом iPhone в симуляторе, мои новые объекты не масштабируются в соответствии с представлением контейнера. Я использую автозапуск. Для целей тестирования я настроил свои подзаголовки просто как большую кнопку, у которой все ее края ограничены супервидом. И в представлении контейнера также есть края, ограниченные этим супервидом. Я хочу, чтобы subview соответствовал представлению контейнера. т.е. кнопка растягивает весь размер представления контейнера. При запуске на разных iPhones размер представления контейнера и, следовательно, subview должен масштабироваться пропорционально различным размерам экрана 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]];  

Я просто не могу заставить это работать. Я новичок в автозапуске и не уверен, что я делаю неправильно, и хотел бы перестать ударить головой об эту стену. Любая помощь будет потрясающей.:)


************* ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ **************


Извините, я не заявлял о своей проблеме так четко, как мог. Итак, вот еще несколько снимков экрана. Во-первых, я опишу, что я сделал по коду.

В didFinishLaunchingWithOptions в AppDelegate.m я создаю MyViewController, как это,

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

В viewDidLoad в MyViewController.m я создаю mySubview и добавляю его в свой контейнерный вид и создаю для него такие ограничения,

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

И, наконец, в init в MySubview.h я добавляю 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, который я использую в качестве контейнера. Он имеет IBOutlet для UIView * containerView и является ссылкой, указанной выше. Единственные ограничения, которые у меня есть для containerView в IB, - это ведущее, конечное и нижнее пространство Superview и верхнее пространство для Superview = 44.

Для MySubview.xib высота и ширина 300, (ограничения не используются для высоты или ширины). Я чувствую, что эти размеры не должны иметь значения, поскольку mySubview должен ограничиваться контейнером.

В MySubview.xib у меня есть 3 объекта, topButton: height = 29, middleView: height = 242 и bottomButton: height = 29. (см. прикрепленное изображение) TopButton имеет ведущие, конечные и верхние ограничения Superview, а нижнее - среднее ограничение. Средство MiddleView имеет ведущие и завершающие ограничения Superview и ограничение topButton и ограничения нижнего уровня к нижнему баттону. И, наконец, bottomButton имеет ведущие, конечные и нижние ограничения Superview и ограничение top to middleView.

Я хочу, чтобы mySubview масштабировался, чтобы соответствовать контейнеру, поскольку ограничения были созданы и добавлены, но вместо этого 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

Как вы можете видеть в фальшивых снимках экрана, mySubview масштабируется, чтобы соответствовать контейнеру, даже если контейнерView немного масштабируется для настройки различных размеров экрана телефона.

Надеюсь, я не перешел за борт с информацией. Любая помощь будет потрясающей. Я чувствую, что я рядом, но должен упустить один ключевой шаг. Grrrrr.

4b9b3361

Ответ 1

Несколько мыслей:

  • Это в основном выглядит отлично, за исключением некоторой странности переменных: ваша локальная переменная containerView равна self.subView, но все ваши другие строки относятся к другой переменной, свойству класса, self.containerView. Вы опустили строку, в которой вы установили свойство класса containerView? Но когда я исправил это, ваш код работал отлично для меня.

  • Убедитесь, что вы не пытаетесь взглянуть на frame сразу после установки ограничений, так как изменения еще не будут отображаться в настройках frame. Вы можете сделать [containerView layoutIfNeeded];, если вы хотите заставить его передать все, основываясь на ограничениях. Кроме того, если вы хотите подтвердить настройки frame, лучше отложить просмотр этих значений до тех пор, пока viewDidAppear (т.е. viewDidLoad не будет слишком рано в процессе построения представления).

  • Небольшая настройка вашего кода (и не связанная с вашей проблемой), но когда я устанавливаю ограничения в представлении контейнера, я часто устанавливаю не только NSLayoutAttributeTop и NSLayoutAttributeLeading, как вы это делали, но также NSLayoutAttributeBottom и NSLayoutAttributeTrailing (а не NSLayoutAttributeWidth и NSLayoutAttributeHeight). Он выполняет то же самое, что и ваш код, но при использовании ненулевых значений это еще более интуитивно понятная часть.

    Во всяком случае, я просто сделал следующий код, перестановку вашего, и он отлично работает:

    - (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` (e.g. 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));
    }
    
  • Вы можете немного упростить этот код, используя язык визуальных форматов, например:

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

    Мне легче получить ограничения с использованием языка визуального формата. Немного меньше подвержено ошибкам (для меня, по крайней мере). Есть, однако, некоторые ограничения, которые не могут быть представлены на языке визуального формата, и в этом случае я возвращаюсь к синтаксису, который вы начертите.

  • В вашем пересмотренном вопросе вы показываете нам метод 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;
    }
    

Ответ 2

В этой проблеме вы указываете, что "мои новые объекты не масштабируются в соответствии с представлением контейнера", но из описания, которое, как я думаю, они есть, проблема заключается в том, что в вашем представлении контейнера нет фиксированного размера.

Я думаю, что если вы установите для своего вида контейнера фиксированную ширину и высоту, которые должны это сделать, вам также может потребоваться позвонить

[self.containerView layoutSubviews]

чтобы принудительно изменить размер после обновления ограничений.

Я также предлагаю вам обмен текстовым форматированием, вы можете поменять свои строки выше на что-то вроде "H: | [newSubview] |" и "V: | [newSubview] |"