美文网首页
Swift 镂空引导, 响应镂空区域的点击事件

Swift 镂空引导, 响应镂空区域的点击事件

作者: YourSummer | 来源:发表于2023-08-27 16:35 被阅读0次
    example.gif

    需求:

    指定按钮, 或者区域的镂空处理, 点击镂空区域响应底部视图的事件
    效果如上gif动画

    封装代码:

    //
    //  GuideView.swift
    //  TestView
    //
    //  Created by cpcoder on 24/8/2023.
    //
    
    import UIKit
    
    enum GuideType {
        case cycle // 圆
        case roundedRect // 矩形
    }
    
    class GuideView: UIView {
        
        fileprivate let rect: CGRect
        
        fileprivate let cornerPath: UIBezierPath
        
        /// 镂空区域的准确frame
        /// - Parameter rect: CGRect
        init(rect: CGRect, type: GuideType) {
            self.rect = rect
            switch type {
            case .cycle:
                // 圆心坐标
                let centerPoint = CGPoint(x: rect.minX + rect.width / 2,
                                          y: rect.minY + rect.height / 2)
                // 圆半径
                let radius = rect.width / 2
                
                // 圆形镂空路径
                self.cornerPath = UIBezierPath(arcCenter: centerPoint,
                                               radius: radius,
                                               startAngle: 0,
                                               endAngle: 2 * CGFloat.pi,
                                               clockwise: false)
            case .roundedRect:
                // 这里是一个圆角矩形镂空
                self.cornerPath = UIBezierPath(roundedRect: rect, cornerRadius: 10)
            }
            super.init(frame: .zero)
        }
        
        required init?(coder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
        
        func show() {
            let frame = UIScreen.main.bounds
            self.frame = frame
            self.backgroundColor = UIColor.black.withAlphaComponent(0.7)
            guard
                let delegate = UIApplication.shared.delegate as? AppDelegate,
                let window = delegate.window
            else {
                return
            }
            // 这里也可以添加到指定的View上, 比如某个控制器的view上
            window.addSubview(self)
            
            // 也可以在这里添加一些文字说明的空间, 或者手指动画
    //        let uiTipsLb = UILabel(frame: CGRect(x: rect.minX, y: rect.maxY, width: 100, height: 50))
    //        uiTipsLb.text = "提示文案 或者 图像"
    //        uiTipsLb.textColor = .white
    //        addSubview(uiTipsLb)
            
            // 添加圆角镂空矩形路径
            let path = UIBezierPath(rect: frame)
            path.append(cornerPath)
            
            let shapeLayer = CAShapeLayer()
            shapeLayer.path = path.cgPath
            shapeLayer.fillRule = .evenOdd
            layer.mask = shapeLayer
        }
        
        override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
            if cornerPath.contains(point) {
                // 镂空区域点击事件穿透
                removeFromSuperview()
                return nil
            } else {
                return super.hitTest(point, with: event)
            }
        }
    }
    
    

    调用:

    //
    //  TestController.swift
    //  TestView
    //
    //  Created by cpcoder on 28/8/2023.
    //
    
    import UIKit
    
    class TestController: UIViewController {
    
        @IBOutlet weak var uiAddBtn: UIButton!
        
        override func viewDidLoad() {
            super.viewDidLoad()
        }
        
        // 添加按钮事件
        @IBAction func addAction(_ sender: Any) {
            print("addAction")
        }
        
        /// 点击Cycle按钮, 展示圆形镂空区域
        /// - Parameter sender:
        @IBAction func cycleAction(_ sender: Any) {
            // 之所以写延迟, 是因为
            // 往往我们需要引导的场景是, 进入页面, 1. viewWillAppear(切换页面多次调用); 2. viewDidAppear(切换页面多次调用) 3.viewDidLoad(调用一次)
            // 如果 写在 viewDidLoad 那么极有可能获取不到准确的frame
            // 为了只展示一次, 且得到准确的frame, 所以写延迟
            // 当然, 也可以写在 1 & 2 中, 那么 你就要额外的变量去标记是否已经展示过镂空引导, 从而解决多次展示问题
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.1, execute: {
                // 获取uiAddBtn转换到self.view之后的确切的frame
                let rect = self.uiAddBtn.convert(self.uiAddBtn.bounds, to: self.view)
                GuideView(rect: rect, type: .cycle).show()
            })
        }
        
        /// 点击圆角矩形按钮, 展示圆角矩形镂空区域
        /// - Parameter sender:
        @IBAction func RoundedRectAction(_ sender: Any) {
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.1, execute: {
                // 获取uiAddBtn转换到self.view之后的确切的frame
                let rect = self.uiAddBtn.convert(self.uiAddBtn.bounds, to: self.view)
                GuideView(rect: rect, type: .roundedRect).show()
            })
        }
    }
    
    

    这些年经历过几次这样的镂空引导, 但还是忘, 记下来


    ycj1z-vfmd2.gif

    相关文章

      网友评论

          本文标题:Swift 镂空引导, 响应镂空区域的点击事件

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