【问题标题】:Add border of varying width to different sides在不同的边上添加不同宽度的边框
【发布时间】:2021-03-04 12:46:46
【问题描述】:

我有一个要求,我需要在 uiview 的顶部、左侧和底部边框宽度为 1 (CGFloat),在右侧边框宽度为 0 (CGFloat)。我尝试为每一侧添加多个 CALayers,但视图并不好,因为滚动边框时没有使用 uiview 滚动。

我尝试使用的代码:

    enum ViewSide: String {
        case left
        case right
        case top
        case bottom
    }
    
    func addBorderToAllSides(color: UIColor, thickness: CGFloat) {
        addBorder(toSides: [.left, .right, .bottom, .top], withColor: color, andThickness: thickness)
    }
    
    func addBorder(toSides sides: [ViewSide], withColor color: UIColor, andThickness thickness: CGFloat) {
        
        sides.forEach { (side) in
            ///remove previously added sublayer
            layer.sublayers?.removeAll(where: {$0.name == side.rawValue})
            let border = CALayer()
            border.backgroundColor = color.cgColor
            switch side {
            case .left:
                border.frame = CGRect(x: frame.minX, y: frame.minY, width: thickness, height: frame.height)
            case .right:
                border.frame = CGRect(x: frame.maxX, y: frame.minY, width: thickness, height: frame.height)
            case .top:
                border.frame = CGRect(x: frame.minX, y: frame.minY, width: frame.width, height: thickness)
            case .bottom:
                border.frame = CGRect(x: frame.minX, y: frame.maxY, width: frame.width, height: thickness)
            }
            border.name = side.rawValue
            layer.addSublayer(border)
        }
    }
}

src - https://gist.github.com/MrJackdaw/6ffbc33fc274838412bfe3ad48592b9b

我想要达到的目标:

这里对于每个项目,在每边添加相同的边框宽度会导致 2 个项目中间的边框是双倍宽度。想要摆脱它。

感谢任何帮助

【问题讨论】:

  • 向我们展示您的代码,以及使用此扩展程序运行代码时的输出。
  • 我认为使用两个UIViews 是可能的,其中“边框”是一个高2 磅、宽1 磅的视图。将“实际”视图正确放置在顶部。如果您使用自动布局,最好将这两个视图放在一个容器视图中。
  • 有多种方法可以实现这一点...在您的图像中,您是否显示UIStackView?它是否水平滚动以显示“Sun thru Sat”?或者,它是否连续滚动,再次“环绕”到“太阳”?
  • @dfd,我曾想过使用 UIView,但不认为这会是最有效的解决方案。希望有更好的解决方案。
  • @DonMag,它是一个集合视图,水平滚动并且不会连续滚动。即停在星期六

标签: ios swift


【解决方案1】:

有多种方法可以做到这一点,但您可能喜欢的一种方法是将CAShapeLayer 添加为单个子层,并使用UIBezierPath 作为侧面。

这是一个简单的例子:

class SidesCell: UICollectionViewCell {
    
    enum ViewSide: String {
        case left
        case right
        case top
        case bottom
    }

    var sides: [ViewSide] = []
    
    let sidesLayer: CAShapeLayer = CAShapeLayer()

    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    func commonInit() -> Void {
        contentView.layer.addSublayer(sidesLayer)
        sidesLayer.fillColor = UIColor.clear.cgColor
        sidesLayer.strokeColor = UIColor.gray.cgColor
        sidesLayer.lineWidth = 1.0
    }
    
    // modify this based on what you're setting in the cell
    //  label text, colors, whatever...
    func setData(_ str: String, sides: [ViewSide]) -> Void {
        self.sides = sides
        // use other data
    }

    // this will be called when the cell is ready for layout
    override func layoutSubviews() {
        super.layoutSubviews()

        let pth = UIBezierPath()
        
        if sides.contains(.left) {
            pth.move(to: CGPoint(x: bounds.minX, y: bounds.minY))
            pth.addLine(to: CGPoint(x: bounds.minX, y: bounds.maxY))
        }
        if sides.contains(.top) {
            pth.move(to: CGPoint(x: bounds.minX, y: bounds.minY))
            pth.addLine(to: CGPoint(x: bounds.maxX, y: bounds.minY))
        }
        if sides.contains(.right) {
            pth.move(to: CGPoint(x: bounds.maxX, y: bounds.minY))
            pth.addLine(to: CGPoint(x: bounds.maxX, y: bounds.maxY))
        }
        if sides.contains(.bottom) {
            pth.move(to: CGPoint(x: bounds.minX, y: bounds.maxY))
            pth.addLine(to: CGPoint(x: bounds.maxX, y: bounds.maxY))
        }
        
        sidesLayer.path = pth.cgPath
    }
    
}

然后,在cellForItemAt 中,您将设置每个单元格所需的边。

例如,如果您有 7 个单元格,并且您希望前 6 个上/左/下“侧线”:

    let c = collectionView.dequeueReusableCell(withReuseIdentifier: "myIdentifier", for: indexPath) as! SidesCell
    if indexPath.item == 6 {
        c.setData("Test", sides: [.top, .bottom])
    } else {
        c.setData("Test", sides: [.top, .left, .bottom])
    }
    return c

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-06-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多