在不同的边上添加不同宽度的边框

Posted

技术标签:

【中文标题】在不同的边上添加不同宽度的边框【英文标题】: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,它是一个集合视图,水平滚动并且不会连续滚动。即停在星期六 【参考方案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

【讨论】:

以上是关于在不同的边上添加不同宽度的边框的主要内容,如果未能解决你的问题,请参考以下文章

Firefox 中不同单元格的边框宽度显示不同

ckeditor里怎么设置表格的外边框与内边框的宽度

为啥 IE 和 Chrome 呈现 css 边框底部宽度不同?

input和select在浏览器中宽度不同解决方案(原创)

使用 CSS3 Rotate 和 Firefox 时如何防止不同宽度的边框出现接缝?

R语言绘图边框