如何通过手指绘图显示使用核心图形的隐藏图像?

How to I reveal a hidden image using core graphics by drawing with finger?

我有一个自定义 UIView,我在其中处理来自用户的触摸事件。此视图包含一个 UIImageView,我在其中显示隐藏图像。我想使用来自用户的触摸事件来慢慢显示隐藏的图像。我认为需要使用核心图形,但我不确定该怎么做。如何实现?

我现在拥有的:

public class customTouchView: UIView {
    
    var overlayImageView = UIImageView()
    
    override open func draw(_ rect: CGRect) {
        overlayImageView.frame = rect
    }
    
    func drawAt(_ point: CGPoint) {
        UIGraphicsBeginImageContextWithOptions(overlayImageView.bounds.size, false, UIScreen.main.scale)
        overlayImageView.image?.draw(in: overlayImageView.bounds)
        
        //Draw here, need to somehow reveal the image
        
        
        overlayImageView.image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
    }
    
    init(image: UIImage) {
        super.init(frame: .zero)
        //Just adding overlayImageView as a subview, setting my image and alpha to 0.5. The image should be hidden at the beginning and touch events that draw over the image should reveal the image. 
        addSubview(overlayImageView)
        overlayImageView.image = image
        overlayImageView.alpha = 0.5
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    public override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard let touch = touches.first else { return }
        let point = touch.location(in: self)
        drawAt(point)
    }
    
    public override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard let touch = touches.first else { return }
        let point = touch.location(in: self)
        drawAt(point)
    }
}

您可以使用 CAShapeLayer 作为遮罩层轻松做到这一点...

蒙版中清晰的部分 (alpha = 0) 不会 显示出来,而不清晰的部分 (alpha = 1) 透.

使用触摸将点和线添加到将用作形状图层的.pathUIBezierPath。当您“绘制”路径时,路径将“显示”底层图像。

这是一个简单的例子...

“显示图像视图”(UIImageView 子类):

class RevealImageView: UIImageView {
    
    private var maskPath = UIBezierPath()
    private var maskLayer: CAShapeLayer = CAShapeLayer()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    func commonInit() -> Void {
        // default is false for UIImageView
        isUserInteractionEnabled = true
        // we only want to stroke the path, not fill it
        maskLayer.fillColor = UIColor.clear.cgColor
        // any color will work, as the mask uses the alpha value
        maskLayer.strokeColor = UIColor.white.cgColor
        // adjust drawing-line-width as desired
        maskLayer.lineWidth = 48
        maskLayer.lineCap = .round
        maskLayer.lineJoin = .round
        // set the mask layer
        layer.mask = maskLayer
    }
    override func layoutSubviews() {
        super.layoutSubviews()
        maskLayer.frame = bounds
    }
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard let touch = touches.first else { return }
        let currentPoint = touch.location(in: self)
        maskPath.move(to: currentPoint)
    }
    
    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard let touch = touches.first else { return }
        let currentPoint = touch.location(in: self)
        // add line to on maskPath
        maskPath.addLine(to: currentPoint)
        // update the mask layer path
        maskLayer.path = maskPath.cgPath
    }
    
}

和一个示例视图控制器:

class ViewController: UIViewController {
    
    let myRevealView = RevealImageView(frame: .zero)
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        guard let img = UIImage(named: "sampleImage") else {
            fatalError("Could not load image!!!!")
        }
        myRevealView.image = img
        
        // a view to show the frame for the Reveal Image view
        //  so we know where we can "draw"
        let frameView = UIView()
        frameView.layer.borderWidth = 1
        frameView.layer.borderColor = UIColor.gray.cgColor
        
        frameView.translatesAutoresizingMaskIntoConstraints = false
        myRevealView.translatesAutoresizingMaskIntoConstraints = false

        view.addSubview(frameView)
        view.addSubview(myRevealView)

        // respect safe area
        let g = view.safeAreaLayoutGuide
        
        NSLayoutConstraint.activate([
            
            // 300 x 300 (1:1 ratio)
            myRevealView.widthAnchor.constraint(equalToConstant: 300.0),
            myRevealView.heightAnchor.constraint(equalTo: myRevealView.widthAnchor),
            // centered in view
            myRevealView.centerXAnchor.constraint(equalTo: g.centerXAnchor),
            myRevealView.centerYAnchor.constraint(equalTo: g.centerYAnchor),
            
            // constrain the frame view 2-pts larger
            frameView.widthAnchor.constraint(equalTo: myRevealView.widthAnchor, constant: 2.0),
            frameView.heightAnchor.constraint(equalTo: frameView.widthAnchor),
            // center it
            frameView.centerXAnchor.constraint(equalTo: myRevealView.centerXAnchor),
            frameView.centerYAnchor.constraint(equalTo: myRevealView.centerYAnchor),

        ])
        
    }
}

将其用作我的“sampleImage”:

稍微“画”了一下之后是这样的: