Почему эти ограниченные макеты имеют разные размеры? - PullRequest
0 голосов
/ 19 декабря 2018

Мой макет сломан.У меня есть макет, добавленный во время выполнения, который я привязываю ко всем 4 сторонам с помощью этого кода:

func anchorAllSides(to parentView:UIView, identifier: String? = nil ) {
    self.translatesAutoresizingMaskIntoConstraints = false
    let top = self.topAnchor.constraint(equalTo: parentView.topAnchor)
    let bottom = self.bottomAnchor.constraint(equalTo: parentView.bottomAnchor)
    let left = self.leadingAnchor.constraint(equalTo: parentView.leadingAnchor)
    let right = self.trailingAnchor.constraint(equalTo: parentView.trailingAnchor)
    if let identifierString = identifier {
        top.identifier = "\(identifierString) - top"
        bottom.identifier = "\(identifierString) - bottom"
        left.identifier = "\(identifierString) - left"
        right.identifier = "\(identifierString) - right"
    }
    NSLayoutConstraint.activate([top, bottom, left, right])
}

В консоли я вижу, что 2 вида имеют ограничения, привязывающие все 4 стороны, но они также имеют совершенно разныеразмеры.

Printing description of $20:
<UIView: 0x7f93084220c0; frame = (0 0; 375 205.333); autoresize = W+H; gestureRecognizers = <NSArray: 0x600001956ac0>; layer = <CALayer: 0x60000176b320>>


Printing description of $21:  
<UIView: 0x7f930840ed40; frame = (0 528.667; 375 528.667); autoresize = RM+BM; layer = <CALayer: 0x6000017698e0>>

(lldb) po [0x7f930840ed40 constraints]
<__NSArrayI 0x600000650330>(
<NSLayoutConstraint:0x60000346a760 'drawerControllerView <-> rolePageDrawerView - bottom' UIView:0x7f93084220c0.bottom == UIView:0x7f930840ed40.bottom   (active)>,
<NSLayoutConstraint:0x60000346a7b0 'drawerControllerView <-> rolePageDrawerView - left' H:|-(0)-[UIView:0x7f93084220c0]   (active, names: '|':UIView:0x7f930840ed40 )>,
<NSLayoutConstraint:0x60000346a800 'drawerControllerView <-> rolePageDrawerView - right' UIView:0x7f93084220c0.trailing == UIView:0x7f930840ed40.trailing   (active)>,
<NSLayoutConstraint:0x60000346a710 'drawerControllerView <-> rolePageDrawerView - top' V:|-(0)-[UIView:0x7f93084220c0]   (active, names: '|':UIView:0x7f930840ed40 )>
)

Приведенная выше информация печатается после того, как представление выложено путем просмотра представления в отладчике иерархии представлений в Xcode.Таким образом, ограничения, все из которых активны, должны были бы сделать их размеры равными в этой точке.

Если они ограничены равными, как размеры кадра могут быть разными?

UPDATE

В попытке сузить эту проблему я использовал ведение журнала точек останова в функциях layoutSubviews () как родительского VC (страница роли vc), так и дочернего VC (календарь vc).В обоих я записываю размер родительского представления для ящика.В дочернем VC я записываю размер для вида ящика и для self.view, который является дочерним для ящика, который прикреплен со всех сторон к ящику.Я также регистрирую экземпляр представления ящика, чтобы убедиться, что они одинаковы.Вот журнал из другого прогона (поэтому адреса экземпляров изменились по сравнению с регистрацией выше):

role page vc drawerSize (width = 375, height = 190.5)
role page vc drawer 0x00007f7ffd516d50
calendar vc drawerSize (width = 375, height = 222.66666666666666)
calendar vc view size (width = 375, height = 222.66666666666666)
calendar vc drawer is 0x00007f7ffd516d50
role page vc drawerSize (width = 375, height = 589.33333333333337)
role page vc drawer 0x00007f7ffd516d50
role page vc drawerSize (width = 375, height = 589.33333333333337)
role page vc drawer 0x00007f7ffd516d50
calendar vc drawerSize (width = 375, height = 205.33333333333334)
calendar vc view size (width = 375, height = 205.33333333333334)
calendar vc drawer is 0x00007f7ffd516d50

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

Ответы [ 2 ]

0 голосов
/ 19 декабря 2018
Ответ

@ matt точно описывает то, что я пытался попросить в моих комментариях.Пример:

override func viewDidLoad() {
    super.viewDidLoad()

    let subview = UIView()
    subview.backgroundColor = .orange

    view.addSubview(subview)
    subview.anchorAllSides(to: view)

    print("BEFORE layoutIfNeeded")
    print(view.frame)
    print(subview.frame)

    view.layoutIfNeeded() // forces the view to update its layout immediately

    print("AFTER layoutIfNeeded")
    print(view.frame)
    print(subview.frame)
}

Печать:

BEFORE layoutIfNeeded
(0.0, 0.0, 375.0, 812.0)
(0.0, 0.0, 0.0, 0.0)
AFTER layoutIfNeeded
(0.0, 0.0, 375.0, 812.0)
(0.0, 0.0, 375.0, 812.0)
0 голосов
/ 19 декабря 2018

Если они ограничены, чтобы быть равными, как размеры кадра могут быть разными?

Поскольку ограничения являются просто инструкциями.Пока эти инструкции не выполнены, они просто инструкции и не более.Это как список покупок;Вы можете видеть, что молоко есть в списке, но вы тогда не говорите: «Так почему же в холодильнике нет молока?». Вы также должны купить молоко.

Что ж, среда выполнения не покупает молоко до тех пор, пока вы не напечатаете описания.Макет не происходит сразу;это происходит во время компоновки, то есть после того, как весь ваш код перестал выполняться и текущая транзакция CAT зафиксирована.После этого два вида будут иметь одинаковые размеры.

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

(И, конечно, он включает в себя layoutSubviews и viewDidLayoutSubviews сами. В этот момент происходит автоматическое расположение, но ваш код может прийтиа также переопределите то, что сделал autolayout.)

Просто чтобы понять суть, вот полный код приложения, которое вводит нас в ситуацию, аналогичную описанной вами:

func delay(_ delay:Double, closure:@escaping ()->()) {
    let when = DispatchTime.now() + delay
    DispatchQueue.main.asyncAfter(deadline: when, execute: closure)
}
class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        let v = UIView()
        v.backgroundColor = .red
        v.translatesAutoresizingMaskIntoConstraints = false
        self.view.addSubview(v)
        NSLayoutConstraint.activate([
            v.topAnchor.constraint(equalTo:self.view.topAnchor),
            v.leadingAnchor.constraint(equalTo:self.view.leadingAnchor),
            v.trailingAnchor.constraint(equalTo:self.view.trailingAnchor),
            v.bottomAnchor.constraint(equalTo:self.view.bottomAnchor),
            ])
        delay(5) {
            v.frame = v.frame.insetBy(dx: 30, dy: 30)
            print(v.frame)
            print(self.view.frame)
            print(self.view.constraints)
        }
    }
}

Обратите внимание на распечатку (для ясности я отредактировал некоторые ограничения):

(30.0, 30.0, 354.0, 676.0)
(0.0, 0.0, 414.0, 736.0)
[
    <NSLayoutConstraint:0x600000083570 V:|-(0)-[UIView:0x7fede9d07190]   (active, names: '|':UIView:0x7fede9f0d230 )>, 
    <NSLayoutConstraint:0x6000000957c0 H:|-(0)-[UIView:0x7fede9d07190]   (active, names: '|':UIView:0x7fede9f0d230 )>, 
    <NSLayoutConstraint:0x600000094c30 UIView:0x7fede9d07190.trailing == UIView:0x7fede9f0d230.trailing   (active)>, 
    <NSLayoutConstraint:0x600000095f40 UIView:0x7fede9d07190.bottom == UIView:0x7fede9f0d230.bottom   (active)>, 
    ...
]

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...