我在一个superview中创建了两个视图,然后在视图之间添加了约束:
_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];
现在我想用动画更改乘数属性,但我无法弄清楚如何更改多重属性。 (我在头文件NSLayoutConstraint.h中的私有属性中找到_coefficient,但它是私有的。)
如何更改多重属性?
我的解决方法是删除旧约束,并为multipler
添加不同值的新约束。
答案 0 :(得分:144)
这是Swift中的NSLayoutConstraint扩展,它可以很容易地设置一个新的乘数:
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()
}
答案 1 :(得分:101)
如果您只需要应用两组乘数,从 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 ...]
答案 2 :(得分:51)
multiplier
属性是只读的。您必须删除旧的NSLayoutConstraint并将其替换为新的NSLayoutConstraint以进行修改。
但是,由于您知道要更改乘数,因此您可以通过在需要更改(通常更少的代码)时自己乘以常量来更改常量。
答案 3 :(得分:45)
我用来更改现有布局约束的乘数的辅助函数。它创建并激活新约束并停用旧约束。
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)
答案 4 :(得分:39)
Andrew Schreiber答案的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];
答案 5 :(得分:11)
您可以更改“常量”属性,而不是通过一点数学来实现相同的目标。假设约束的默认乘数是1.0f。这是Xamarin C#代码,可以很容易地翻译成objective-c
private void SetMultiplier(nfloat multiplier)
{
FirstItemWidthConstraint.Constant = -secondItem.Frame.Width * (1.0f - multiplier);
}
答案 6 :(得分:2)
正如在其他答案中所解释的:您需要删除约束并创建新约束。
您可以通过使用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()
}
答案 7 :(得分:1)
要更改乘数的值,请按照以下步骤操作: 1.为所需的约束(例如someConstraint)创建出口。 2.更改乘数值,例如 someConstraint.constant * = 0.8 或任何乘数。
就这样,祝您编程愉快。
答案 8 :(得分:1)
是的,只要更改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 = shouldBeArchived
newConstraint.identifier = identifier
NSLayoutConstraint.activate([newConstraint])
return newConstraint
}
self.mainImageViewHeightMultiplier = self.mainImageViewHeightMultiplier.setMultiplier(375.0/812.0)
答案 9 :(得分:1)
在Swift 5.x中,您可以使用:
extension NSLayoutConstraint {
func setMultiplier(multiplier: CGFloat) -> NSLayoutConstraint {
guard let firstItem = firstItem else {
return self
}
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
}
}
答案 10 :(得分:0)
这是基于@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()
}
答案 11 :(得分:0)
以上代码均不适用于我 因此,尝试修改自己的代码后,此代码 该代码可在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()
}
答案 12 :(得分:0)
如许多其他答案所建议的那样,通过更改代码中的活动约束进行切换对我不起作用。因此,我创建了2个约束,一个已安装,另一个未绑定,将两者都绑定到代码,然后通过删除一个并添加另一个来进行切换。
为了完整起见,要绑定约束,请使用鼠标右键将约束拖至代码,就像其他任何图形元素一样:
我命名了一个比例IPad,另一个比例命名为iPhone。
然后,在viewDidLoad处添加以下代码
override open func viewDidLoad() {
super.viewDidLoad()
if ... {
view.removeConstraint(proportionIphone)
view.addConstraint(proportionIpad)
}
}
我正在使用xCode 10和Swift 5.0
答案 13 :(得分:0)
我有办法。无需重新创建约束。
假设您有一个想要限制其纵横比以匹配图像纵横比的 imageView。
import excel2json
excel2json.convert_from_file('test.xls')
答案 14 :(得分:0)
@IBOutlet 弱变量 viewHeightConstraint: NSLayoutConstraint!
让 heightOfSuperview = self.view.bounds.height
viewHeightConstraint.constant = heightOfSuperview * 0.5
// 与乘法器效果相同
答案 15 :(得分:-1)
人们可以读到:
var multiplier: CGFloat
The multiplier applied to the second attribute participating in the constraint.
就此documentation page。这是否意味着一个人应该能够修改乘数(因为它是一个var)?