美文网首页
iOS开发之转盘菜单—Swift

iOS开发之转盘菜单—Swift

作者: 季末微夏 | 来源:发表于2020-12-03 11:21 被阅读0次

    前言

    使用Swift实现的转盘菜单,主要用到UIBezierPathCALayer遮罩绘制扇形UIViewCATransform3DMakeRotation实现旋转动画。代码设计使用默认configureCallback回调方便创建和设置基本属性,参考UITableView代理和数据源模式,支持AutoLayoutFrame

    效果图

    转盘菜单

    1.遮罩绘制扇形View

    计算扇形曲线位置,通过CALayermask属性绘制出扇形UIView
    核心代码

    func setMaskLayer(_ startAngle: CGFloat, endAngle: CGFloat) {
        let center = CGPoint(x: bounds.width * 0.5, y: bounds.height * 0.5)
        let layer = CAShapeLayer()
        path.addArc(withCenter: center, radius: bounds.width * 0.5, startAngle: startAngle, endAngle: endAngle, clockwise: true)
        path.addLine(to: center)
        layer.path = path.cgPath
        layer.rasterizationScale = UIScreen.main.scale
        layer.shouldRasterize = true
        self.layer.mask = layer
    }
    

    2.中间镂空

    func createHole(in view : UIView, radius: CGFloat)   {
        let path = CGMutablePath()
        path.addArc(center: view.center, radius: radius, startAngle: 0.0, endAngle: 2.0 * .pi, clockwise: true)
        path.addRect(CGRect(origin: .zero, size: view.bounds.size))
        let maskLayer = CAShapeLayer()
        maskLayer.path = path
        maskLayer.fillRule = .evenOdd
        view.layer.mask = maskLayer
        view.clipsToBounds = true
    }
    

    3.旋转动画

    添加UIPanGestureRecognizerUITapGestureRecognizer手势,根据手势位置使用atan2函数计算旋转角度,然后用CATransform3DMakeRotation围绕Z轴旋转做动画
    核心代码

    func handlePanGesture(_ sender: UIPanGestureRecognizer) {
        let location = sender.location(in: self)
        switch sender.state {
        case .began:
            startPoint = location
        case .changed:
            let radian1 = -atan2(startPoint.x - menuLayerView.center.x, startPoint.y - menuLayerView.center.y)
            let radian2 = -atan2(location.x - menuLayerView.center.x, location.y - menuLayerView.center.y)
            menuLayerView.transform = menuLayerView.transform.rotated(by: radian2 - radian1)
            startPoint = location
        default:
            let angle = 2 * CGFloat(Double.pi) / CGFloat(cells.count)
            var menuViewAngle = atan2(menuLayerView.transform.b, menuLayerView.transform.a)
            if menuViewAngle < 0 {
                menuViewAngle += CGFloat(2 * Double.pi)
            }
            var index = cells.count - Int((menuViewAngle + CGFloat(Double.pi / 4)) / angle)
            if index == cells.count {
                index = 0
            }
            setSelectedIndex(index, animated: true)
        }
    }
    func handleTapGesture(_ sender: UITapGestureRecognizer) {
        let location = sender.location(in: menuLayerView)
        for (index, cell) in cells.enumerated() {
            if cell.path.contains(location) {
                setSelectedIndex(index, animated: true)
            }
        }
    }
    

    4.弹出收起动画

    func openMenuView(withAnimate animate: Bool = true) {
        openMenu = true
        UIView.animate(withDuration: animate ? configure.animationDuration : 0, delay: 0, usingSpringWithDamping: 0.7, initialSpringVelocity: 5.0, options: .curveEaseInOut) {
            self.centerButton.transform = CGAffineTransform(rotationAngle: .pi * -0.5)
            self.centerButton.setImage(self.configure.closeImage, for: .normal)
            self.menuLayerView.transform = CGAffineTransform(scaleX: 1, y: 1).rotated(by: self.currentAngle)
        }
    }
    func closeMenuView(withAnimate animate: Bool = true) {
        openMenu = false
        let scale = (configure.centerRadius * 2) / bounds.width
        UIView.animate(withDuration: animate ? configure.animationDuration : 0, delay: 0, usingSpringWithDamping: 0.7, initialSpringVelocity: 5.0, options: .curveEaseInOut) {
            self.centerButton.transform = .identity
            self.centerButton.setImage(self.configure.openImage, for: .normal)
            self.menuLayerView.transform = CGAffineTransform(scaleX: scale, y: scale).rotated(by: self.currentAngle)
        }
    }
    

    5.内部细节

    考虑到方便布局和使用,内部使用UIView叠加旋转实现,这里也可以采用Layer直接绘制实现,相对UIView,层次结构会简单很多

    总结

    核心代码已经贴出,完整代码请查看----->>>CLDemo,如果对你有所帮助,欢迎Star。

    相关文章

      网友评论

          本文标题:iOS开发之转盘菜单—Swift

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