在iOS開發(fā)中,用UIImage作為mask蒙板,實(shí)現(xiàn)一些有意思的效果,可以說很常見!本文記錄我自己最近的項(xiàng)目中,使用UIImage反轉(zhuǎn)后作為mask蒙板,結(jié)合UIBlurEffect毛玻璃特效,制作的按鈕效果,給有類似需求的朋友作為參考!…… 請(qǐng)看下面的最終效果:

最終效果
如果你對(duì)這個(gè)感興趣,那么接下來,我們就重新來做一遍!
制作思路:
- 使用CGBlendMode.destinationOut混合模式(反轉(zhuǎn)圖片內(nèi)容)
- 將UIImage作為圖層的mask蒙板
- 添加UIBlurEffect毛玻璃特效作為打底
具體思路如下圖:

圖片反轉(zhuǎn)Mask
設(shè)置圖層mask蒙版,直接設(shè)置UIview的mask屬性就可以了:
let bgLayer = UIView(frame: CGRect(origin: center, size: size))
bgLayer.mask = mask // 設(shè)置mask屬性
圖片反轉(zhuǎn)的方法,可以寫成一個(gè)UIImage的擴(kuò)展,方便調(diào)用,代碼如下:
// 反轉(zhuǎn)圖片方法
func invert(size: CGSize, color: UIColor, padding: CGFloat, ratio: CGFloat) -> UIImage {
let blendMode = CGBlendMode.destinationOut // 設(shè)置混合模式
let drawRect = CGRect(origin: .zero, size: size) // 繪制區(qū)域
// 定義圖片上下文
UIGraphicsBeginImageContextWithOptions(size, false, scale)
/*======================================================*/
color.setFill() // 填充顏色
UIRectFill(drawRect) // 用指定顏色填充
draw(in: drawRect.inset(by: UIEdgeInsets(top: padding, left: padding * ratio, bottom: padding, right: padding * ratio)), blendMode: blendMode, alpha: 1.0)
let invertImage = UIGraphicsGetImageFromCurrentImageContext()!
/*======================================================*/
UIGraphicsEndImageContext() // 上下文結(jié)束
return invertImage
}
為了使用方便,我是自定義了一個(gè)UIButton的子類,考慮到icon圖標(biāo)的長(zhǎng)寬比例不同,所以暴露一個(gè)ratio比例和padding內(nèi)邊距的參數(shù)給外面進(jìn)行設(shè)置。
背景圖就隨便,這里我用的是一個(gè)UIStackView里面放一些色塊,主要是跟按鈕有個(gè)對(duì)比,下面是完整代碼:
- MaskBtn.swift (定義部分的代碼)
//
// MaskBtn.swift
// UIKit-basic
//
// Created by Qire_er on 2022/1/12.
//
import UIKit
class MaskBtn: UIButton {
private var icon: UIImage! // icon圖片
private var size: CGSize! // icon尺寸
private var padding: CGFloat! // icon內(nèi)邊距
private var ratio: CGFloat! // icon寬高比例
private var radius: CGFloat! // 圓角半徑
init(icon: UIImage, size: CGSize, padding: CGFloat, ratio: CGFloat, radius: CGFloat, tintColor: UIColor) {
super.init(frame: .zero)
self.icon = icon
self.size = size
self.padding = padding
self.ratio = ratio
self.radius = radius
self.tintColor = tintColor
createCompose()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// 創(chuàng)建圖片蒙板效果
private func createCompose() {
let maskImg = icon.invert(size: CGSize(width: size.width, height: size.height), color: tintColor, padding: padding, ratio: ratio)
let mask = UIImageView(image: maskImg)
let bgLayer = UIView(frame: CGRect(origin: center, size: size))
let blur = bgLayer.createBlurEffect(frame: bgLayer.frame)
bgLayer.backgroundColor = tintColor
bgLayer.mask = mask
bgLayer.layer.cornerRadius = radius
bgLayer.isUserInteractionEnabled = false // 阻止響應(yīng)用戶交互,否則按鈕事件無(wú)效
blur.isUserInteractionEnabled = false // 阻止響應(yīng)用戶交互,否則按鈕事件無(wú)效
blur.layer.cornerRadius = radius
blur.clipsToBounds = true
addSubview(blur)
addSubview(bgLayer)
}
}
///////////////////////////////////////////////////////////////////////////////////////////
// 偷懶一下,相關(guān)擴(kuò)展就直接寫到這里了!
extension UIImage {
// 反轉(zhuǎn)圖片方法
func invert(size: CGSize, color: UIColor, padding: CGFloat, ratio: CGFloat) -> UIImage {
let blendMode = CGBlendMode.destinationOut // 設(shè)置混合模式
let drawRect = CGRect(origin: .zero, size: size) // 繪制區(qū)域
// 定義圖片上下文
UIGraphicsBeginImageContextWithOptions(size, false, scale)
/*======================================================*/
color.setFill() // 填充顏色
UIRectFill(drawRect) // 用指定顏色填充
draw(in: drawRect.inset(by: UIEdgeInsets(top: padding, left: padding * ratio, bottom: padding, right: padding * ratio)), blendMode: blendMode, alpha: 1.0)
let invertImage = UIGraphicsGetImageFromCurrentImageContext()!
/*======================================================*/
UIGraphicsEndImageContext() // 上下文結(jié)束
return invertImage
}
}
///////////////////////////////////////////////////////////////////////////////////////////
extension UIView {
// 創(chuàng)建【毛玻璃】效果
func createBlurEffect(frame: CGRect) -> UIVisualEffectView {
let blurEffect = UIBlurEffect(style: .regular)
let blurView = UIVisualEffectView(effect: blurEffect)
blurView.frame = frame
return blurView
}
}
///////////////////////////////////////////////////////////////////////////////////////////
- MaskBtnVC.swift(調(diào)用部分的代碼)
//
// MaskBtnVC.swift
// UIKit-basic
//
// Created by Qire_er on 2022/1/12.
//
import UIKit
class MaskBtnVC: UIViewController {
// 圖片相關(guān)配置信息
// 這里直接用系統(tǒng)圖標(biāo)名稱作為key,用ratio比例作為value
// 另外,size不同,ratio也不一樣,暫時(shí)沒有想出什么更方便的方法!
private let imgNames = ["heart.fill": 0.75, "camera.fill": 0.65, "book.fill": 0.75, "gearshape.fill": 0.95, "alarm.fill": 1.0, "gift.fill": 0.75]
override func viewDidLoad() {
super.viewDidLoad()
makeBG() // 創(chuàng)建背景圖
makeBtns() // 創(chuàng)建按鈕
view.backgroundColor = .white
}
// 創(chuàng)建按鈕方法
private func makeBtns() {
let btnStack = UIStackView()
btnStack.translatesAutoresizingMaskIntoConstraints = false
btnStack.axis = .vertical
btnStack.alignment = .center
btnStack.distribution = .fillEqually
for item in imgNames {
let btn = MaskBtn(
icon: UIImage(systemName: item.key)!,
size: CGSize(width: 100, height: 100),
padding: 20,
ratio: CGFloat(item.value),
radius: 32,
tintColor: .white.withAlphaComponent(0.85)
)
// 加一點(diǎn)陰影效果
btn.layer.shadowColor = UIColor.black.cgColor
btn.layer.shadowOpacity = 0.15
btn.layer.shadowOffset = CGSize(width: 5, height: 5)
btn.layer.shadowRadius = 10
btnStack.addArrangedSubview(btn)
btn.widthAnchor.constraint(equalToConstant: 100).isActive = true
}
view.addSubview(btnStack)
// 添加約束
NSLayoutConstraint.activate([
btnStack.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 15),
btnStack.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -15),
btnStack.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 15),
btnStack.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -5),
])
}
// 創(chuàng)建背景圖方法
private func makeBG() {
let colorStack = UIStackView()
colorStack.translatesAutoresizingMaskIntoConstraints = false
colorStack.axis = .vertical
colorStack.distribution = .fillEqually
// 創(chuàng)建色塊
for i in 0..<30 {
let colorBlock = UIView()
colorBlock.backgroundColor = UIColor(
hue: CGFloat(i * 5 + 16) / 100.0,
saturation: CGFloat((i * 15) % 100) / 100.0,
brightness: 0.85,
alpha: 1.0
)
colorStack.addArrangedSubview(colorBlock)
}
view.addSubview(colorStack)
// 添加約束
NSLayoutConstraint.activate([
colorStack.leftAnchor.constraint(equalTo: view.leftAnchor),
colorStack.rightAnchor.constraint(equalTo: view.rightAnchor),
colorStack.topAnchor.constraint(equalTo: view.topAnchor),
colorStack.bottomAnchor.constraint(equalTo: view.bottomAnchor),
])
}
}
(==完==)
ps: 以上僅代表個(gè)人淺見,如果你有什么高見,也歡迎討論交流!-