iOS AutoLayout - получить ширину кадра

Я занимаюсь разработкой с использованием iOS 6 авто макет

Я хотел бы войти сообщение, отображающее ширину кадра представления.

Я могу видеть textView на экране.

Но я получаю ширину и высоту равными нулю, я что-то упустил?

NSLog(@"textView    = %p", self.textView);
NSLog(@"height      = %f", self.textView.frame.size.height);
NSLog(@"width       = %f", self.textView.frame.size.width);

textView    = 0x882de00
height      = 0.000000
width       = 0.000000

9 ответов

Решение

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

Изменить: этот ответ указывает, почему сценарий в вопросе не работает. Ответ @dreamzor указывает, где разместить код для его решения.

На самом деле, приведенные выше ответы не совсем верны. Я следовал за ними и получал нули снова и снова.

Хитрость заключается в том, чтобы поместить свой фрейм-зависимый код в viewDidLayoutSubviews метод, который

Уведомляет контроллер представления, что его представление только что выложило его подпредставления.

Не забывайте, что этот метод вызывается несколько раз и не является частью жизненного цикла ViewController, поэтому будьте осторожны при его использовании.

Надеюсь, это будет кому-то полезно.

Просто хотел добавить, что для моей программы без ландшафтного режима НЕ использовать Auto Layout намного проще... Я пытался, хотя =D

Включить в ваш viewDidLoad()

self.view.setNeedsLayout()
self.view.layoutIfNeeded()

Прежде чем получить доступ к yourview.frame.size.width

Решение

  • Поместите этот код в viewDidAppear

причина

  • viewDidLoad происходит до завершения автоматического размещения Таким образом, позиция еще не установлена ​​с помощью autolayout, который был указан в xib
  • viewDidAppear происходит после завершения автоматического размещения.

На самом деле мне удалось заставить обновление макета, прежде чем мой код в viewDidLoad:

override func viewDidLoad() {
        super.viewDidLoad()

        println("bounds before \(self.previewContainer.bounds)");
        //on iPhone 6 plus -> prints bounds before (0.0,0.0,320.0,320.0)

        self.view.setNeedsLayout()
        self.view.layoutIfNeeded()

        println("bounds after \(self.previewContainer.bounds)");
        //on iPhone 6 plus -> prints bounds after (0.0,0.0,414.0,414.0)

        //Size dependent code works here
        self.create()
    }

ОБНОВЛЕНИЕ: Это, кажется, больше не работает

Это действительно странная особенность. Но я нашел:

Если вы хотите получить кадр без использования метода layoutsubviews, используйте этот:

dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"View frame: %@", NSStringFromCGRect(view.frame));
    });

Это действительно странно!!!

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

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

Так что я решил это с небольшим взломом. В моей раскадровке mySubview должно быть меньше, чем его содержание self.view, Но когда viewDidLayoutSubviews сначала называется, mySubview по-прежнему имеет ширину 600, тогда как self.view кажется, установлен правильно (это проект iPhone). Поэтому все, что мне нужно сделать, это отслеживать последующие вызовы и проверять относительную ширину. однажды mySubview меньше чем self.view Я могу быть уверен, что это было правильно выложено.

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    if self.mySubview.bounds.size.width < self.view.bounds.size.width {

        // mySubview's width became less than the view's width, so it is
        // safe to assume it is now laid out correctly...

    }
}

Это имеет то преимущество, что не полагается на жестко запрограммированные числа, поэтому он может работать, например, на всех форм-факторах iPhone. Конечно, это не может быть панацеей во всех случаях или на всех устройствах, но, вероятно, есть много оригинальных способов сделать аналогичные проверки относительных размеров.

И нет, нам не нужно этого делать, но пока Apple не предоставит нам более надежные обратные вызовы, мы все застряли с этим.

Вы можете узнать размер только после первого прохода макета. Или просто вызовите метод ниже, после того, как вы получили реальную ширину вашего вида.

[yourView layoutIfNeeded];

iOS AutoLayout - получить ширину кадра

 -(void) layoutSubviews{
        [self layoutIfNeeded];
        //right you code to set frame its will work to get frame and set frame.
        CALayer *bottomBorder = [CALayer layer];
        bottomBorder.frame = CGRectMake(0.0f, bkView.frame.size.height - 1, bkView.frame.size.width, 1.0f);
        bottomBorder.backgroundColor = [UIColor blackColor].CGColor;
        [bkView.layer addSublayer:bottomBorder];
    }

Я согласен с решением "user1046037"

Если вы используете и руководства atuoLayout, и код одновременно, вам лучше поместить программирование фреймов (или NSlayoutConstraints) в "ViewDidAppear", особенно когда вы разрабатываете пользовательский интерфейс для нескольких устройств.

Основываясь на моих тестах, iOS14 будет брать автоматические макеты с экрана (iPhone 11 Pro Max по умолчанию) передViewDidLoad и обновлять его вViewDidAppear.

Для людей, которые не знакомы с циклом просмотра, его "загрузить представление из раскадровки" -> "ViewDidLoad" -> "ViewWillAppear" -> "ViewDidAppear".

Другие вопросы по тегам