it-swarm.com.ru

Могу ли я изменить свойство множителя для NSLayoutConstraint?

Я создал два представления в одном суперпредставлении, а затем добавил ограничения между представлениями:

_indicatorConstrainWidth = [NSLayoutConstraint constraintWithItem:self.view1 attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self.view2 attribute:NSLayoutAttributeWidth multiplier:1.0f constant:0.0f];
[_indicatorConstrainWidth setPriority:UILayoutPriorityDefaultLow];
_indicatorConstrainHeight = [NSLayoutConstraint constraintWithItem:self.view1 attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self.view2 attribute:NSLayoutAttributeHeight multiplier:1.0f constant:0.0f];
[_indicatorConstrainHeight setPriority:UILayoutPriorityDefaultLow];
[self addConstraint:_indicatorConstrainWidth];
[self addConstraint:_indicatorConstrainHeight];

Теперь я хочу изменить свойство множителя с помощью анимации, но я не могу понять, как изменить свойство множителя. (Я нашел _coefficient в частной собственности в заголовочном файле NSLayoutConstraint.h, но это личное.)

Как мне изменить свойство умножителя? 

Мой обходной путь - удалить старое ограничение и добавить новое с другим значением для multipler.

117
Bimawa

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

NSLayoutConstraint *standardConstraint, *zoomedConstraint;

// ...
// switch between constraints
standardConstraint.active = NO; // this line should always be the first line. because you have to deactivate one before activating the other one. or they will conflict.
zoomedConstraint.active = YES;
[self.view layoutIfNeeded]; // or using [UIView animate ...]
100
Ja͢ck

Вот расширение NSLayoutConstraint в Swift, которое позволяет довольно легко установить новый множитель:

import UIKit

extension NSLayoutConstraint {

    func setMultiplier(multiplier:CGFloat) -> NSLayoutConstraint {

        NSLayoutConstraint.deactivateConstraints([self])

        let newConstraint = NSLayoutConstraint(
            item: firstItem,
            attribute: firstAttribute,
            relatedBy: relation,
            toItem: secondItem,
            attribute: secondAttribute,
            multiplier: multiplier,
            constant: constant)

        newConstraint.priority = priority
        newConstraint.shouldBeArchived = shouldBeArchived
        newConstraint.identifier = identifier

        NSLayoutConstraint.activateConstraints([newConstraint])
        return newConstraint
    }
}

В Swift 3.0

import UIKit
extension NSLayoutConstraint {
    /**
     Change multiplier constraint

     - parameter multiplier: CGFloat
     - returns: NSLayoutConstraint
    */
    func setMultiplier(multiplier:CGFloat) -> NSLayoutConstraint {

        NSLayoutConstraint.deactivate([self])

        let newConstraint = NSLayoutConstraint(
            item: firstItem,
            attribute: firstAttribute,
            relatedBy: relation,
            toItem: secondItem,
            attribute: secondAttribute,
            multiplier: multiplier,
            constant: constant)

        newConstraint.priority = priority
        newConstraint.shouldBeArchived = self.shouldBeArchived
        newConstraint.identifier = self.identifier

        NSLayoutConstraint.activate([newConstraint])
        return newConstraint
    }
}

Использование демо:

@IBOutlet weak var myDemoConstraint:NSLayoutConstraint!

override func viewDidLoad() {
    let newMultiplier:CGFloat = 0.80
    myDemoConstraint = myDemoConstraint.setMultiplier(newMultiplier)

    //If later in view lifecycle, you may need to call view.layoutIfNeeded() 
}
133
Andrew Schreiber

Свойство multiplier доступно только для чтения. Вы должны удалить старый NSLayoutConstraint и заменить его новым, чтобы изменить его. 

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

51
Fruity Geek

Вспомогательная функция, которую я использую для изменения множителя существующего ограничения макета. Он создает и активирует новое ограничение и деактивирует старое. 

struct MyConstraint {
  static func changeMultiplier(_ constraint: NSLayoutConstraint, multiplier: CGFloat) -> NSLayoutConstraint {
    let newConstraint = NSLayoutConstraint(
      item: constraint.firstItem,
      attribute: constraint.firstAttribute,
      relatedBy: constraint.relation,
      toItem: constraint.secondItem,
      attribute: constraint.secondAttribute,
      multiplier: multiplier,
      constant: constraint.constant)

    newConstraint.priority = constraint.priority

    NSLayoutConstraint.deactivate([constraint])
    NSLayoutConstraint.activate([newConstraint])

    return newConstraint
  }
}

Использование, изменение множителя до 1,2:

constraint = MyConstraint.changeMultiplier(constraint, multiplier: 1.2)
43
Evgenii

Версия Objective-C для ответа Эндрю Шрайбера

Создайте категорию для класса NSLayoutConstraint и добавьте метод в файл .h следующим образом

    #import <UIKit/UIKit.h>

@interface NSLayoutConstraint (Multiplier)
-(instancetype)updateMultiplier:(CGFloat)multiplier;
@end

В файле .m

#import "NSLayoutConstraint+Multiplier.h"

