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, который был указан в xibviewDidAppear
происходит после завершения автоматического размещения.
На самом деле мне удалось заставить обновление макета, прежде чем мой код в 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".