Swift menu菜单

/*功能: 只需要传入菜单箭头点位置、菜单宽度、数据源即可。

   1、支持任意点弹出(点是基于整个屏幕位置)

   2、会根据点位置自动计算菜单位置

   3、背景色、文字等支持自定义设置

   4、菜单最大宽度=屏幕-边距    最大高度=屏幕高度一半

*/

根据位置展示对应效果

importUIKit

//Mark: menu代理

protocol SwiftPopMenuDelegate :NSObjectProtocol{

    func swiftPopMenuDidSelectIndex(index:Int)

}

public enum SwiftPopMenuConfigure {

    casePopMenuTextFont(UIFont)            //菜单文字字体

    casePopMenuTextColor(UIColor)          //菜单文字颜色

    case PopMenuBackgroudColor(UIColor)    //菜单背景色

    casepopMenuCornorRadius(CGFloat)            //菜单圆角

    casepopMenuItemHeight(CGFloat)          //菜单行高度

    case popMenuSplitLineColor(UIColor)    //菜单分割线颜色

    case popMenuIconLeftMargin(CGFloat)          //icon左间距

    casepopMenuMargin(CGFloat)              //菜单与屏幕边距

    casepopMenuAlpha(CGFloat)              //菜单背景透明度

}

class ZHGPopMenuView: UIView {

    //delegate

   weak var delegate : SwiftPopMenuDelegate?

   //block

   publicvardidSelectMenuBlock:((_index:Int)->Void)?


   let KScrW:CGFloat = UIScreen.main.bounds.size.width

   let KScrH:CGFloat = UIScreen.main.bounds.size.height

    ///*  -----------------------  外部参数 通过configure设置 ---------------------------- */

    //区域外背景透明度

    private var popMenuOutAlpha:CGFloat = 0.3

    //背景色

    private var popMenuBgColor:UIColor = UIColor.white

    //圆角弧度

    private var popMenuCornorRadius:CGFloat = 6

    //文字颜色

    private var popMenuTextColor:UIColor = UIColor.black

    //字体大小等

    privatevarpopMenuTextFont:UIFont=UIFont.systemFont(ofSize:17)

    //菜单高度

    private var popMenuItemHeight:CGFloat = 44.0

    //菜单分割线颜色

    privatevarpopMenuSplitLineColor:UIColor=UIColor(red:222/255.0, green:222/255.0, blue:222/255.0, alpha:0.5)

    //icon左间距

    private var popMenuIconLeftMargin:CGFloat = 15

    //菜单与屏幕边距

    private var popMenuMargin:CGFloat = 10


    ///*  -----------------------  外部参数 over------------------------------------------ */


    privatevararrowPoint:CGPoint=CGPoint.zero        //小箭头位置

    privatevararrowViewWidth:CGFloat=15              //三角箭头宽

    privatevararrowViewHeight:CGFloat=10              //三角箭头高

    privatevarpopData:[(icon:String,title:String)]!      //数据源


    static let cellID:String = "SwiftPopMenuCellID"

    private var myFrame:CGRect!    //tableview  frame

    privatevararrowView:UIView! =nil


    var tableView:UITableView! = nil



 ///  初始化菜单

 ///

 /// - Parameters:

 ///  - menuWidth: 菜单宽度

 ///  - arrow: 箭头位置是popmenu相对整个屏幕的位置

 ///  - datas: 数据源,icon允许传空,数据源没数据,不会显示菜单

 ///  - configure: 配置信息,可不传

    init(menuWidth:CGFloat,arrow:CGPoint,datas:[(icon:String,title:String)],configures:[SwiftPopMenuConfigure] = []) {

        super.init(frame:UIScreen.main.bounds)

        self.frame = UIScreen.main.bounds

        //读取配置

        configures.forEach{ (config)in

            switch(config){

                caselet.PopMenuTextFont(value):

                    popMenuTextFont= value

                caselet.PopMenuTextColor(value):

                    popMenuTextColor= value

                caselet.PopMenuBackgroudColor(value):

                    popMenuBgColor= value

                caselet.popMenuCornorRadius(value):

                    popMenuCornorRadius= value

                caselet.popMenuItemHeight(value):

                    popMenuItemHeight= value

                caselet.popMenuSplitLineColor(value):

                    popMenuSplitLineColor= value

                caselet.popMenuIconLeftMargin(value):

                    popMenuIconLeftMargin= value

                caselet.popMenuMargin(value):

                    popMenuMargin= value

                caselet.popMenuAlpha(value):

                    popMenuOutAlpha= value

            }

        }


        popData= datas

        //设置myFrame size  ,original会在后面计算

        myFrame=CGRect(x:0, y:0, width: menuWidth, height:popMenuItemHeight*CGFloat(popData.count))

        myFrame.size.height = min(KScrH/2, myFrame.height)

        myFrame.size.width = min(KScrW-popMenuMargin*2, myFrame.width)


        //设置肩头,与屏幕间隔10

        arrowPoint= arrow

        arrowPoint.x = max(popMenuMargin, min(arrowPoint.x, KScrW-popMenuMargin))


    }


