SwiftUI QR code scan reactangle with border corner

Viewed 1256

QR code with corner border line

My requirement has to show QR code within the 4 corner lines, Scanning QR code is done. Currently .overlay( RoundedRectangle is showing full border., but I need to draw a below, any idea?

CodeScannerView(codeTypes: [.qr], simulatedData: "Some simulated data", completion: self.handleScan)
                 .padding(.horizontal, 40)
                 .cornerRadius(35)
                 .overlay(
                     RoundedRectangle(cornerRadius: 20)
                         .stroke(Color.yellow, lineWidth: 5)
                 )
                 .frame(width: 350, height: 250)
                 .padding(.bottom , 50)``` 


2 Answers

You can achieve that border with stroke(). It does take some more parameters like a StrokeStyle. With a little bit of calculations you can achieve that result. Here is an example:

struct ContentView : View {
    var body : some View {

        Text("Hello World")
            .frame(width: 275, height: 275)
            .overlay(
                Rectangle()
                    .stroke(Color.yellow, style: StrokeStyle(lineWidth: 5.0,lineCap: .round, lineJoin: .bevel, dash: [60, 215], dashPhase: 29))
            )
    }
}

Basically you will have to pass an array of dash, where first number is the length of your yellow border. The 215 is the spacing.

If you calculate 60*4 + 215*4, you will have to get the same as calulcating the scope of your actual view. For me its 275*4. Then play around with the dashPhase and you can achieve a good result.

The solution posted by @davidev is simple and works for static use cases. However I implemented a much more flexible approach using path:

struct ScanOverlayView: View {
    var body: some View {
        GeometryReader { geometry in
            let cutoutWidth: CGFloat = min(geometry.size.width, geometry.size.height) / 1.5

            ZStack {
                Rectangle()
                    .fill(Color.black.opacity(0.5))
                    
                RoundedRectangle(cornerRadius: 20)
                    .fill(Color.black)
                    .frame(width: cutoutWidth, height: cutoutWidth, alignment: .center)
                    .blendMode(.destinationOut)
            }.compositingGroup()
            
            Path { path in
                
                let left = (geometry.size.width - cutoutWidth) / 2.0
                let right = left + cutoutWidth
                let top = (geometry.size.height - cutoutWidth) / 2.0
                let bottom = top + cutoutWidth
                
                path.addPath(
                    createCornersPath(
                        left: left, top: top,
                        right: right, bottom: bottom,
                        cornerRadius: 40, cornerLength: 20
                    )
                )
            }
            .stroke(Color.blue, lineWidth: 8)
            .frame(width: cutoutWidth, height: cutoutWidth, alignment: .center)
            .aspectRatio(1, contentMode: .fit)
        }
    }
    
    private func createCornersPath(
        left: CGFloat,
        top: CGFloat,
        right: CGFloat,
        bottom: CGFloat,
        cornerRadius: CGFloat,
        cornerLength: CGFloat
    ) -> Path {
        var path = Path()

        // top left
        path.move(to: CGPoint(x: left, y: (top + cornerRadius / 2.0)))
        path.addArc(
            center: CGPoint(x: (left + cornerRadius / 2.0), y: (top + cornerRadius / 2.0)),
            radius: cornerRadius / 2.0,
            startAngle: Angle(degrees: 180.0),
            endAngle: Angle(degrees: 270.0),
            clockwise: false
        )

        path.move(to: CGPoint(x: left + (cornerRadius / 2.0), y: top))
        path.addLine(to: CGPoint(x: left + (cornerRadius / 2.0) + cornerLength, y: top))

        path.move(to: CGPoint(x: left, y: top + (cornerRadius / 2.0)))
        path.addLine(to: CGPoint(x: left, y: top + (cornerRadius / 2.0) + cornerLength))

        // top right
        path.move(to: CGPoint(x: right - cornerRadius / 2.0, y: top))
        path.addArc(
            center: CGPoint(x: (right - cornerRadius / 2.0), y: (top + cornerRadius / 2.0)),
            radius: cornerRadius / 2.0,
            startAngle: Angle(degrees: 270.0),
            endAngle: Angle(degrees: 360.0),
            clockwise: false
        )

        path.move(to: CGPoint(x: right - (cornerRadius / 2.0), y: top))
        path.addLine(to: CGPoint(x: right - (cornerRadius / 2.0) - cornerLength, y: top))

        path.move(to: CGPoint(x: right, y: top + (cornerRadius / 2.0)))
        path.addLine(to: CGPoint(x: right, y: top + (cornerRadius / 2.0) + cornerLength))

        // bottom left
        path.move(to: CGPoint(x: left + cornerRadius / 2.0, y: bottom))
        path.addArc(
            center: CGPoint(x: (left + cornerRadius / 2.0), y: (bottom - cornerRadius / 2.0)),
            radius: cornerRadius / 2.0,
            startAngle: Angle(degrees: 90.0),
            endAngle: Angle(degrees: 180.0),
            clockwise: false
        )
        
        path.move(to: CGPoint(x: left + (cornerRadius / 2.0), y: bottom))
        path.addLine(to: CGPoint(x: left + (cornerRadius / 2.0) + cornerLength, y: bottom))

        path.move(to: CGPoint(x: left, y: bottom - (cornerRadius / 2.0)))
        path.addLine(to: CGPoint(x: left, y: bottom - (cornerRadius / 2.0) - cornerLength))

        // bottom right
        path.move(to: CGPoint(x: right, y: bottom - cornerRadius / 2.0))
        path.addArc(
            center: CGPoint(x: (right - cornerRadius / 2.0), y: (bottom - cornerRadius / 2.0)),
            radius: cornerRadius / 2.0,
            startAngle: Angle(degrees: 0.0),
            endAngle: Angle(degrees: 90.0),
            clockwise: false
        )
        
        path.move(to: CGPoint(x: right - (cornerRadius / 2.0), y: bottom))
        path.addLine(to: CGPoint(x: right - (cornerRadius / 2.0) - cornerLength, y: bottom))

        path.move(to: CGPoint(x: right, y: bottom - (cornerRadius / 2.0)))
        path.addLine(to: CGPoint(x: right, y: bottom - (cornerRadius / 2.0) - cornerLength))

        return path
    }
}

This will result in:

enter image description here

Related