更新 UICollectionView 补充视图的方向更改约束
Update constraints for supplementary view of UICollectionView on orientation change
我在 UICollectionView
中使用 header(补充视图)。在 header 上,我有一个距离左侧有一定距离的标签。我正在计算并设置约束常量。一切都按预期工作。
如果现在更改了方向,则标签具有旧位置。现在我需要更新所有 header 的约束。调用 invalidateLayout
不会更新约束。如何手动触发重新计算?
编辑:
这是我的 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 ();
}
如您所见,这不是 Objective-C 但您应该能够看到我在做什么。我采用 collection 视图的宽度(在补充视图的实例化时设置),然后我计算单元格的宽度,它几乎对应于单元格的实际大小。使用 referencePoint 我确定了位置。在这里你可以看到我的约束设置:
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));
}
在此代码中,与左侧距离的计算几乎相同,只是 frame 具有集合 headerReferenceSize
的高度。宽度应该适合初始化。我使用标签的全高,我设置了前导 space 并将其固定在右边。
您需要在视图控制器的主视图上调用 layoutIfNeeded
以便更新约束。这样的事情应该有效:
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
// Update the constraints here for the new orientation - toOrientation
// ...
[UIView animateWithDuration:duration animations: ^{
[self.view layoutIfNeeded];
}];
}
这将使布局随方向变化而变化。
您可以在 layoutIfNeeded
调用之后添加一个断点,以查看帧是否符合您的预期。
如果您的约束不在视图控制器中,而是在 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];
}
让我知道这是否适合您!
更新
您不应手动更改 SectionHeader 的框架。你应该通过实现协议方法来做到这一点:
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section;
你可以在SectionHeader
的init方法中调用layoutIfNeeded
给label添加约束后,添加断点看frame是否正确。
如果适合你,请告诉我!
我在 UICollectionView
中使用 header(补充视图)。在 header 上,我有一个距离左侧有一定距离的标签。我正在计算并设置约束常量。一切都按预期工作。
如果现在更改了方向,则标签具有旧位置。现在我需要更新所有 header 的约束。调用 invalidateLayout
不会更新约束。如何手动触发重新计算?
编辑:
这是我的 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 ();
}
如您所见,这不是 Objective-C 但您应该能够看到我在做什么。我采用 collection 视图的宽度(在补充视图的实例化时设置),然后我计算单元格的宽度,它几乎对应于单元格的实际大小。使用 referencePoint 我确定了位置。在这里你可以看到我的约束设置:
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));
}
在此代码中,与左侧距离的计算几乎相同,只是 frame 具有集合 headerReferenceSize
的高度。宽度应该适合初始化。我使用标签的全高,我设置了前导 space 并将其固定在右边。
您需要在视图控制器的主视图上调用 layoutIfNeeded
以便更新约束。这样的事情应该有效:
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
// Update the constraints here for the new orientation - toOrientation
// ...
[UIView animateWithDuration:duration animations: ^{
[self.view layoutIfNeeded];
}];
}
这将使布局随方向变化而变化。
您可以在 layoutIfNeeded
调用之后添加一个断点,以查看帧是否符合您的预期。
如果您的约束不在视图控制器中,而是在 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];
}
让我知道这是否适合您!
更新
您不应手动更改 SectionHeader 的框架。你应该通过实现协议方法来做到这一点:
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section;
你可以在SectionHeader
的init方法中调用layoutIfNeeded
给label添加约束后,添加断点看frame是否正确。
如果适合你,请告诉我!