最后更新: 2017-12-15

一、 项目初始化

  1. 解析对应的资源, 下载Pap.er之后,需要解析里面的资源.

    采用如下的方法: http://blog.csdn.net/xuzihai0703/article/details/50327531

  2. 创建项目工程

  3. 导入里面的资源icon, 然后运行

    可以看到,资源文件夹里面有一个AppIcon.icns 文件夹, 里面包含搜有的icon资源.可以在 这里 进行解析、下载, 添加到项目Assets.xcassets - AppIcon中, cmd + R运行;



    运行之后,什么都没有,当然是这样的,毕竟我们什么都没做

  4. 在状态栏显示App, 进行如下操作

    • 把资源文件夹内的两张 icon16*16的文件,放到 Assets里面去

    关于StatusBar icon尺寸可以参考这篇文章

    • applicationDidFinishLaunching 的上面通过 NSStatusBar 实例化一个 NSStatusItem 对象, 通过设置此对象, 我们可以进行一系列的操作,例如icon、title、action等.

@NSApplicationMain

class AppDelegate: NSObject, NSApplicationDelegate {

    @IBOutlet weak var window: NSWindow!

    let statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.squareLength)

    func applicationDidFinishLaunching(_ aNotification: Notification) {
// Insert code here to initialize your application
let icon = NSImage(named: NSImage.Name(rawValue: "icon16*16"))
icon?.isTemplate = true
statusItem.image = icon
statusItem.button?.target = self
statusItem.button?.action = #selector(onStatusItemDidClicked(_:))
} @objc private func onStatusItemDidClicked(_ item: NSStatusItem) {
print("onStatusItemDidClicked")
}

}

