You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何创建仅四角带边框的方形UIView?二维码扫描UI背景处理

实现二维码扫描框:四角边框+深色遮罩效果

一、仅四角带边框的扫描框实现

你可以通过自定义UIView并重写draw(_ rect:)方法来绘制四角边框,精准控制每个角的样式:

class ScanBorderView: UIView {
    // 可自定义的边框属性
    var borderColor: UIColor = .white {
        didSet { setNeedsDisplay() }
    }
    var borderWidth: CGFloat = 2 {
        didSet { setNeedsDisplay() }
    }
    var cornerLength: CGFloat = 20 {
        didSet { setNeedsDisplay() }
    }
    
    override func draw(_ rect: CGRect) {
        super.draw(rect)
        guard let context = UIGraphicsGetCurrentContext() else { return }
        
        context.setStrokeColor(borderColor.cgColor)
        context.setLineWidth(borderWidth)
        context.setLineCap(.square)
        
        // 左上角:顶部横线 + 左侧竖线
        context.move(to: CGPoint(x: rect.minX, y: rect.minY + cornerLength))
        context.addLine(to: CGPoint(x: rect.minX, y: rect.minY))
        context.addLine(to: CGPoint(x: rect.minX + cornerLength, y: rect.minY))
        
        // 右上角:顶部横线 + 右侧竖线
        context.move(to: CGPoint(x: rect.maxX - cornerLength, y: rect.minY))
        context.addLine(to: CGPoint(x: rect.maxX, y: rect.minY))
        context.addLine(to: CGPoint(x: rect.maxX, y: rect.minY + cornerLength))
        
        // 左下角:底部横线 + 左侧竖线
        context.move(to: CGPoint(x: rect.minX, y: rect.maxY - cornerLength))
        context.addLine(to: CGPoint(x: rect.minX, y: rect.maxY))
        context.addLine(to: CGPoint(x: rect.minX + cornerLength, y: rect.maxY))
        
        // 右下角:底部横线 + 右侧竖线
        context.move(to: CGPoint(x: rect.maxX - cornerLength, y: rect.maxY))
        context.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY))
        context.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY - cornerLength))
        
        context.strokePath()
    }
}

使用时直接实例化并设置位置尺寸:

let scanBorder = ScanBorderView(frame: CGRect(x: 0, y: 0, width: 250, height: 250))
scanBorder.center = view.center
view.addSubview(scanBorder)

二、周围深色背景+方形透明的遮罩实现

通过CAShapeLayer创建遮罩层,核心是绘制全屏路径并减去中间扫描框路径,实现中间透明、周围深色的效果:

class ScanMaskView: UIView {
    // 扫描框尺寸,可调整
    var scanFrame: CGRect = CGRect(x: 0, y: 0, width: 250, height: 250) {
        didSet { updateMask() }
    }
    // 遮罩背景色,支持透明度
    var maskColor: UIColor = UIColor.black.withAlphaComponent(0.6) {
        didSet { backgroundColor = maskColor }
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupView()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setupView()
    }
    
    private func setupView() {
        backgroundColor = maskColor
        updateMask()
    }
    
    private func updateMask() {
        let maskLayer = CAShapeLayer()
        let fullPath = UIBezierPath(rect: bounds)
        let scanPath = UIBezierPath(rect: scanFrame)
        
        // 从全屏路径中减去扫描框路径
        fullPath.append(scanPath)
        fullPath.usesEvenOddFillRule = true
        
        maskLayer.path = fullPath.cgPath
        maskLayer.fillRule = .evenOdd
        layer.mask = maskLayer
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        // 确保屏幕旋转或尺寸变化时,扫描框保持居中
        scanFrame = scanFrame.offsetBy(dx: center.x - scanFrame.midX, dy: center.y - scanFrame.midY)
        updateMask()
    }
}

组合使用遮罩和边框视图:

let maskView = ScanMaskView(frame: view.bounds)
// 设置扫描框居中
maskView.scanFrame.origin = CGPoint(x: view.center.x - 125, y: view.center.y - 125)
view.addSubview(maskView)

// 添加四角边框到遮罩层上
let scanBorder = ScanBorderView(frame: maskView.scanFrame)
maskView.addSubview(scanBorder)

内容的提问来源于stack exchange,提问作者phast

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 19:35:38