Create an account

Very important

  • To access the important data of the forums, you must be active in each forum and especially in the leaks and database leaks section, send data and after sending the data and activity, data and important content will be opened and visible for you.
  • You will only see chat messages from people who are at or below your level.
  • More than 500,000 database leaks and millions of account leaks are waiting for you, so access and view with more activity.
  • Many important data are inactive and inaccessible for you, so open them with activity. (This will be done automatically)


Thread Rating:
  • 830 Vote(s) - 3.53 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Can I change multiplier property for NSLayoutConstraint?

#1
I created two views in one superview, and then added constraints between views:

_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];

Now I want to change multiplier property with animation, but I can't figure out how to change the multipler property. (I found _coefficient in private property in header file NSLayoutConstraint.h, but it private.)

How do I change multipler property?

My workaround is to remove the old constraint and add the new one with a different value for `multipler`.
Reply

#2
The `multiplier` property is read only. You have to remove the old NSLayoutConstraint and replace it with a new one to modify it.

However, since you know you want to change the multiplier, you can just change the constant by multiplying it yourself when changes are needed which is often less code.
Reply

#3
A helper function I use to change *multiplier* of an existing layout constraint. It creates and activates a new constraint and deactivates the old one.

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

Usage, changing multiplier to 1.2:

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

Reply

#4
One can read:

var multiplier: CGFloat
The multiplier applied to the second attribute participating in the constraint.

on this [documentation page][1]. Doesn't that mean that one should be able to modify multiplier (since it is a var)?


[1]:

[To see links please register here]

Reply

#5
Objective-C Version for Andrew Schreiber answer

Create the category for NSLayoutConstraint Class and add the method in .h file like this

#import <UIKit/UIKit.h>

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

In the .m file

#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

Later in the ViewController create the outlet for the constraint you want to update.

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

and update the multiplier where ever you want like below..

self.topConstraint = [self.topConstraint updateMultiplier:0.9099];
Reply

#6
Here is an answer based on @Tianfu's answer in C#. Other answers that require activation and deactivation of constraints did not work for me.

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()
}
Reply

#7
You can change the "constant" property instead to achieve the same goal with a little math. Assume your default multiplier on the constraint is 1.0f. This is Xamarin C# code which can be easily translated to objective-c

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

Reply

#8
NONE OF THE ABOVE CODE WORKED FOR ME
SO AFTER TRYING TO MODIFY MY OWN CODE THIS CODE
This code is working in Xcode 10 and 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()
}
Reply

#9
As is in other answers explained: You need to remove constraint and create new one.


----------

You can avoid returning new constraint by creating static method for `NSLayoutConstraint` with `inout` parameter, which allows you to reassign passed constraint

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
}

}

Example usage:

@IBOutlet weak var constraint: NSLayoutConstraint!

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

#10
Switch by changing the active constraint in code as suggested by many other answers did not work for me. So i created 2 constrains, one installed and the other not, bind both to the code, and then switch by removing one and adding the other.

For the sake of completeness, to bind the constrain drag the constrain to the code using mouse right button, just like any other graphic element:

[![enter image description here][1]][1]

I named one proportionIPad and the other proportionIPhone.

Then, add the following code, at viewDidLoad

override open func viewDidLoad() {
super.viewDidLoad()
if ... {

view.removeConstraint(proportionIphone)
view.addConstraint(proportionIpad)
}
}

I am using xCode 10 and swift 5.0


[1]:
Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

©0Day  2016 - 2023 | All Rights Reserved.  Made with    for the community. Connected through