```

  • cmd + R 运行一下, 跑起来了。 状态栏出现了, 点击一下, 控制台出现打印信息。 Good!

    动手一下: 删除 icon?.isTemplate = true 会是什么效果?

二、处理 Dock栏以 及 状态栏左

当我们点击cmd + R 运行时候, 会出现如下情况:

  • 左边的状态栏

  • Dock栏 以及显示一个系统默认给加载的窗口.

找到 MainMenu.xib, 然后删除 Main Menu 以及 Window, 然后运行。

运行好之后,你会发现,状态栏左在没有那多选项了,但是还是存在一个 . Dock 栏以后存在, 值得称赞的是,系统默认加载的 Window 消失了

这是你需要在系统设置文件 info.plist 设置 Application is agent (UIElement) = YES 即可, 如下图

对了,别忘记删除 applicationDidFinishLaunching 上面的 @IBOutlet weak var window: NSWindow!, 因为window 以及被我们干没了。

三、NSPopover 使用

观察官方的 Pap.er, 点击 状态栏icon, 会出现如下界面:

.

macOS开发中,系统为我们提供了 NSPopover 来实现此效果。

3.1 NSPopover 属性介绍

查看NSPopover文档, 简单介绍其属性。

属性 说明
@IBOutlet weak open var delegate: NSPopoverDelegate? 代理
open var appearance: NSAppearance? popover的外观, 默认 NSAppearanceNameVibrantLight
open var behavior: NSPopover.Behavior Popover 的行为:
applicationDefined 表示NSPopover的关闭需要App自己负责控制;
transient: 表示只要点击到NSPopover显示的窗口之外就自动关闭;
semitransient: 表示 只要点击到NSPopover显示的窗口之外就自动关闭,但是点击到当前App 窗口之外不会关闭。
open var animates: Bool 是否动画
@IBOutlet open var contentViewController: NSViewController? popover 内容展示的控制器, 在show之前一定要设置
open var contentSize: NSSize popover 显示的大小
方法
open func show(relativeTo positioningRect: NSRect, of positioningView: NSView, preferredEdge: NSRectEdge) 显示
@IBAction open func performClose(_ sender: Any?) 关闭popover 但是有可能会关不掉
open func close() 强制关闭

3.2 JUST DO IT

简单介绍之后,我们开始动手吧。

Step1:applicationDidFinishLaunching 上面添加一个 NSPopover 的实例;

let popover = NSPopover()

Step2:applicationDidFinishLaunching 里面添加如下设置:

popover.behavior = .transient
popover.animates = true
popover.contentSize = CGSize(width: 285, height: 600)

Step3:statusItem.button的响应方法中添加对应的响应

if !self.popover.isShown {
self.popover.show(relativeTo: statusBarButton.bounds, of: statusBarButton, preferredEdge: .minY)
}

仅仅这几步还是不行的, 我们忘记了最重要的设置 contentViewController.点击 File->New->File->MacOS->Cocoa Class, 新建一个 MainPopoverViewController, 我们采用xib 来布局视图,当然 这不是必须的;

Last Step: 在 Step2 设置 popover 的地方,添加一句

popover.contentViewController =  MainPopoverViewController(nibName: NSNib.Name(rawValue: "MainPopoverViewController"), bundle: nil)

设置完之后, cmd + R 运行, 点击Status Item。显示如下,Great!

3.3 细节优化

  1. Popover 展示出来之后, 用户如果点击非App 区域, 那么需要Popover 消失, 有如下两种方式:
  • 获取用户点击的区域, 然后判断用户点击是否在Popover的 contentViewController上-- 此种方式比较复杂
  • 根据 NSApplicationDelegateapplicationWillResignActive 通知处理,简单,有效。
    func applicationWillResignActive(_ notification: Notification) {
    self.popover.close()
    }
  1. MainPopoverViewController 从nib中加载出来,但是外界其实不要知道其实例化方式, 给 MainPopoverViewController 提供一个类方法实例化即可。
extension MainPopoverViewController {
static func make() -> MainPopoverViewController {
let vc = MainPopoverViewController(nibName: NSNib.Name(rawValue: "MainPopoverViewController"), bundle: nil)
return vc
}
}

四、代码

AppDelegate.swift

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate { let statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.squareLength) let popover = NSPopover() func applicationDidFinishLaunching(_ aNotification: Notification) {
// Insert code here to initialize your application
let icon = NSImage(named: NSImage.Name(rawValue: "icon16*16"))
icon?.isTemplate = true
statusItem.image = icon
statusItem.button?.target = self
statusItem.button?.action = #selector(onStatusItemDidClicked(_:)) popover.contentViewController = MainPopoverViewController.make()
popover.behavior = .transient
popover.animates = true
popover.contentSize = CGSize(width: 285, height: 600) } @objc private func onStatusItemDidClicked(_ statusBarButton: NSStatusBarButton) {
print("onStatusItemDidClicked")
if !self.popover.isShown {
self.popover.show(relativeTo: statusBarButton.bounds, of: statusBarButton, preferredEdge: .minY)
}
} func applicationWillResignActive(_ notification: Notification) {
self.popover.close()
}
}

MainPopoverViewController.swift

extension MainPopoverViewController {
static func make() -> MainPopoverViewController {
let vc = MainPopoverViewController(nibName: NSNib.Name(rawValue: "MainPopoverViewController"), bundle: nil)
return vc
}
} class MainPopoverViewController: NSViewController { override func viewDidLoad() {
super.viewDidLoad()
} }

Pap.er 模仿 - 第一天的更多相关文章

  1. Pap.er 模仿 - 第二天

    最后更新:2017-12-19 在第一天中, 我们完成了项目的基本设置.隐藏Dock.显示和隐藏Popover等操作,接下来的这章中, Pap.er将会去搭建对应 UI. 一.设置Popover对应颜 ...

  2. power designer 绘制E-R 图

    总体概括:本篇主要先介绍E-R图的一些基本概念,然后介绍怎么绘制E-R图,特别是用power designer 的反向工程怎么把表中对字段的注释也展示出来. 1.E-R图的基本概念: E-R图就是en ...

  3. Tomcat6启用Gzip压缩功能

    配置Tomcat根目录下/conf/server.xml文件: <Connector port="8080" protocol="HTTP/1.1" co ...

  4. mongo数据库的常见操作

    连接mongodb数据库的命令查看对应数据库mongo.exeuse shujukuming;db.opportunity.findOne({"id":5}); db.opport ...

  5. 爬取5K分辨率超清唯美壁纸

    目录 爬取5K分辨率超清唯美壁纸 简介 编写思路 使用教程 演示图片 完整源代码 @ 爬取5K分辨率超清唯美壁纸 简介 壁纸的选择其实很大程度上能看出电脑主人的内心世界,有的人喜欢风景,有的人喜欢星空 ...

  6. Mac 上有哪些比较有意思的小软件?

    文章素材来源:微博.新浪看点 收录于:风云社区(SCOEE)[提供mac软件下载] 更多专题,可关注小编[磨人的小妖精],查看我的文章,也可上[风云社区 SCOEE],查找和下载相关软件资源. (一) ...

  7. MetaMask/safe-event-emitter

    https://github.com/MetaMask/safe-event-emitter safe-event-emitter An EventEmitter that isolates the ...

  8. MSER最稳定极值区域源码分析

    最稳定极值区域介绍 如把灰度图看成高低起伏的地形图,其中灰度值看成海平面高度的话,MSER的作用就是在灰度图中找到符合条件的坑洼.条件为坑的最小高度,坑的大小,坑的倾斜程度,坑中如果已有小坑时大坑与小 ...

  9. 已知二叉树的中序序列为DBGEAFC,后序序列为DGEBFCA,给出相应的二叉树

    面对这种问题时我们该怎么解决? 今天写数据结构题.发现了一道总是碰见问题的题在这里我写了一种求解方法我自己称它为分层递归求解. 第一步通过观察我们知道后序遍历时最后一个是根节点A 在中序序列中A的左边 ...

随机推荐

  1. HTTP 常见相应状态码及含义

    1xx:信息 100 Continue 服务器仅接收到部分请求,但是一旦服务器并没有拒绝该请求,客户端应该继续发送其余的请求. 101 Switching Protocols 服务器转换协议:服务器将 ...

  2. [DS+Algo] 007 希尔排序及其代码实现

    步骤 将数组列在一个表(一行多列)中,按特定的步长进行插入排序 步长从 length/2 到 1,每次除 2 将数组转换至表是为了更好地理解这算法,算法本身还是使用数组进行排序 算法性能 (根据步长序 ...

  3. Java——HashMap使用Demo

    package map; import java.util.Collection; import java.util.HashMap; import java.util.Set; public cla ...

  4. roslyn\csc.exe

    vs2019调试运行时提示roslyn\csc.exe错误时在nuget包管理器控制台里输入:  Update-Package Microsoft.CodeDom.Providers.DotNetCo ...

  5. P1536村村通

    这是一个并查集的题,被洛谷评为提高—. 拿到这个题便看出了这是一个裸的并查集,于是就写了一个模板,结果发现连输入都输不进去,一看竟然是多组数据,,然后看到N==0结束,于是便加了一层while.之后提 ...

  6. 异步Promise及Async/Await可能最完整入门攻略

    此文只介绍Async/Await与Promise基础知识与实际用到注意的问题,将通过很多代码实例进行说明,两个实例代码是setDelay和setDelaySecond. tips:本文系原创转自我的博 ...

  7. (ES6)数据处理常用工具方法收集(更新状态: on)

    1. 扁平数组转成tree结构(来源: StackOverflow的印度老哥写的) // Data Set // One top level comment var comments = [{ id: ...

  8. MacOS X快捷键一览(http://www.cnblogs.com/ios8/p/Mac-OSX-keyword-cmd.html)

    ctrl+shift                                    快速放大dock的图标会暂时放大,而如果你开启了dock放大Command+Option+W         ...

  9. Huawei交换机路由器远程Telnet配置

    <huawei>system-view Enter system view, return user view with Ctrl+Z.[huawei]interface g0/0/0[h ...

  10. octave - 用于数值计算的高级交互式语言

    SYNOPSIS 总览 octave [options] OPTIONS 选项 octave 全部命令行选项可以通过运行命令 octave --help 来查看. DESCRIPTION 描述 Oct ...