[技术文档][技术中心][iOS部][114啦]全局菜单

菜单类型

1、首页点击更多按钮弹起的菜单:FunctionView

2、详情页点击更多按钮弹出的菜单:YYWMenuView

3、长按webview中的链接弹出的菜单:YYWContextMenuHelp.swift

具体实现

  • FunctionView
    界面由nib搭建。view加在mainviewcontroller的view中。
    通过以下代码来隐藏和显示,有动画效果。
    部分按钮在首页时置灰不可点击。
    该菜单的具体功能实现全由PageViewManager代理实现。
func showFunctionBar(_ sender: UIButton)
    {
        guard self.functionView.isAnimatting == false else {
            return
        }
 
        self.mainViewController().view.bringSubview(toFront: self.functionView)
        
        let show = self.functionView.contentViewBottomAL.constant < 0
        self.functionView.isHidden = false
        self.functionView.isAnimatting = true
        if show
        {
            self.functionView.showAnimation()
            MobClick.event("homeToolBar_showMenu")
            let enabled = MainViewFacade.sharedInstance.isNotHomeWebPage()
            self.setUpButtonEnabled(functionView.addBookmarkButton, label: functionView.addBookmarkLabel, enabled: enabled)
            self.setUpButtonEnabled(functionView.shareBtn, label: functionView.shareLabel, enabled: enabled)
            self.setUpButtonEnabled(functionView.webSnapShotButton, label: functionView.webSnapShotLabel, enabled: enabled)
            self.setUpButtonEnabled(functionView.refreshBtn, label: functionView.refreshLabel, enabled: enabled)
        }
        else
        {
            self.functionView.hideAnimation()
        }
        self.functionView.contentView.layoutIfNeeded()
    }
  • ** YYWMenuView**
    该菜单是添加在window上的,因此全局调用一次show方法即可显示出来。
    该枚举代表显示的位置,不同类型显示不同的菜单项。
enum contentType: Int {
    case home = 0//
    case web
    case card
  }
switch ctype {
    case .home:
      self.menuItems = [
        YYWMenuItem(defaultType: .accountStatus),
        YYWMenuItem(defaultType: .bookmarkHistiry),
        YYWMenuItem(defaultType: .setting)
      ]
      break
    case .web:
      self.menuItems = [
        YYWMenuItem(defaultType: .accountStatus),
        YYWMenuItem(defaultType: .setting),
        YYWMenuItem(defaultType: .capture),
        YYWMenuItem(defaultType: .copyLink),
        YYWMenuItem(defaultType: .bookmarkHistiry),
        YYWMenuItem(defaultType: .addBookmark)
      ]
    case .card:
      self.menuItems = [
        YYWMenuItem(defaultType: .setFont),
        YYWMenuItem(defaultType: .feedback)
      ]
      break
    }

各菜单项对应的title与image已经预先定义好。

init(defaultType: YYWMenuItemType) {
    type = defaultType
    switch type {
    case .accountStatus:
      title = NSLocalizedString("未登录", comment: "")
      image = UIImage(named: "menu_visitor")!
    case .setting:
      title = NSLocalizedString("设置", comment: "")
      image = UIImage(named: "menu_setting")!
    case .darkModel:
      title = NSLocalizedString("夜间模式", comment: "")
      image = UIImage(named: "menu_night")!
    case .capture:
      title = NSLocalizedString("截图", comment: "")
      image = UIImage(named: "menu_screenshot")!
    case .copyLink:
      title = NSLocalizedString("复制链接", comment: "")
      image = UIImage(named: "menu_copy")!
    case .cloudOof:
      title = NSLocalizedString("收藏到115", comment: "")
      image = UIImage(named: "menu_star")!
    case .bookmarkHistiry:
      title = NSLocalizedString("书签/历史", comment: "")
      image = UIImage(named: "menu_sc")!
    case .addBookmark:
      title = NSLocalizedString("添加书签", comment: "")
      image = UIImage(named: "menu_bookmark")!
    case .setFont:
        title = NSLocalizedString("字体设置", comment: "")
        image = UIImage(named: "menu_font")!
    case .feedback:
        title = NSLocalizedString("意见反馈", comment: "")
        image = UIImage(named: "menu_edit")!
    case .itemType:
      assert(true, "itemType 不是默认类型, 使用上面那个方法初始化。")
      title = ""
      image = UIImage()
    }
    super.init()
  }

因此初始化时指定type,显示方向type,以及一个block。

init(archorView: UIView, contentType ctype: contentType, directionType dtype: directionType, action: @escaping YYWMenuAction)
// block定义 回调时返回点击的type项,根据该type处理事件。
typealias YYWMenuAction = (YYWMenuItemType) -> Void
  • YYWContextMenuHelp
    该弹层使用系统自带的UIAlertController实现。
    根据以下方法获取的webview元素决定显示哪些弹层。
userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage)

YYWContextMenuHelp.Elements(link: linkURL, image: imageURL, imageUrls: self.allImagesUrl, linkText: linkText)

