Reputation: 20279
I'm using a header (supplementary view) in my UICollectionView
. On the header I have label which has a certain distance from the left side. I'm doing my calculation and setting the constant of a constraint. Everything does work as expected.
If the orientation is now changed, the labels have the old position. Now I need to update the constraints for all my headers. Calling invalidateLayout
doesn't update the constraints. How can I manually trigger the recalculation?
Edit:
This is how my layoutSubviews
does look like, where the recalculation takes place:
public override void LayoutSubviews ()
{
this.width = this.collectionViewSize.Width;
this.itemWidth = (nfloat)Math.Round(this.width / numberOfItemsInRow);
leftSpacing.Constant = this.itemWidth * this.referencePoint;
if (leftSpacing.Constant == 0)
leftSpacing.Constant = SectionHeader.MIN_SPACING;
base.LayoutSubviews ();
}
As you can see this is not Objective-C but you should be able to see what I'm doing. I take the width of the collection view (set on instantiation of the supplementary view) and then I calculate the width of cell which corresponds nearly to the real size of the cells. With the referencePoint I determine the position. Here you can see the setup of my constraints:
public SectionHeader (CGRect frame) : base (frame)
{
this.width = frame.Size.Width;
this.itemWidth = (nfloat)Math.Round(width / numberOfItemsInRow);
label = new UILabel (){
BackgroundColor = UIColor.White,
TextAlignment = UITextAlignment.Left
};
label.TranslatesAutoresizingMaskIntoConstraints = false;
AddSubview (label);
NSMutableDictionary viewsDictionary = new NSMutableDictionary();
viewsDictionary["label"] = label;
this.AddConstraints(NSLayoutConstraint.FromVisualFormat("V:|[label]|",(NSLayoutFormatOptions)0,null,viewsDictionary));
leftSpacing = NSLayoutConstraint.Create(label, NSLayoutAttribute.Left, NSLayoutRelation.Equal, this, NSLayoutAttribute.Left, 1, SectionHeader.MIN_SPACING);
leftSpacing.Priority = 250;
this.AddConstraint(leftSpacing);
this.AddConstraint(NSLayoutConstraint.Create(label, NSLayoutAttribute.Right, NSLayoutRelation.Equal, this, NSLayoutAttribute.Right, 1, 0));
}
In this code the calculation for the distance from the left is nearly the same, except that frame has the height of the set headerReferenceSize
. The width should be OK for the initialisation. I'm using the full height for the label, I set up the leading space and I pin it to the right.
Upvotes: 4
Views: 4017
Reputation: 3494
You need to call layoutIfNeeded
on the main view in the view controller so that the constraints are updated. Something like this should work:
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
// Update the constraints here for the new orientation - toOrientation
// ...
[UIView animateWithDuration:duration animations: ^{
[self.view layoutIfNeeded];
}];
}
This will animate the layout changes on orientation change.
You could add a breakpoint after the layoutIfNeeded
call, to see that the frames are what you would expect.
If your constraints are not in the view controller, but in a UIView
subclass, you can do the following:
- (void)awakeFromNib {
[super awakeFromNib];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateIntrinsicConstraints) name:UIDeviceOrientationDidChangeNotification object:nil];
}
- (void)updateIntrinsicConstraints {
// Update your constraints here
[self.constraint setConstant:newValue];
// You might need to call [self layoutIfNeeded] here, if you don't call it in another place
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
Let me know if this worked for you!
Update
You should not change the frame of the SectionHeader manually. You should do this by implementing the protocol method:
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section;
You could call layoutIfNeeded
in the init method of the SectionHeader
after you add the constraints to the label, add a breakpoint after to see if the frame is correct.
Let me know if it works out for you!
Upvotes: 2