    requiredpublicinit?(coder aDecoder:NSCoder) {

        fatalError("init(coder:) has not been implemented")

    }




    funcinitViews() {

        self.backgroundColor = UIColor.black.withAlphaComponent(popMenuOutAlpha)


        letarrowPs =getArrowPoints()

        myFrame.origin= arrowPs.3

        letisarrowUP = arrowPs.4

        print(arrowPs)

        //箭头

        arrowView=UIView(frame: CGRect(x: myFrame.origin.x, y: isarrowUP ? myFrame.origin.y-arrowViewHeight : myFrame.origin.y+myFrame.height, width: myFrame.width, height: arrowViewHeight))

        letlayer=CAShapeLayer()

        letpath=UIBezierPath()

        path.move(to: arrowPs.0)

        path.addLine(to: arrowPs.1)

        path.addLine(to: arrowPs.2)

        layer.path=path.cgPath

        layer.fillColor=popMenuBgColor.cgColor

        arrowView.layer.addSublayer(layer)

        self.addSubview(arrowView)


        tableView=UITableView(frame:CGRect(x:myFrame.origin.x,y:myFrame.origin.y,width:myFrame.width,height:myFrame.height), style: .plain)

        tableView.register(SwiftPopMenuCell.classForCoder(), forCellReuseIdentifier:ZHGPopMenuView.cellID)

        tableView.backgroundColor = popMenuBgColor

        tableView.layer.cornerRadius = popMenuCornorRadius

        tableView.separatorStyle = .none

        tableView.layer.masksToBounds = true

        tableView.delegate=self

        tableView.dataSource=self

        tableView.bounces=false

        UIView.animate(withDuration:0.3) {

            self.addSubview(self.tableView)

        }

    }



    /// 计算箭头位置

    ///

    /// - Returns: (三角箭头顶,三角箭头左,三角箭头右,tableview 原点,是否箭头朝上)

    func getArrowPoints() -> (CGPoint,CGPoint,CGPoint,CGPoint,Bool) {

        if arrowPoint.x <= popMenuMargin {

            arrowPoint.x = popMenuMargin

        }

        if arrowPoint.x >= KScrW - popMenuMargin{

            arrowPoint.x = KScrW - popMenuMargin

        }

        varoriginalPoint =CGPoint.zero


        //箭头中间距离左边距离

        vararrowMargin:CGFloat=popMenuMargin

        if arrowPoint.x < KScrW/2{

            if(arrowPoint.x>myFrame.width/2) {

                arrowMargin =myFrame.width/2

                originalPoint =CGPoint(x:arrowPoint.x-myFrame.width/2, y:arrowPoint.y+arrowViewHeight)

            }else{

                arrowMargin =arrowPoint.x-popMenuMargin

                originalPoint =CGPoint(x:popMenuMargin, y:arrowPoint.y+arrowViewHeight)

            }


        }else{


            if (KScrW-arrowPoint.x) < myFrame.width/2{

                arrowMargin = (myFrame.width-KScrW+arrowPoint.x)

                originalPoint =CGPoint(x: KScrW-popMenuMargin-myFrame.width, y: arrowPoint.y+arrowViewHeight)



            }else{

                arrowMargin =myFrame.width/2

                originalPoint =CGPoint(x:arrowPoint.x-myFrame.width/2, y:arrowPoint.y+arrowViewHeight)

            }

        }


        //箭头朝上

        if (KScrH - arrowPoint.y) > myFrame.height{


            return(CGPoint(x: arrowMargin, y:0),CGPoint(x: arrowMargin-arrowViewWidth/2, y:arrowViewHeight),CGPoint(x: arrowMargin+arrowViewWidth/2, y:arrowViewHeight),originalPoint,true)


        }else{

            originalPoint.y = arrowPoint.y-myFrame.height-arrowViewHeight


            return(CGPoint(x: arrowMargin, y:arrowViewHeight),CGPoint(x: arrowMargin-arrowViewWidth/2, y:0),CGPoint(x: arrowMargin+arrowViewWidth/2, y:0),originalPoint,false)

        }


    }


}

