如何用 UIControl 屏蔽 UIImage?
How can you mask a UIImage with a UIControl?
我可以将一个 UIImage 的掩码 属性 设置为另一个 UIView,但是如果我将 UIImage 的掩码 属性 设置为一个 UISwitch,则 UIImage 和 UISwitch 不显示。
recordMicSwitch = UISwitch()
guard let sc = recordMicSwitch else { return }
sc.frame = CGRect(x: deviceWidth - sc.frame.size.width - rightMargin, y: yPos, width: 0, height: 0)
sc.onTintColor = UIColor(red: 0, green: 0.717, blue: 1.0, alpha: 1.0)
view.addSubview(sc)
let image: UIImage = UIImage(named: "testBGGradient.png")!
let bgImage = UIImageView(image: image)
bgImage.frame = CGRect(x:200, y:120, width:bgImage.frame.width/2, height:bgImage.frame.height/2)
bgImage.mask = recordMicSwitch!
self.view.addSubview(bgImage)
所以这实际上并不只是将我们的图像屏蔽到UISwitch
那么简单。
这种简单的方法之所以行不通,是因为掩码的实际工作原理。当我们像您建议的那样遮盖图像时,我们会采用另一个视图的形状并将其应用于我们的图像。然后,我们的图像实际上被添加到父级。我们最终得到的是一个被切割成开关形状的图像(该图像接收 none 个开关事件)。
我们实际上要做的是更多地参与。我们需要将我们的图像添加到开关 subview
的不同部分,并将其遮盖起来。
为了方便起见,我制作了一个自定义开关 class 来完成幕后的繁重工作:
class ImageTintSwitch: UISwitch {
init(tintImage: UIImage) {
super.init(frame: .zero)
// Make sure we have subviews & grab the first one
guard let element = subviews.first else { return }
// Loop through only the subviews that clipToBounds inside the one we grabbed
for (index, view) in element.subviews.enumerated() where view.clipsToBounds {
// Add our image only where we need it
configure(with: tintImage, on: element, maskedTo: view, atIndex: index)
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func configure(with image: UIImage, on parent: UIView, maskedTo view: UIView, atIndex index: Int) {
// Make an imageView with our image
let imageView: UIImageView = {
let view = UIImageView(image: image)
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
// Insert our new imageView only where we need it
parent.insertSubview(imageView, at: index)
// Mask our imageView to the views that we found
imageView.mask = view
// Constrain our imageView to match the parent view
NSLayoutConstraint.activate([
imageView.centerXAnchor.constraint(equalTo: parent.centerXAnchor),
imageView.centerYAnchor.constraint(equalTo: parent.centerYAnchor),
imageView.widthAnchor.constraint(equalTo: parent.widthAnchor),
imageView.heightAnchor.constraint(equalTo: parent.heightAnchor)
])
}
}
要使用这个自定义开关,我们只需使用下面的代码:
let customSwitch = ImageTintSwitch(tintImage: UIImage(named: "gradient.jpg") ?? UIImage())
结果如下:
我可以将一个 UIImage 的掩码 属性 设置为另一个 UIView,但是如果我将 UIImage 的掩码 属性 设置为一个 UISwitch,则 UIImage 和 UISwitch 不显示。
recordMicSwitch = UISwitch()
guard let sc = recordMicSwitch else { return }
sc.frame = CGRect(x: deviceWidth - sc.frame.size.width - rightMargin, y: yPos, width: 0, height: 0)
sc.onTintColor = UIColor(red: 0, green: 0.717, blue: 1.0, alpha: 1.0)
view.addSubview(sc)
let image: UIImage = UIImage(named: "testBGGradient.png")!
let bgImage = UIImageView(image: image)
bgImage.frame = CGRect(x:200, y:120, width:bgImage.frame.width/2, height:bgImage.frame.height/2)
bgImage.mask = recordMicSwitch!
self.view.addSubview(bgImage)
所以这实际上并不只是将我们的图像屏蔽到UISwitch
那么简单。
这种简单的方法之所以行不通,是因为掩码的实际工作原理。当我们像您建议的那样遮盖图像时,我们会采用另一个视图的形状并将其应用于我们的图像。然后,我们的图像实际上被添加到父级。我们最终得到的是一个被切割成开关形状的图像(该图像接收 none 个开关事件)。
我们实际上要做的是更多地参与。我们需要将我们的图像添加到开关 subview
的不同部分,并将其遮盖起来。
为了方便起见,我制作了一个自定义开关 class 来完成幕后的繁重工作:
class ImageTintSwitch: UISwitch {
init(tintImage: UIImage) {
super.init(frame: .zero)
// Make sure we have subviews & grab the first one
guard let element = subviews.first else { return }
// Loop through only the subviews that clipToBounds inside the one we grabbed
for (index, view) in element.subviews.enumerated() where view.clipsToBounds {
// Add our image only where we need it
configure(with: tintImage, on: element, maskedTo: view, atIndex: index)
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func configure(with image: UIImage, on parent: UIView, maskedTo view: UIView, atIndex index: Int) {
// Make an imageView with our image
let imageView: UIImageView = {
let view = UIImageView(image: image)
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
// Insert our new imageView only where we need it
parent.insertSubview(imageView, at: index)
// Mask our imageView to the views that we found
imageView.mask = view
// Constrain our imageView to match the parent view
NSLayoutConstraint.activate([
imageView.centerXAnchor.constraint(equalTo: parent.centerXAnchor),
imageView.centerYAnchor.constraint(equalTo: parent.centerYAnchor),
imageView.widthAnchor.constraint(equalTo: parent.widthAnchor),
imageView.heightAnchor.constraint(equalTo: parent.heightAnchor)
])
}
}
要使用这个自定义开关,我们只需使用下面的代码:
let customSwitch = ImageTintSwitch(tintImage: UIImage(named: "gradient.jpg") ?? UIImage())
结果如下: