iosswiftuigraphicscontextasyncdisplaykitcgcolor

Incorrect upper and lower line color with UIGraphicsGetCurrentContext


The project uses ASDK (Texture). There is a main node, it has a subnode, under certain circumstances it is necessary to show the outer boundary of the subnode, in this project it is done by adding a border node and UIGraphicsGetCurrentContext, also the task is to border line width be the same on all devices regardless of UIScreen.main.scale. I did a test code and everything works fine, except that the lower and upper lines have a smaller width than the side lines (which are displayed correctly). Please tell how to fix it? I can not spread the screenshoot of the whole screen, but I uploaded the part so I can show what the problem is. You can see the green color on the bottom line, this should not be.

enter image description here

private func enableEditingMode() {
        let solidBorderStyle = BorderStyle.solid
        let border = ASBorderNode(shapeType: self.shapeType, borderType: solidBorderStyle)
        border.frame = ASBorderNode.calculateFrame(self.shapeType, borderType: solidBorderStyle, superView: frame)
        supernode?.insertSubnode(border, at: 0)
    }

enum BorderStyle {
    case dashed
    case solid
    case solidLight

    var lineWidth: CGFloat {
        switch self {
        case .dashed:
            return 1
        case .solid:
            return 6 / UIScreen.main.scale
        case .solidLight:
            return 2
        }
    }

}

class ASBorderNode: ASDisplayNode {

    private (set) var shapeType: TemplateLayoutElement.Shape?
    private (set) var borderType: BorderStyle


    init(shapeType:TemplateLayoutElement.Shape?, borderType:BorderStyle = .dashed) {
        self.borderType = borderType
        self.shapeType = shapeType
        super.init()
        self.isOpaque = false
    }

    class func calculateFrame(_ shapeType: TemplateLayoutElement.Shape?, borderType: BorderStyle, superView frame: CGRect) -> CGRect {
        switch borderType {
        case .solid:
            let lineWidth = borderType.lineWidth //* UIScreen.main.scale
            let widthHeightValue = lineWidth * 2
            return CGRect(x: -lineWidth + frame.origin.x, y: -lineWidth + frame.origin.y, width: frame.width + widthHeightValue, height: frame.height + widthHeightValue)
        default:
            assertionFailure("Implement for specific style")
            return .zero
        }
    }

    override class func draw(_ bounds: CGRect, withParameters parameters: Any?, isCancelled isCancelledBlock: () -> Bool, isRasterizing: Bool) {
        if let context = UIGraphicsGetCurrentContext(),
            let parameters = parameters as? ASBorderNode {

            switch parameters.borderType {
            case .dashed:
                break
            case .solid:
                context.setStrokeColor(UIColor.black.withAlphaComponent(0.5).cgColor)
                context.setFillColor(UIColor.clear.cgColor)
                context.setLineWidth(parameters.borderType.lineWidth)
            case .solidLight:
                break
            }

            switch parameters.shapeType {
            case .circle?:
                break
            default:
                switch parameters.borderType {
                case .solid:
                    debugPrint("Bounds", bounds)
                    let frame = bounds.insetBy(dx: parameters.borderType.lineWidth / UIScreen.main.scale, dy: parameters.borderType.lineWidth / UIScreen.main.scale)
                    debugPrint("insetBy", frame)
                    context.addRect(frame)
                default:
                    break
                }
            }

            context.strokePath()
        }
    }

    override func drawParameters(forAsyncLayer layer: _ASDisplayLayer) -> NSObjectProtocol? {
        return self
    }

}

Update 1: Another example enter image description here


Solution

  • I believe what you're seeing is a stroke artifact. The only way I know how to avoid them is to build a path that corresponds to what you want the stroke shape to be and use fill (so you're layering filled objects on top of each other, rather than just stroking the base path).