画线并用 UIVisualEffectView 填充
Draw Line and fill with UIVisualEffectView
画线部分设置完成:
func drawLineFrom(_ fromPoint: CGPoint, toPoint: CGPoint) {
let blurEffect = UIBlurEffect(style: UIBlurEffectStyle.dark)
let blurEffectView = UIVisualEffectView(effect: blurEffect)
UIGraphicsBeginImageContextWithOptions(tempImageView.frame.size, false, UIScreen.main.scale)
let context = UIGraphicsGetCurrentContext()
tempImageView.image?.draw(in: CGRect(x: 0, y: 0, width: tempImageView.frame.size.width, height: tempImageView.frame.size.height), blendMode: .normal, alpha: 1.0)
context?.move(to: CGPoint(x: fromPoint.x, y: fromPoint.y))
context?.addLine(to: CGPoint(x: toPoint.x, y: toPoint.y))
context?.setLineCap(.round)
context?.setLineWidth(brushWidth)
context?.setStrokeColor(blurEffectView(effect: blurEffect))
context?.setBlendMode(.normal)
context!.strokePath()
var img = UIGraphicsGetImageFromCurrentImageContext()
tempImageView.image = img
tempImageView.alpha = opacity
UIGraphicsEndImageContext()
}
它基本上使用了 touchesBegan、touchesMoved 和 touchesEnded,这就是 fromPoint
和 toPoint
的来源。
就像您已经看到的那样,我正在尝试用 UIVisualEffectView 而不是 Color 来填充这一行。显然我的方法并没有真正奏效。
执行此操作的最佳解决方案是什么?
设置
A UIVisualEffectView
本身并没有任何内容,而是取决于它下面的视图。如果你想用 UIVisualEffect
给出绘图的效果,你应该构建你想要在其上绘图的视图层次结构。也许像带有图像视图的视图,显示一些图像,然后在其上显示效果视图,例如:
let imageView = UIImageView(image: UIImage(named: "image.jpg"))
let blurEffect = UIBlurEffect(style: .dark)
let effectView = UIVisualEffectView(effect: blurEffect)
effectView.frame = imageView.bounds
let view = UIView(frame: imageView.bounds)
view.addSubview(imageView)
view.addSubview(effectView)
然后您需要在此状态下对视图层次结构进行快照。如果它被触摸完全填充,这将像视图一样。您可以通过在 UIView
:
上添加扩展名来做到这一点
extension UIView
{
var snapshot: UIImage?
{
UIGraphicsBeginImageContextWithOptions(self.bounds.size, false, 0)
self.drawHierarchy(in: self.bounds, afterScreenUpdates: true)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
}
和
let image = view.snapshot!
我们现在可以将 UIVisualEffectView
替换为 UIImageView
保存我们的快照视图层次结构:
effectView.removeFromSuperview()
let topImageView = UIImageView(image: image)
view.addSubview(topImageView)
然后您可以通过声明 CAShapeLayer
属性 并将其设置为 topImageView
的遮罩层来遮罩 topImageView
绘制路径
let shapeLayer = CAShapeLayer()
和
topImageView.layer.mask = shapeLayer
绘图
现在您可以编写 drawLine
函数:
func drawLine(from fromPoint: CGPoint, to toPoint: CGPoint)
{
let path: UIBezierPath
if let layerPath = self.shapeLayer.path
{
path = UIBezierPath(cgPath: layerPath)
}
else
{
path = UIBezierPath()
}
path.move(to: fromPoint)
path.addLine(to: toPoint)
self.shapeLayer.path = path.cgPath
self.shapeLayer.lineWidth = brushWidth
self.shapeLayer.lineCap = "round"
self.shapeLayer.strokeColor = UIColor.black.cgColor
}
在没有调用 drawLine
的实时视图中的游乐场中,我的视图如下所示:
调用后:
drawLine(from: CGPoint(x: 0, y: 0), to: CGPoint(x: imageView.frame.maxX, y: imageView.frame.maxY))
drawLine(from: CGPoint(x: 0, y: imageView.frame.maxY), to: CGPoint(x: imageView.frame.maxX, y: 0))
看起来像:
您应该知道这是处理器密集型的并且可能不高效。
更新
如果以后要更新视图层次结构或视觉效果,可以将 UIVisualEffectView
保留在视图层次结构中,而不是调用 removeFromSuperview
并隐藏它。然后重复快照和遮罩的过程。例如:
func updateMask(with visualEffect: UIVisualEffect)
{
topImageView.isHidden = true
effectView.isHidden = false
effectView.effect = visualEffect
topImageView.image = view.snapshot
topImageView.isHidden = false
effectView.isHidden = true
}
你可以看到我在游乐场使用的代码here.
画线部分设置完成:
func drawLineFrom(_ fromPoint: CGPoint, toPoint: CGPoint) {
let blurEffect = UIBlurEffect(style: UIBlurEffectStyle.dark)
let blurEffectView = UIVisualEffectView(effect: blurEffect)
UIGraphicsBeginImageContextWithOptions(tempImageView.frame.size, false, UIScreen.main.scale)
let context = UIGraphicsGetCurrentContext()
tempImageView.image?.draw(in: CGRect(x: 0, y: 0, width: tempImageView.frame.size.width, height: tempImageView.frame.size.height), blendMode: .normal, alpha: 1.0)
context?.move(to: CGPoint(x: fromPoint.x, y: fromPoint.y))
context?.addLine(to: CGPoint(x: toPoint.x, y: toPoint.y))
context?.setLineCap(.round)
context?.setLineWidth(brushWidth)
context?.setStrokeColor(blurEffectView(effect: blurEffect))
context?.setBlendMode(.normal)
context!.strokePath()
var img = UIGraphicsGetImageFromCurrentImageContext()
tempImageView.image = img
tempImageView.alpha = opacity
UIGraphicsEndImageContext()
}
它基本上使用了 touchesBegan、touchesMoved 和 touchesEnded,这就是 fromPoint
和 toPoint
的来源。
就像您已经看到的那样,我正在尝试用 UIVisualEffectView 而不是 Color 来填充这一行。显然我的方法并没有真正奏效。 执行此操作的最佳解决方案是什么?
设置
A UIVisualEffectView
本身并没有任何内容,而是取决于它下面的视图。如果你想用 UIVisualEffect
给出绘图的效果,你应该构建你想要在其上绘图的视图层次结构。也许像带有图像视图的视图,显示一些图像,然后在其上显示效果视图,例如:
let imageView = UIImageView(image: UIImage(named: "image.jpg"))
let blurEffect = UIBlurEffect(style: .dark)
let effectView = UIVisualEffectView(effect: blurEffect)
effectView.frame = imageView.bounds
let view = UIView(frame: imageView.bounds)
view.addSubview(imageView)
view.addSubview(effectView)
然后您需要在此状态下对视图层次结构进行快照。如果它被触摸完全填充,这将像视图一样。您可以通过在 UIView
:
extension UIView
{
var snapshot: UIImage?
{
UIGraphicsBeginImageContextWithOptions(self.bounds.size, false, 0)
self.drawHierarchy(in: self.bounds, afterScreenUpdates: true)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
}
和
let image = view.snapshot!
我们现在可以将 UIVisualEffectView
替换为 UIImageView
保存我们的快照视图层次结构:
effectView.removeFromSuperview()
let topImageView = UIImageView(image: image)
view.addSubview(topImageView)
然后您可以通过声明 CAShapeLayer
属性 并将其设置为 topImageView
topImageView
绘制路径
let shapeLayer = CAShapeLayer()
和
topImageView.layer.mask = shapeLayer
绘图
现在您可以编写 drawLine
函数:
func drawLine(from fromPoint: CGPoint, to toPoint: CGPoint)
{
let path: UIBezierPath
if let layerPath = self.shapeLayer.path
{
path = UIBezierPath(cgPath: layerPath)
}
else
{
path = UIBezierPath()
}
path.move(to: fromPoint)
path.addLine(to: toPoint)
self.shapeLayer.path = path.cgPath
self.shapeLayer.lineWidth = brushWidth
self.shapeLayer.lineCap = "round"
self.shapeLayer.strokeColor = UIColor.black.cgColor
}
在没有调用 drawLine
的实时视图中的游乐场中,我的视图如下所示:
调用后:
drawLine(from: CGPoint(x: 0, y: 0), to: CGPoint(x: imageView.frame.maxX, y: imageView.frame.maxY))
drawLine(from: CGPoint(x: 0, y: imageView.frame.maxY), to: CGPoint(x: imageView.frame.maxX, y: 0))
看起来像:
您应该知道这是处理器密集型的并且可能不高效。
更新
如果以后要更新视图层次结构或视觉效果,可以将 UIVisualEffectView
保留在视图层次结构中,而不是调用 removeFromSuperview
并隐藏它。然后重复快照和遮罩的过程。例如:
func updateMask(with visualEffect: UIVisualEffect)
{
topImageView.isHidden = true
effectView.isHidden = false
effectView.effect = visualEffect
topImageView.image = view.snapshot
topImageView.isHidden = false
effectView.isHidden = true
}
你可以看到我在游乐场使用的代码here.