@implementation NSLayoutConstraint (Multiplier)
-(instancetype)updateMultiplier:(CGFloat)multiplier {

    [NSLayoutConstraint deactivateConstraints:[NSArray arrayWithObjects:self, nil]];

   NSLayoutConstraint *newConstraint = [NSLayoutConstraint constraintWithItem:self.firstItem attribute:self.firstAttribute relatedBy:self.relation toItem:self.secondItem attribute:self.secondAttribute multiplier:multiplier constant:self.constant];
    [newConstraint setPriority:self.priority];
    newConstraint.shouldBeArchived = self.shouldBeArchived;
    newConstraint.identifier = self.identifier;
    newConstraint.active = true;

    [NSLayoutConstraint activateConstraints:[NSArray arrayWithObjects:newConstraint, nil]];
    //NSLayoutConstraint.activateConstraints([newConstraint])
    return newConstraint;
}
@end

Позже в ViewController создайте выход для ограничения, которое вы хотите обновить.

@property (strong, nonatomic) IBOutlet NSLayoutConstraint *topConstraint;

и обновить множитель, где вы хотите, как показано ниже ..

self.topConstraint = [self.topConstraint updateMultiplier:0.9099];
36
Koti Tummala

Вместо этого вы можете изменить свойство «константа», чтобы достичь той же цели с небольшой математикой. Предположим, что ваш множитель по умолчанию для ограничения равен 1.0f. Это код Xamarin C #, который можно легко перевести на target-c

private void SetMultiplier(nfloat multiplier)
{
    FirstItemWidthConstraint.Constant = -secondItem.Frame.Width * (1.0f - multiplier);
}
11
Tianfu Dai

Как объясняется в других ответах: Вам нужно удалить ограничение и создать новое.


Вы можете избежать возврата нового ограничения, создав статический метод для NSLayoutConstraint с параметром inout, который позволяет переназначить переданное ограничение

import UIKit

extension NSLayoutConstraint {

    static func setMultiplier(_ multiplier: CGFloat, of constraint: inout NSLayoutConstraint) {
        NSLayoutConstraint.deactivate([constraint])

        let newConstraint = NSLayoutConstraint(item: constraint.firstItem, attribute: constraint.firstAttribute, relatedBy: constraint.relation, toItem: constraint.secondItem, attribute: constraint.secondAttribute, multiplier: multiplier, constant: constraint.constant)

        newConstraint.priority = constraint.priority
        newConstraint.shouldBeArchived = constraint.shouldBeArchived
        newConstraint.identifier = constraint.identifier

        NSLayoutConstraint.activate([newConstraint])
        constraint = newConstraint
    }

}

Пример использования:

@IBOutlet weak var constraint: NSLayoutConstraint!

override func viewDidLoad() {
    NSLayoutConstraint.setMultiplier(0.8, of: &constraint)
    // view.layoutIfNeeded() 
}
1
Robert Dresler

Ни один из вышеперечисленных кодов не работал для меня SO ПОСЛЕ ПОПЫТКИ ИЗМЕНИТЬ МОЙ СОБСТВЕННЫЙ КОД ЭТОТ КОД Этот код работает в Xcode 10 и Swift 4.2

import UIKit
extension NSLayoutConstraint {
/**
 Change multiplier constraint

 - parameter multiplier: CGFloat
 - returns: NSLayoutConstraintfor 
*/i
func setMultiplier(multiplier:CGFloat) -> NSLayoutConstraint {

    NSLayoutConstraint.deactivate([self])

    let newConstraint = NSLayoutConstraint(
        item: firstItem,
        attribute: firstAttribute,
        relatedBy: relation,
        toItem: secondItem,
        attribute: secondAttribute,
        multiplier: multiplier,
        constant: constant)

    newConstraint.priority = priority
    newConstraint.shouldBeArchived = self.shouldBeArchived
    newConstraint.identifier = self.identifier

    NSLayoutConstraint.activate([newConstraint])
    return newConstraint
}
}



 @IBOutlet weak var myDemoConstraint:NSLayoutConstraint!

override func viewDidLoad() {
let newMultiplier:CGFloat = 0.80
myDemoConstraint = myDemoConstraint.setMultiplier(newMultiplier)

//If later in view lifecycle, you may need to call view.layoutIfNeeded() 
 }
0
Ullas Kumar

Вот ответ, основанный на ответе @ Tianfu в C #. Другие ответы, которые требуют активации и деактивации ограничений, не работали для меня.

    var isMapZoomed = false
@IBAction func didTapMapZoom(_ sender: UIButton) {
    let offset = -1.0*graphHeightConstraint.secondItem!.frame.height*(1.0 - graphHeightConstraint.multiplier)
    graphHeightConstraint.constant = (isMapZoomed) ? offset : 0.0

    isMapZoomed = !isMapZoomed
    self.view.layoutIfNeeded()
}
0
RawMean

Для изменения значения множителя выполните следующие действия: 1. создать точки для требуемого ограничения, например, someConstraint . 2. измените значение множителя как someConstraint.constant * = 0,8 или любое значение множителя.

вот и все, счастливое кодирование.

0
Gulshan Kumar

предположим, что view1 в раскадровке имеет ограничение ширины для основного вида (self.view в коде), как это

  view1Width = view * 0.7 + constant 

вместо создания 2 ограничений и переключения между ними путем изменения свойства Active ORRR [путем деактивации текущего ограничения со старым множителем и создания нового с новым множителем] оставьте ограничение 1 и поиграйте с его константой 

предположим, что я хочу изменить множитель view1 на 0,9 вместо 0,7

Я могу сделать это

  self.view1Width.constant += self.view.frame.size.width * 0.2

то же самое вы делаете для вычитания 

0
Sh_Khan