创建代码

func contextMenuHelper(_ elements: Elements,  cookie:String?, gestureRecognizer: UILongPressGestureRecognizer) {
        // locationInView can return (0, 0) when the long press is triggered in an invalid page
        // state (e.g., long pressing a link before the document changes, then releasing after a
        // different page loads).
        guard let navigationController = UIApplication.shared.delegate?.window??.rootViewController as? UINavigationController else { return }
        guard let mainViewController = navigationController.viewControllers.first as? MainViewController else { return }
        let view = MainViewFacade.sharedInstance.currentPageView()
        let touchPoint = view.tabWebView!.gestureRecognizer.location(in: view)
        guard touchPoint != CGPoint.zero else { return }
        
        let touchSize = CGSize(width: 0, height: 16)
        
        let actionSheetController = UIAlertController(title: nil, message: nil, preferredStyle: UIAlertControllerStyle.actionSheet)
        var dialogTitle: String?
        
        if let url = elements.link, let imageUrl = elements.image {//长按链接与图片
            dialogTitle = url.absoluteString
            if dialogTitle?.hasPrefix("javascript:") == true {
                return
            }
            if dialogTitle?.characters.count > 0{
                if !view.isPushPageView {
                    actionSheetController.addAction(openNewTabAction(url, mainViewController))
                }
                actionSheetController.addAction(copyAction(url))
                actionSheetController.addAction(shareAction(url.absoluteString,elements.linkText ?? ""))
                actionSheetController.addAction(saveImageAction(imageUrl, cookie ?? ""))
                actionSheetController.addAction(shareImageAction(imageUrl, cookie ?? ""))
                actionSheetController.addAction(browserImageAction(imageUrl, elements, cookie ?? "", mainViewController))
//                if let _ = UserDefaults.standard.object(forKey: "defaults_user_authdata"), !imageUrl.absoluteString.hasPrefix("data:image/") {
//                    actionSheetController.addAction(cloudImageAction(imageUrl))
//                }
            }
            
        } else if let url = elements.link {///长按链接
            dialogTitle = url.absoluteString
            if dialogTitle?.hasPrefix("javascript:") == true {
                return
            }
            
            if dialogTitle?.characters.count > 0{
//                actionSheetController.addAction(openNewTabAction(url, mainViewController))
                if !view.isPushPageView {
                    if (yywFunctionMatch != "" &&  url.absoluteString.hasPrefix(yywFunctionMatch) == true)
                       {
                            var originalString = url.absoluteString
                            let escapedString = originalString.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)
                            originalString = "http://115.com/lx?mag="
                            originalString = originalString + (escapedString ?? "")
                            if let strUrl = URL(string: originalString){
                                actionSheetController.addAction(openNewTabAction(strUrl, mainViewController))
                            }
                    } else {
                        actionSheetController.addAction(openNewTabAction(url, mainViewController))
                    }
                }
                actionSheetController.addAction(copyAction(url))
                actionSheetController.addAction(copyLinkTextAction(elements.linkText ?? ""))
                actionSheetController.addAction(shareAction(url.absoluteString,elements.linkText ?? ""))
            }
        } else if let imageUrl = elements.image {//长按图片
            if dialogTitle == nil {
                dialogTitle = imageUrl.absoluteString
            }
            dialogTitle = ""
            actionSheetController.addAction(browserImageAction(imageUrl, elements, cookie ?? "", mainViewController))
            actionSheetController.addAction(saveImageAction(imageUrl, cookie ?? ""))
            actionSheetController.addAction(shareImageAction(imageUrl, cookie ?? ""))
//            if let _ = UserDefaults.standard.object(forKey: "defaults_user_authdata"), !imageUrl.absoluteString.hasPrefix("data:image/") {
//                actionSheetController.addAction(cloudImageAction(imageUrl))
//            }
        }
        
        // If we're showing an arrow popup, set the anchor to the long press location.
        if let popoverPresentationController = actionSheetController.popoverPresentationController {
            popoverPresentationController.delegate = self
            popoverPresentationController.sourceView = view
            popoverPresentationController.sourceRect = CGRect(origin: touchPoint, size: touchSize)
            popoverPresentationController.permittedArrowDirections = .any
        }
        
        if dialogTitle != nil && dialogTitle?.characters.count > 0 {
            actionSheetController.title = dialogTitle?.ellipsize(maxLength: 120)
        }
        let cancelAction = UIAlertAction(title: "取消", style: UIAlertActionStyle.cancel, handler: nil).changeAlertActionTextColor()
        
        actionSheetController.addAction(cancelAction)
        if let navVc = mainViewController.presentedViewController as? UINavigationController {
            navVc.present(actionSheetController, animated: true, completion: nil)
        } else {
            mainViewController.present(actionSheetController, animated: true, completion: nil)
        }
    }

旋转屏幕时会将弹出收起。模仿UC做法。

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

推荐阅读更多精彩内容