美文网首页Swift基础
【iOS】MaskBtn图片蒙板按钮(swift)

【iOS】MaskBtn图片蒙板按钮(swift)

作者: Qire_er | 来源:发表于2022-01-12 19:14 被阅读0次

    在iOS开发中,用UIImage作为mask蒙板,实现一些有意思的效果,可以说很常见!本文记录我自己最近的项目中,使用UIImage反转后作为mask蒙板,结合UIBlurEffect毛玻璃特效,制作的按钮效果,给有类似需求的朋友作为参考!…… 请看下面的最终效果:


    最终效果

    如果你对这个感兴趣,那么接下来,我们就重新来做一遍!

    制作思路:

    1. 使用CGBlendMode.destinationOut混合模式(反转图片内容)
    2. 将UIImage作为图层的mask蒙板
    3. 添加UIBlurEffect毛玻璃特效作为打底

    具体思路如下图:


    图片反转Mask

    设置图层mask蒙版,直接设置UIview的mask属性就可以了:

     let bgLayer = UIView(frame: CGRect(origin: center, size: size))
     bgLayer.mask = mask // 设置mask属性
    

    图片反转的方法,可以写成一个UIImage的扩展,方便调用,代码如下:

    // 反转图片方法
    func invert(size: CGSize, color: UIColor, padding: CGFloat, ratio: CGFloat) -> UIImage {
        let blendMode = CGBlendMode.destinationOut // 设置混合模式
        let drawRect = CGRect(origin: .zero, size: size) // 绘制区域
        
        // 定义图片上下文
        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() // 上下文结束
        
        return invertImage
    }
    

    为了使用方便,我是自定义了一个UIButton的子类,考虑到icon图标的长宽比例不同,所以暴露一个ratio比例和padding内边距的参数给外面进行设置。

    背景图就随便,这里我用的是一个UIStackView里面放一些色块,主要是跟按钮有个对比,下面是完整代码:

    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内边距
        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")
        }
    
        // 创建图片蒙板效果
        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    // 阻止响应用户交互,否则按钮事件无效
            blur.isUserInteractionEnabled = false   // 阻止响应用户交互,否则按钮事件无效
            blur.layer.cornerRadius = radius
            blur.clipsToBounds = true
            
            addSubview(blur)
            addSubview(bgLayer)
        }
    }
    
    ///////////////////////////////////////////////////////////////////////////////////////////
    // 偷懒一下,相关扩展就直接写到这里了!
    
    extension UIImage {
        // 反转图片方法
        func invert(size: CGSize, color: UIColor, padding: CGFloat, ratio: CGFloat) -> UIImage {
            let blendMode = CGBlendMode.destinationOut // 设置混合模式
            let drawRect = CGRect(origin: .zero, size: size) // 绘制区域
            
            // 定义图片上下文
            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() // 上下文结束
            
            return invertImage
        }
    }
    
    ///////////////////////////////////////////////////////////////////////////////////////////
    
    extension UIView {
        // 创建【毛玻璃】效果
        func createBlurEffect(frame: CGRect) -> UIVisualEffectView {
            let blurEffect = UIBlurEffect(style: .regular)
            let blurView = UIVisualEffectView(effect: blurEffect)
            blurView.frame = frame
            return blurView
        }
    }
    
    ///////////////////////////////////////////////////////////////////////////////////////////
    
    1. MaskBtnVC.swift(调用部分的代码)
    //
    //  MaskBtnVC.swift
    //  UIKit-basic
    //
    //  Created by Qire_er on 2022/1/12.
    //
    
    import UIKit
    
    class MaskBtnVC: UIViewController {
        
        // 图片相关配置信息
        // 这里直接用系统图标名称作为key,用ratio比例作为value
        // 另外,size不同,ratio也不一样,暂时没有想出什么更方便的方法!
        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() // 创建背景图
            makeBtns() // 创建按钮
            view.backgroundColor = .white
        }
        
        // 创建按钮方法
        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)
                )
                // 加一点阴影效果
                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),
            ])
            
        }
        
        // 创建背景图方法
        private func makeBG() {
            let colorStack = UIStackView()
            colorStack.translatesAutoresizingMaskIntoConstraints = false
            colorStack.axis = .vertical
            colorStack.distribution = .fillEqually
            
            // 创建色块
            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: 以上仅代表个人浅见,如果你有什么高见,也欢迎讨论交流!-

    相关文章

      网友评论

        本文标题:【iOS】MaskBtn图片蒙板按钮(swift)

        本文链接:https://www.haomeiwen.com/subject/yaowcrtx.html