如何通过手指绘图显示使用核心图形的隐藏图像?
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) 会透.
使用触摸将点和线添加到将用作形状图层的.path
的UIBezierPath
。当您“绘制”路径时,路径将“显示”底层图像。
这是一个简单的例子...
“显示图像视图”(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”:
稍微“画”了一下之后是这样的:
我有一个自定义 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) 会透.
使用触摸将点和线添加到将用作形状图层的.path
的UIBezierPath
。当您“绘制”路径时,路径将“显示”底层图像。
这是一个简单的例子...
“显示图像视图”(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”:
稍微“画”了一下之后是这样的: