Копировать IB Созданы ограничения на другой UIView

У меня есть UITableView листинг вместе с другими элементами представления на экране. Я планирую поменять этот список другим видом, если нет транзакций для отображения. Для этого мне нужно скопировать все ограничения, прикрепленные к UITableView, и добавить их в новый UIView.

Screenshot

Я попытался скопировать значения свойств .constraints(), но он возвращает nil, потому что ограничения привязаны к супервизу. Получение ограничений из superview дает все ограничения, прикрепленные к другим разделам.

Есть ли быстрый способ копирования и добавления ограничений от одного UIView к другому?

Ответ 1

Нет быстрого пути.

Я сделал это с циклом над ограничениями супервизора.

Objective-C

+ (void)copyConstraintsFromView:(UIView *)sourceView toView:(UIView *)destView
{
    for (NSLayoutConstraint *constraint in sourceView.superview.constraints) {
        if (constraint.firstItem == sourceView)
        {
            [sourceView.superview addConstraint:[NSLayoutConstraint constraintWithItem:destView attribute:constraint.firstAttribute relatedBy:constraint.relation toItem:constraint.secondItem attribute:constraint.secondAttribute multiplier:constraint.multiplier constant:constraint.constant]];
        }
        else if (constraint.secondItem == sourceView)
        {
            [sourceView.superview addConstraint:[NSLayoutConstraint constraintWithItem:constraint.firstItem attribute:constraint.firstAttribute relatedBy:constraint.relation toItem:destView attribute:constraint.secondAttribute multiplier:constraint.multiplier constant:constraint.constant]];
        }
    }
}

Swift

static func copyConstraints(fromView sourceView: UIView, toView destView: UIView) {
    guard let sourceViewSuperview = sourceView.superview else {
        return
    }
    for constraint in sourceViewSuperview.constraints {
        if constraint.firstItem as? UIView == sourceView {
            sourceViewSuperview.addConstraint(NSLayoutConstraint(item: destView, attribute: constraint.firstAttribute, relatedBy: constraint.relation, toItem: constraint.secondItem, attribute: constraint.secondAttribute, multiplier: constraint.multiplier, constant: constraint.constant))
        } else if constraint.secondItem as? UIView == sourceView {
            sourceViewSuperview.addConstraint(NSLayoutConstraint(item: constraint.firstItem, attribute: constraint.firstAttribute, relatedBy: constraint.relation, toItem: destView, attribute: constraint.secondAttribute, multiplier: constraint.multiplier, constant: constraint.constant))
        }
    }
}

Примечание

Не забывайте копировать ограничения только после добавления destView в иерархию представления.

Ответ 2

Нет, в этом нет ничего встроенного в систему.

Объект NSLayoutConstraint неизменен, за исключением его приоритета constant, поэтому после создания объекта вы не можете просто применить "то же" ограничение к другому представлению (где "тот же" означает либо идентификацию объекта, либо равенство объекта).

Если производительность позволяет, а не настраивать и разрывать представления со всеми их ограничениями, я бы просто установил как представление таблицы, так и представления данных без данных как братья и сестры, используя одну вспомогательную функцию для установки эквивалентных ограничений для каждого, так что они выложены одинаково, но с одним поверх другого. Затем я просто поменял бы этот вид, видимый с помощью свойства hidden.

Однако, если вы действительно хотите дублировать одно ограничение на вид на другое представление, во время выполнения, в общем случае, вам придется написать метод утилиты, который выполняет рекурсивный поиск, начиная с самого предкового супервизора, который может иметь любой ограничение, влияющее на копирование вида, и создает дублирующее ограничение, применяемое к другому представлению. Такая функция может быть уже записана в одной из вспомогательных библиотек AL, например FLKAutoLayout.