Получить ссылку на NSLayoutConstraint с помощью набора идентификаторов в раскадровке
Я устанавливал ограничения кнопки с помощью раскадровки. Я видел параметр "Идентификатор" в свойствах ограничения.
![Screenshot of constraint's properties]()
Я хочу сделать ссылку на это ограничение, чтобы изменить его значение в коде, чтобы переместить объект.
Как я могу получить ссылку на этот NSLayoutContraint
из этого идентификатора.
Я прочитал документацию, она была написана следующим образом
@interface NSLayoutConstraint (NSIdentifier)
/* For ease in debugging, name a constraint by setting its identifier, which will be printed in the constraint description.
Identifiers starting with UI and NS are reserved by the system.
*/
@property (nullable, copy) NSString *identifier NS_AVAILABLE_IOS(7_0);
@end
Итак, я понял, что это для целей отладки.
Что делать, если я хочу его получить и использовать? Я видел эту ссылку, но не получил удовлетворительного ответа: Как получить идентификатор NSLayoutConstraint по указателю?
Ответы
Ответ 1
Вы можете экстраполировать логику, представленную в предыдущем ответе, в расширение.
extension UIView {
/// Returns the first constraint with the given identifier, if available.
///
/// - Parameter identifier: The constraint identifier.
func constraintWithIdentifier(_ identifier: String) -> NSLayoutConstraint? {
return self.constraints.first { $0.identifier == identifier }
}
}
Затем вы можете получить доступ к любому ограничению в любом месте, используя:
myView.constraintWithIdentifier("myConstraintIdentifier")
Редактировать: просто для удовольствия, используя приведенный выше код, здесь расширение, которое находит все ограничения с этим идентификатором во всех дочерних UIViews. Пришлось изменить функцию, чтобы она возвращала массив вместо первого найденного ограничения.
func constraintsWithIdentifier(_ identifier: String) -> [NSLayoutConstraint] {
return self.constraints.filter { $0.identifier == identifier }
}
func recursiveConstraintsWithIdentifier(_ identifier: String) -> [NSLayoutConstraint] {
var constraintsArray: [NSLayoutConstraint] = []
var subviews: [UIView] = [self]
while !subviews.isEmpty {
constraintsArray += subviews.flatMap { $0.constraintsWithIdentifier(identifier) }
subviews = subviews.flatMap { $0.subviews }
}
return constraintsArray
}
Ответ 2
В Swift 3,
let filteredConstraints = button.constraints.filter { $0.identifier == "identifier" }
if let yourConstraint = filteredConstraints.first {
// DO YOUR LOGIC HERE
}
Ответ 3
Swift 3
Я написал быстрое расширение NSView, которое прекрасно справляется с этим.
extension NSView {
func constraint(withIdentifier: String) -> NSLayoutConstraint? {
return self.constraints.filter { $0.identifier == withIdentifier }.first
}
}
Использование:
if let c = button.constraint(withIdentifier: "my-button-width") {
// do stuff with c
}
Ответ 4
Я предполагаю, что у вас установлена розетка для кнопки, поэтому у вас есть доступная ссылка на нее. Итак, сначала извлеките ограничения вида с вашей кнопки. Затем цикл через массив и на каждой итерации сравнивает свойство идентификатора каждого ограничения со значением, введенным вами в Interface Builder. Похоже, что вы кодируете в Objective-C, поэтому ниже приведен пример кода Objective-C. Измените @ "identifier" на любое значение, заданное в Interface Builder.
NSArray *constraints = [button constraints];
int count = [constraints count];
int index = 0;
BOOL found = NO;
while (!found && index < count) {
NSLayoutConstraint *constraint = constraints[index];
if ( [constraint.identifier isEqualToString:@"identifier"] ) {
//save the reference to constraint
found = YES;
}
index++;
}
Ответ 5
Я упростил поиск и добавил в список предков список предков:
+ (NSLayoutConstraint *) findConstraintNamed:(NSString *)identifierTarget startWith:(UIView *)aView;
{
// walk upward from item through ancestors
UIView *currentView = aView;
while (currentView != nil)
{
NSArray *constraints = [currentView constraints];
NSInteger foundConstraintIndex = [constraints indexOfObjectPassingTest:^BOOL(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
return [((NSLayoutConstraint *)obj).identifier isEqualToString:identifierTarget];
}];
if (foundConstraintIndex != NSNotFound)
{
return constraints[foundConstraintIndex];
}
// not found, so walk up the ancestor chain
currentView = currentView.superview;
}
return nil; // not found anywhere in item or ancestors! :(
}
Ответ 6
Для изменения размера набора кнопок в контейнере общего вида это работает. Каждая кнопка subview/должна использовать общий идентификатор (например, "высота" ).
@IBAction func btnPressed(_ sender: UIButton) {
for button in self.btnView.subviews{
for constraint in button.constraints{
if constraint.identifier == "height"{
constraint.constant = constraint.constant == 0 ? 30:0
}
}
}
UIView.animate(withDuration: 0.3) { () -> Void in
self.view.layoutIfNeeded()
}
}