在uicollectionview中添加单元格下方的水平线

时间:2016-10-12 07:29:56

标签: ios swift uicollectionview cashapelayer

我正在实现类似日历布局,并在屏幕截图中显示了一些修改。为实现这一点,我使用了UICollectionView。问题是,我必须绘制一个屏幕宽度连续线(截图中的绿线)。 The green line should cover the whole width,我知道由于half of the cornerRadius而没有在圆形单元格上显示,而在第一个单元格(上午10点)之后仅显示垂直线。我必须添加shapelayer,以便它看起来像一条连续的线。这是我到目前为止尝试过的代码。

KKViewController.m

 func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {

    let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as! KKBookCollectionViewCell

    self.bookingCollectionView.backgroundColor = UIColor.whiteColor()

    let rectangularRowIndex:NSInteger = indexPath.row % 5
    if(rectangularRowIndex == 0 )
    {
        cell.userInteractionEnabled = false
        cell.layer.cornerRadius = 0
        cell.timeSlotLabel.text = "10am"
        cell.backgroundColor = UIColor.whiteColor()
        cell.layer.borderWidth = 0
        cell.layer.borderColor = UIColor.clearColor().CGColor

    }
    else
    {
        cell.userInteractionEnabled = true
        cell.layer.cornerRadius = cell.frame.size.width/2
        cell.timeSlotLabel.text = ""
        //cell.backgroundColor = UIColor.lightGrayColor()
        cell.layer.borderWidth = 1
        cell.layer.borderColor = UIColor.grayColor().CGColor

        if cell.selected == true
        {
            cell.backgroundColor = UIColor.greenColor()
        }

        else
        {
            cell.backgroundColor = UIColor.lightGrayColor()
        }
    }
    return cell
}

KKCollectionCell.m

var borderWidth:CGFloat!
var borderPath:UIBezierPath!

override func awakeFromNib() {
    super.awakeFromNib()
    drawHorizontalLine()
    dottedLine(with: borderPath, and: borderWidth)

    drawVerticalLine()
    dottedLine(with: borderPath, and: borderWidth)

func drawVerticalLine()
{
    borderPath = UIBezierPath()
    borderPath.moveToPoint(CGPointMake(self.frame.origin.x + self.frame.size.width, self.frame.origin.y))
    //borderPath.addLineToPoint(CGPointMake(self.frame.size.width - 5, self.frame.origin.y + self.frame.size.height - 50))

    borderPath.addLineToPoint(CGPointMake(self.frame.origin.x + self.frame.size.width, self.frame.origin.y + self.frame.size.height))
    borderWidth = 2.0
    print("border path is %f, %f:\(borderPath)")
}

func drawHorizontalLine()
{
    borderPath = UIBezierPath()
    borderPath.moveToPoint(CGPointMake(0, self.frame.origin.y))
    borderPath.addLineToPoint(CGPointMake(self.frame.size.width + 10, self.frame.origin.y))
    borderWidth = 2.0
    print("border path is %f, %f:\(borderPath)")
}

func dottedLine (with path:UIBezierPath, and borderWidth:CGFloat)
{
    let shapeLayer = CAShapeLayer()
    shapeLayer.strokeStart = 0.0
    shapeLayer.strokeColor = UIColor.greenColor().CGColor
    shapeLayer.lineWidth = borderWidth
    shapeLayer.lineJoin = kCALineJoinRound
    shapeLayer.lineDashPattern = [1,2]
    shapeLayer.path = path.CGPath
    self.layer.addSublayer(shapeLayer)
}

enter image description here

2 个答案:

答案 0 :(得分:0)

您可以在集合视图单元格中添加新视图,并为该新视图设置角半径。您还必须减少单元格之间的间距。然后这条线看起来就像你期望的那样。

答案 1 :(得分:0)

我知道这是一个老问题,但从未得到正确回答,我一直在寻找这种行为并在另一个答案的帮助下实现了它。 要实现这一点,您需要对 UICollectionViewFlowLayout 进行子类化(也许一个简单的布局也可以,但我没有尝试)。

class HorizontalLineFlowLayout: UICollectionViewFlowLayout {

var insets: CGFloat = 10.0
static let lineWidth: CGFloat = 10.0

override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
    guard let attributes = super.layoutAttributesForElements(in: rect) else { return nil }
    
    var attributesCopy: [UICollectionViewLayoutAttributes] = []
    
    for attribute in attributes {
        attributesCopy += [attribute]
        
        let indexPath = attribute.indexPath
        
        if collectionView!.numberOfItems(inSection: indexPath.section) == 0 { continue }
        
        let contains = attributes.contains { layoutAttribute in
            layoutAttribute.indexPath == indexPath && layoutAttribute.representedElementKind == HorizontalLineDecorationView.kind
        }
        
        if !contains {
            let horizontalAttribute = UICollectionViewLayoutAttributes(forDecorationViewOfKind: HorizontalLineDecorationView.kind, with: indexPath)
            
            let width = indexPath.item == collectionView!.numberOfItems(inSection: indexPath.section) - 1 ?
                attribute.frame.width + insets :
                attribute.frame.width + insets * 1.5
            
            let frame = CGRect(x: attribute.frame.minX, y: attribute.frame.minY, width: width, height: 0.5)
            
            horizontalAttribute.frame = frame
            
            attributesCopy += [horizontalAttribute]
        }
    }
    
    return attributesCopy
}

override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
    return true
}

函数 layoutAttributesForElements 每次都会被调用,它为您指定的单元格和您指定的框架制作线条。

您还需要看起来像这样的装饰视图:

class HorizontalLineDecorationView: UICollectionReusableView {

static let kind = "HorizontalLineDecorationView"

override init(frame: CGRect) {
    super.init(frame: frame)
    
    backgroundColor = .gray
    alpha = 0.2
}

required init?(coder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

}

通常它只是一个位于单元格后面的视图,分别指向它的indexPath,所以这些线并不完全沿着屏幕,而是一些聚集在一起的线,看起来像一条完整的线,你可以调整它的宽度和高度,玩那个。

注意为布局中的属性设置的框架,即装饰视图的框架,并且是相对于单元格(属性)定义的。

不要忘记注册那个装饰视图,并制作布局并将其传递给 collecitonview,如下所示:

let layout = HorizontalLineFlowLayout()
    layout.register(HorizontalLineDecorationView.self, forDecorationViewOfKind: HorizontalLineDecorationView.kind)
    layout.minimumInteritemSpacing = 10.0
    layout.minimumLineSpacing = 10.0
    layout.sectionInset = .zero
    
    collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
    collectionView.register(DateCell.self, forCellWithReuseIdentifier: "month")
    
    collectionView.delegate = monthDelegate
    collectionView.dataSource = monthDelegate
    collectionView.backgroundColor = .clear

最终结果是enter image description here