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)
}
}