2013-10-25 29 views
91

我一個上海華設立了兩個意見,然後在視圖之間添加約束:我可以更改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]; 

現在我想改變乘數屬性與動畫,但我無法弄清楚如何改變乘數屬性。 (我在頭文件NSLayoutConstraint.h中的私有屬性中找到了_coefficient,但它是私有的。)

如何更改multipler屬性?

我的解決方法是刪除舊約束併爲multipler添加具有不同值的新約束。

+1

您當前刪除舊約束並添加新的方法做的是正確的選擇。我明白,它不覺得「正確」,但它是你應該這樣做的方式。 – Rob

+3

我認爲乘數不應該是恆定的。這是一個糟糕的設計。 – Borzh

+1

@Borzh爲什麼通過乘數我做出自適應約束。對於可重新調整的ios。 – Bimawa

回答

82

如果你只有有兩套需要應用乘法器,從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 ...] 
+0

這是iOS 8 API –

+15

@CullenSUN,從我的回答中可以明顯看出「iOS 8 ...」的含義:p –

+0

您可以在約束條件下動畫這一更改嗎?即:動畫關閉乘數約束0.75並打開乘數約束0.3並使其具有動畫流暢性約束動畫已經做的動畫? – micnguyen

48

multiplier屬性是隻讀的。你必須刪除舊的NSLayoutConstraint,並用新的替換它來修改它。

但是,既然您知道您想要更改乘數,您可以在需要更改時更改常數,而這通常是更少的代碼。

+49

乘法器是隻讀的,這似乎很奇怪。我並不期待那樣! – jowie

+94

@jowie具有諷刺意味的是,「常量」的值可以改變,而乘數不能。 –

+6

如果常數爲0.0,則此解決方案不起作用。 – Madhan

38

一個幫手函數我用來更改乘數現有的佈局約束。它會創建並激活一個新約束,並停用舊約束。

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) 
+1

它適用於iOS 8嗎?或者可以在早期版本中使用 –

+1

'NSLayoutConstraint.deactivate'功能僅適用於iOS 8.0+。 – Evgenii

91

這裏是一個NSLayoutConstraint擴展在夫特使設置新乘數很容易:

import Foundation 
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 
    } 
} 

在夫特3.0

import Foundation 
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() 
} 
+2

真的有幫助... – milanpanchal

+7

'NSLayoutConstraint.deactivateConstraints([self])'應該在創建'newConstraint'之前完成,否則可能會導致warning:_Unable同時滿足constraints_。 'newConstraint.active = true'也是不必要的,因爲'NSLayoutConstraint.activateConstraints([newConstraint])'完全一樣。 – tzaloga

+1

你救了我一天的男人! – iOS

26

的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 

後來在ViewCon troller爲您想要更新的約束創建出口。

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

並更新乘法器在哪裏你想要像下面..

self.topConstraint = [self.topConstraint updateMultiplier:0.9099]; 
+0

我已經在這個示例代碼中移動了停用,因爲'active = true'與激活相同,因此會在之前添加重複約束取消激活被調用,這會在某些情況下導致約束錯誤。 – Jules

7

您可以更改「常量」屬性,以實現相同的目標,只需要一點數學運算。假設你的約束的默認乘數是1.0f。這是Xamarin C#代碼可以很容易地轉換爲目標c

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

這是一個不錯的解決方案 –

-1

人們可以改爲:

var multiplier: CGFloat 
The multiplier applied to the second attribute participating in the constraint. 
在此 documentation page

。這並不意味着應該能夠修改乘數(因爲它是一個變量)?

0

這是一個基於@天孚在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

假設在一個情節串連圖板具有廠景像這樣

view1Width = view * 0.7 + constant 

而不是創建2個約束,並通過改變Active屬性在它們之間進行切換的寬度約束到主視圖(在代碼self.view) ORRR [通過使用舊的乘數去激活當前約束並用新的乘數創建一個新約束]將其設置爲1約束並使用其常量

假設我想將view1乘數更改爲0.9而不是0.7

我可以做到這一點

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

同你作減法

相關問題