简体   繁体   English

在方向更改时更新UICollectionView补充视图的约束

[英]Update constraints for supplementary view of UICollectionView on orientation change

I'm using a header (supplementary view) in my UICollectionView . 我在我的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. 调用invalidateLayout不会更新约束。 How can I manually trigger the recalculation? 如何手动触发重新计算?

Edit: 编辑:

This is how my layoutSubviews does look like, where the recalculation takes place: 这就是我的layoutSubviews看起来的样子,重新计算的位置:

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. 正如您所看到的,这不是Objective-C,但您应该能够看到我在做什么。 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. 使用referencePoint我确定位置。 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 . 在此代码中,左边距离的计算几乎相同,只是框架具有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. 我正在使用标签的全高,我设置了前导空间,然后将其固定在右侧。

You need to call layoutIfNeeded on the main view in the view controller so that the constraints are updated. 您需要在视图控制器的主视图上调用layoutIfNeeded ,以便更新约束。 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. 您可以在layoutIfNeeded调用之后添加断点,以查看帧是您期望的。

If your constraints are not in the view controller, but in a UIView subclass, you can do the following: 如果您的约束不在视图控制器中,而是在UIView子类中,则可以执行以下操作:

- (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. 您不应手动更改SectionHeader的框架。 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. 在将约束添加到标签后,可以在SectionHeader的init方法中调用layoutIfNeeded ,之后添加断点以查看框架是否正确。

Let me know if it works out for you! 让我知道它是否适合你!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM