我创建了具有自定义形状的UIBezierPath,然后我总是将其屏蔽为图像,但我总是得到空图像这是我的代码首先,我创建了路径,然后创建了图像,最后创建了我的遮罩,但是它不起作用
这里是图像,我需要对其进行遮罩dropbox.com/s/tnxgx7g1uvb1zj7/TeethMask.png?dl=0,这里是UIBazier路径dropbox.com/s/nz93n1vgvj6c6y0/…...我需要在此路径中对该图像进行遮罩输出是这样的https://www.dropbox.com/s/gueyhdmmdcfvyiq/image.png?dl=0
这里是ViewController类
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let tapGR = UITapGestureRecognizer(target: self, action: #selector(didTap))
self.view.addGestureRecognizer(tapGR)
}
@objc func didTap(tapGR: UITapGestureRecognizer) {
let tapPoint = tapGR.location(in: self.view)
if #available(iOS 11.0, *) {
let shapeView = ShapeView(origin: tapPoint)
self.view.addSubview(shapeView)
} else {
// Fallback on earlier versions
}
}
}
这里是ShapeView类
import UIKit
@available(iOS 11.0, *)
class ShapeView: UIView {
let size: CGFloat = 150
let lineWidth: CGFloat = 3
var fillColor: UIColor!
var path: UIBezierPath!
init(origin: CGPoint) {
super.init(frame: CGRect(x: 0.0, y: 0.0, width: size, height: size))
self.fillColor = randomColor()
self.path = mouthPath()
self.center = origin
self.backgroundColor = UIColor.clear
}
func randomColor() -> UIColor {
let hue:CGFloat = CGFloat(Float(arc4random()) / Float(UINT32_MAX))
return UIColor(hue: hue, saturation: 0.8, brightness: 1.0, alpha: 0.8)
}
func mouthPath() -> UIBezierPath{
let pointsArray = [CGPoint(x:36 , y:36 ),CGPoint(x:41 , y:36 ),CGPoint(x:45 , y:36 ),CGPoint(x:49 , y:36 ),CGPoint(x:53 , y:36 ),CGPoint(x:58 , y: 37),CGPoint(x:64 , y:37 ),CGPoint(x:69 , y:36 ),CGPoint(x:65 , y:29 ),CGPoint(x:58 , y:24 ),CGPoint(x:50 , y:22 ),CGPoint(x:42 , y:23 ),CGPoint(x:36 , y:28 ),CGPoint(x:32 , y:35 )]
let newPath = UIBezierPath()
let factor:CGFloat = 10
for i in 0...pointsArray.count - 1 { // last point is 0,0
let point = pointsArray[i]
let currentPoint1 = CGPoint(x: point.x * factor , y: point.y * factor)
if i == 0 {
newPath.move(to: currentPoint1)
} else {
newPath.addLine(to: currentPoint1)
}
}
newPath.addLine(to: CGPoint(x: pointsArray[0].x * factor, y: pointsArray[0].y * factor))
newPath.close()
let imageTemplate = UIImageView()
imageTemplate.image = UIImage(named: "TeethMask")
self.addSubview(imageTemplate)
self.bringSubviewToFront(imageTemplate)
imageTemplate.frame = self.frame
let mask = CAShapeLayer(layer: self.layer)
mask.frame = newPath.bounds
mask.fillColor = UIColor.clear.cgColor
mask.strokeColor = UIColor.black.cgColor
mask.path = newPath.cgPath
mask.shouldRasterize = true
imageTemplate.layer.mask = mask
imageTemplate.layer.addSublayer(mask)
}
}
您链接的“牙齿”图像:
的原始大小为461 x 259
。因此,我将使用200 x 112
的比例“目标”大小。
首先,形状图层在左上角使用0,0
。您原始的点阵:
let pointsArray = [
CGPoint(x: 36, y: 36),
CGPoint(x: 41, y: 36),
CGPoint(x: 45, y: 36),
CGPoint(x: 49, y: 36),
CGPoint(x: 53, y: 36),
CGPoint(x: 58, y: 37),
CGPoint(x: 64, y: 37),
CGPoint(x: 69, y: 36),
CGPoint(x: 65, y: 29),
CGPoint(x: 58, y: 24),
CGPoint(x: 50, y: 22),
CGPoint(x: 42, y: 23),
CGPoint(x: 36, y: 28),
CGPoint(x: 32, y: 35),
]
赋予此形状:如果我们反转y坐标:
let pointsArray = [ CGPoint(x: 36.0, y: 23.0), CGPoint(x: 41.0, y: 23.0), CGPoint(x: 45.0, y: 23.0), CGPoint(x: 49.0, y: 23.0), CGPoint(x: 53.0, y: 23.0), CGPoint(x: 58.0, y: 22.0), CGPoint(x: 64.0, y: 22.0), CGPoint(x: 69.0, y: 23.0), CGPoint(x: 65.0, y: 30.0), CGPoint(x: 58.0, y: 35.0), CGPoint(x: 50.0, y: 37.0), CGPoint(x: 42.0, y: 36.0), CGPoint(x: 36.0, y: 31.0), CGPoint(x: 32.0, y: 24.0), ]
我们得到这个形状:如果您的形状这样偏移,将很难使事情正确地“对齐”,因此我们可以“标准化”从左上角开始的点:
let pointsArray: [CGPoint] = [ CGPoint(x: 4.0, y: 1.0), CGPoint(x: 9.0, y: 1.0), CGPoint(x: 13.0, y: 1.0), CGPoint(x: 17.0, y: 1.0), CGPoint(x: 21.0, y: 1.0), CGPoint(x: 26.0, y: 0.0), CGPoint(x: 32.0, y: 0.0), CGPoint(x: 37.0, y: 1.0), CGPoint(x: 33.0, y: 8.0), CGPoint(x: 26.0, y: 13.0), CGPoint(x: 18.0, y: 15.0), CGPoint(x: 10.0, y: 14.0), CGPoint(x: 4.0, y: 9.0), CGPoint(x: 0.0, y: 2.0), ]
导致:但是,我们希望形状适合图像,因此我们可以将
UIBezierPath
缩放到imageView的边界:
// need to scale the path to self.bounds let scaleW = bounds.width / pth.bounds.width let scaleH = bounds.height / pth.bounds.height let trans = CGAffineTransform(scaleX: scaleW, y: scaleH) pth.apply(trans)
我们在这里:唯一剩下的就是使用它作为图像的蒙版。
我将建议使用
UIImageView
而不是UIView
作为子类...这样,您可以设置.image
属性,而无需将其他视图添加为子视图。另外,我认为您会发现,在控制器代码中而不是在自定义类中管理自定义蒙版图像的大小要容易得多。这里是演示视图控制器和自定义
MouthShapeView
:
class TeethViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() let tapGR = UITapGestureRecognizer(target: self, action: #selector(didTap)) self.view.addGestureRecognizer(tapGR) } @objc func didTap(tapGR: UITapGestureRecognizer) { let tapPoint = tapGR.location(in: self.view) if #available(iOS 11.0, *) { // make sure you can load the image if let img = UIImage(named: "TeethMask") { // create custom ShapeView with image let shapeView = MouthShapeView(image: img) // if you want to use original image proportions // set the width you want and calculate a proportional height // based on the original image size let targetWidth: CGFloat = 200.0 let targetHeight: CGFloat = img.size.height / img.size.width * targetWidth // set the frame size shapeView.frame.size = CGSize(width: targetWidth, height: targetHeight) // set the frame center shapeView.center = tapPoint // add it self.view.addSubview(shapeView) } } else { // Fallback on earlier versions } } } @available(iOS 11.0, *) class MouthShapeView: UIImageView { let pointsArray: [CGPoint] = [ CGPoint(x: 4.0, y: 1.0), CGPoint(x: 9.0, y: 1.0), CGPoint(x: 13.0, y: 1.0), CGPoint(x: 17.0, y: 1.0), CGPoint(x: 21.0, y: 1.0), CGPoint(x: 26.0, y: 0.0), CGPoint(x: 32.0, y: 0.0), CGPoint(x: 37.0, y: 1.0), CGPoint(x: 33.0, y: 8.0), CGPoint(x: 26.0, y: 13.0), CGPoint(x: 18.0, y: 15.0), CGPoint(x: 10.0, y: 14.0), CGPoint(x: 4.0, y: 9.0), CGPoint(x: 0.0, y: 2.0), ] let maskLayer = CAShapeLayer() override init(image: UIImage?) { super.init(image: image) maskLayer.fillColor = UIColor.black.cgColor } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func layoutSubviews() { super.layoutSubviews() let newPath = UIBezierPath() pointsArray.forEach { p in if p == pointsArray.first { newPath.move(to: p) } else { newPath.addLine(to: p) } } newPath.close() // need to scale the path to self.bounds let scaleW = bounds.width / newPath.bounds.width let scaleH = bounds.height / newPath.bounds.height let trans = CGAffineTransform(scaleX: scaleW, y: scaleH) newPath.apply(trans) maskLayer.path = newPath.cgPath layer.mask = maskLayer } }
当您运行该代码并点击视图时,将获得以下信息: