【iOS】MaskBtn圖片蒙板按鈕(swift)

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


最終效果

如果你對(duì)這個(gè)感興趣,那么接下來,我們就重新來做一遍!

制作思路:

  1. 使用CGBlendMode.destinationOut混合模式(反轉(zhuǎn)圖片內(nèi)容)
  2. 將UIImage作為圖層的mask蒙板
  3. 添加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ì)比,下面是完整代碼:

  1. 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
    }
}

///////////////////////////////////////////////////////////////////////////////////////////
  1. 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è)人淺見,如果你有什么高見,也歡迎討論交流!-

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容