// MARK: - 页面显示、隐藏

extension ZHGPopMenuView{


    overridepublicfunctouchesBegan(_touches:Set, with event:UIEvent?) {

        iftouches.first?.view!=tableView{

            dismiss()

        }

    }


    publicfuncshow() {

        ifpopData.isEmpty{

            return

        }

        initViews()

        UIApplication.shared.keyWindow?.addSubview(self)

    }


    publicfuncdismiss() {

        self.removeFromSuperview()

    }

}

// MARK: - UITableViewDataSource,UITableViewDelegate

extension ZHGPopMenuView : UITableViewDataSource,UITableViewDelegate{


    publicfunctableView(_tableView:UITableView, numberOfRowsInSection section:Int) ->Int{

        returnpopData.count

    }


    publicfunctableView(_tableView:UITableView, cellForRowAt indexPath:IndexPath) ->UITableViewCell{

        ifpopData.count>indexPath.row{

            letcell = tableView.dequeueReusableCell(withIdentifier:ZHGPopMenuView.cellID)as!SwiftPopMenuCell


            letmodel =popData[indexPath.row]

            cell.setConfig(_txtColor: popMenuTextColor, _lineColor: popMenuSplitLineColor, _txtFont: popMenuTextFont, _iconLeft: popMenuIconLeftMargin)

            ifindexPath.row==popData.count-1{

                cell.fill(iconName: model.icon, title: model.title, islast:true)

            }else{

                 cell.fill(iconName: model.icon, title: model.title)

            }

            returncell

        }


        return UITableViewCell()

    }


    publicfunctableView(_tableView:UITableView, heightForRowAt indexPath:IndexPath) ->CGFloat{

        return popMenuItemHeight

    }


    publicfunctableView(_tableView:UITableView, heightForFooterInSection section:Int) ->CGFloat{

        return0.01

    }


    publicfunctableView(_tableView:UITableView, didSelectRowAt indexPath:IndexPath) {

        ifself.delegate!=nil{

            self.delegate?.swiftPopMenuDidSelectIndex(index: indexPath.row)

        }

        if didSelectMenuBlock != nil {

            didSelectMenuBlock!(indexPath.row)

        }


        dismiss()

    }


}

/// UITableViewCell

class SwiftPopMenuCell: UITableViewCell {

    var iconImage:UIImageView!

    var lblTitle:UILabel!

    varline:UIView!


    //自定义属性

    varlineColor:UIColor=UIColor(red:222/255.0, green:222/255.0, blue:222/255.0, alpha:0.5)

    var txtColor:UIColor = UIColor.black

    vartxtFont:UIFont=UIFont.systemFont(ofSize:17)

    variconLeft:CGFloat=15



    overrideinit(style:UITableViewCell.CellStyle, reuseIdentifier:String?) {

        super.init(style: style, reuseIdentifier: reuseIdentifier)

        self.backgroundColor = UIColor.clear


        iconImage=UIImageView()

        self.contentView.addSubview(iconImage)

        self.selectionStyle = .none


        lblTitle=UILabel()

        self.contentView.addSubview(lblTitle)


        line=UIView()

        self.contentView.addSubview(line)

    }



    requiredinit?(coder aDecoder:NSCoder) {

        fatalError("init(coder:) has not been implemented")

    }



    funcfill(iconName:String,title:String,islast:Bool=false) {

        iconImage.image=UIImage(named: iconName)

        lblTitle.text= title

        line.isHidden= islast

    }


    funcsetConfig(_txtColor:UIColor,_lineColor:UIColor,_txtFont:UIFont,_iconLeft:CGFloat) {

        txtColor= _txtColor

        txtFont= _txtFont

        lineColor= _lineColor

        iconLeft= _iconLeft


        line.backgroundColor = lineColor

        lblTitle.textColor = txtColor

        lblTitle.font = txtFont

    }


    override func layoutSubviews() {

        super.layoutSubviews()

        self.iconImage.frame=CGRect(x:iconLeft, y: (self.bounds.size.height-20)/2, width:20, height:20)

        self.lblTitle.frame=CGRect(x:20+iconLeft*2, y:0, width:self.bounds.size.width-40, height:self.bounds.size.height)

        self.line.frame=CGRect(x:0, y:self.frame.size.height-1, width:self.frame.size.width, height:1)


    }



}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,036评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,046评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,411评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,622评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,661评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,521评论 1 304
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,288评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,200评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,644评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,837评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,953评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,673评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,281评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,889评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,011评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,119评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,901评论 2 355

推荐阅读更多精彩内容