问题描述
我有一个 UICollectionView,其中一些单元格应该有一个虚线边框,其中一些应该有一个实心边框。此外,根据数据模型中存在的内容,单元格的大小可能会有所不同。
我遇到的问题是我无法使虚线边框与集合视图单元格的大小相同,而且单元格大小可以根据内容更改。但基本上,单元格应该有虚线边框或实心边框。实心边框很容易调整到正确的大小。
这是它现在的样子的图片。虚线边框涂成绿色只是为了更容易看到。
这是视图层次结构调试视图。这里有两个虚线边框,因为我一直在试验。绿色边框是 UICollectionViewCell 根层上的一个子层。灰色边框是单独视图的子层,该视图是集合视图单元格的 contentView 属性的子视图。
代码
方法 1 - 添加带有子层的专用视图
这里我想添加一个带有虚线边框的 UIView 子类。然后,当我需要显示虚线边框或隐藏虚线边框时,我只需相应地设置视图的 hidden
属性。这工作正常,除了我无法调整虚线边框子层的大小。
视图正在根据 AutoLayout 约束调整为正确的宽度和高度,如上面的视图层次结构调试器屏幕截图所示。但是子图层仍然是原始大小(大约 50px x 50px,我猜它来自 UICollectionView,因为我没有在任何地方指定该大小)。
对于这个实现,我有一个名为 MyResizableSublayerView
的自定义 UIView 子类。它覆盖 layoutSublayersOfLayer
来处理子层的大小调整,或者至少这是应该发生的事情,但显然它不起作用。
但随后在集合视图单元格中使用 MyResizableSublayerView
类将虚线边框添加到视图层次结构中。
MyResizableSublayerView
@interface MyResizableSublayerView : UIView
@property (strong,nonatomic) CAShapeLayer *borderLayer;
+ (instancetype)viewWithBorderSublayer:(CAShapeLayer *)shapeLayer;
@end
@implementation MyResizableSublayerView
+ (instancetype)viewWithBorderSublayer:(CAShapeLayer *)shapeLayer {
CIResizableSublayerView *view = [[MyResizableSublayerView alloc] init];
view.borderLayer = shapeLayer;
return view;
}
- (void)setBorderLayer:(CAShapeLayer *)borderLayer {
if (self->_borderLayer) {
[self->_borderLayer removeFromSuperlayer];
}
self->_borderLayer = borderLayer;
[self.layer addSublayer:self->_borderLayer];
}
- (void)layoutSublayersOfLayer:(CALayer *)layer {
[super layoutSublayersOfLayer:layer];
self.borderLayer.frame = layer.bounds;
}
@end
MyCollectionViewCell
@interface MyCollectionViewCell ()
@property (strong,nonatomic) MyResizableSublayerView *unavailableBorderView;
@end
@implementation MyCollectionViewCell
- (instancetype)init {
return [self initWithFrame:CGRectZero];
}
- (instancetype)initWithCoder:(NSCoder *)coder {
if (self = [super initWithCoder:coder]) {
[self initialize];
}
return self;
}
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[self initialize];
}
return self;
}
- (void)initialize {
self.contentView.layer.cornerRadius = 4.0f;
self.contentView.layer.borderWidth = 1.0f;
//... add other subviews
[self.contentView addSubview:self.unavailableBorderView];
[NSLayoutConstraint activateConstraints:@[
[self.contentView.widthAnchor constraintLessthanorEqualToConstant:250.0],[self.contentView.widthAnchor constraintGreaterThanorEqualToConstant:100.0],[self.unavailableBorderView.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor],[self.unavailableBorderView.topAnchor constraintEqualToAnchor:self.contentView.topAnchor],[self.unavailableBorderView.trailingAnchor constraintEqualToAnchor:self.contentView.trailingAnchor],[self.unavailableBorderView.bottomAnchor constraintEqualToAnchor:self.contentView.bottomAnchor],//... constraints for other views
]];
}
- (MyResizableSublayerView *)unavailableBorderView {
if (!self->_unavailableBorderView) {
CAShapeLayer *layer = [CAShapeLayer layer];
layer.strokeColor = [UIColor colorWithRed:0xE0/255.0 green:0xE0/255.0 blue:0xE0/255.0 alpha:1.0].CGColor;
layer.linewidth = 4.0;
layer.lineJoin = kCALineJoinRound;
layer.fillColor = [UIColor clearColor].CGColor;
layer.lineDashPattern = @[@4,@4];
layer.frame = self.contentView.bounds;
layer.path = [UIBezierPath bezierPathWithRoundedRect:self.contentView.bounds cornerRadius:self.contentView.layer.cornerRadius].CGPath;
self->_unavailableBorderView = [MyResizableSublayerView viewWithBorderSublayer:layer];
self->_unavailableBorderView.translatesAutoresizingMaskIntoConstraints = NO;
self->_unavailableBorderView.layer.cornerRadius = self.contentView.layer.cornerRadius;
self->_unavailableBorderView.backgroundColor = [UIColor colorWithWhite:1.0 alpha:0.0];
}
return self->_unavailableBorderView;
}
//... more logic
@end
方法 2 - 直接添加到 UICollectionViewCell
对于这种方法,我将 CAShapeLayer 直接添加到 UICollectionViewCell,然后覆盖 layoutSublayersOfLayer
以尝试调整虚线边框子层的大小,但这也不起作用。
@interface MyCollectionViewCell ()
@property (strong,nonatomic) CAShapeLayer *unavailableBorderLayer;
@end
@implementation MyCollectionViewCell
- (instancetype)init {
return [self initWithFrame:CGRectZero];
}
- (instancetype)initWithCoder:(NSCoder *)coder {
if (self = [super initWithCoder:coder]) {
[self initialize];
}
return self;
}
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[self initialize];
}
return self;
}
- (void)initialize {
self.contentView.layer.cornerRadius = 4.0f;
self.contentView.layer.borderWidth = 1.0f;
//... add other subviews
[NSLayoutConstraint activateConstraints:@[
[self.contentView.widthAnchor constraintLessthanorEqualToConstant:250.0],//... constraints for other views
]];
CAShapeLayer *layer = [CAShapeLayer layer];
layer.strokeColor = [UIColor greenColor].CGColor;
layer.linewidth = 2.0;
layer.lineJoin = kCALineJoinRound;
layer.fillColor = [UIColor clearColor].CGColor;
layer.lineDashPattern = @[@4,@4];
layer.frame = self.contentView.bounds;
layer.path = [UIBezierPath bezierPathWithRoundedRect:self.contentView.bounds cornerRadius:self.contentView.layer.cornerRadius].CGPath;
self->_unavailableBorderLayer = layer;
[self.layer addSublayer:self->_unavailableBorderLayer];
}
- (void)layoutSublayersOfLayer:(CALayer *)layer {
[super layoutSublayersOfLayer:layer];
self.unavailableBorderLayer.frame = self.bounds;
}
//... more logic
@end
问题
我对此有几个问题。
- 我的代码不允许将虚线边框调整为与集合视图单元格大小相同的代码有什么问题?
- 哪种方法是向集合视图单元格添加虚线边框的最佳方法。或者有没有比我在这里列出的方法更好的方法?同样,我的目标是能够显示或隐藏虚线边框,并使其与动态调整大小的集合视图单元格大小相同。
解决方法
不太清楚您对内容视图的约束做了什么……但是,如果您获得了所需的布局,除了虚线边框,请尝试一下。
首先,不要使用 layoutSublayersOfLayer
,使用:
- (void)layoutSubviews {
[super layoutSubviews];
_unavailableBorderLayer.frame = self.bounds;
}