最后更新: 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. editText内容从hint右输入

    如何让editText内容从hint右输入呢: <EditText android:id="@+id/et_password" android:textColor=" ...

  2. js中 json对象的转化 JSON.parse()

    JSON.parse() 方法用来解析JSON字符串,json.parse()将字符串转成json对象.构造由字符串描述的JavaScript值或对象.提供可选的reviver函数用以在返回之前对所得 ...

  3. 开篇——从程序员到IT经理

    2002年~2005年我在广州的广东水力电力职业技术学院求学,主修网络工程.求学期间,我从事最多的就是玩游戏,当时就是玩MU和CS,所以有一门编程课叫C语言的“肥佬”(广东话)了,要补考,没办法,于是 ...

  4. 极*Java速成教程 - (6)

    Java高级特性 String String是Java中的字符串类型,字符串类型在内存中是一个不可变的对象.如果要对字符串对象进行修改,如果是较少的修改可以使用+运算符,Java会自动进行优化,但如果 ...

  5. ubuntu 新建root用户

    1. sudo passwd :设置root用户密码 2. 切换用户 方式一:su 方式二: su root 3. 新增普通用户

  6. python中输入某年某月某日,判断这一天是这一年的第几天?

    输入某年某月某日,判断这一天是这一年的第几天?程序分析 特殊情况,闰年时需考虑二月多加一天: 直接上代码 #定义一个函数,判断是否为闰年 def leapyear(y): return (y % 40 ...

  7. 搜索专题: HDU1258Sum It Up

    Sum It Up Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total ...

  8. vue生命周期简单总结

    生命周期(钩子函数):一个组件从创建到销毁的过程就是生命周期     beforeCreate: 创建前     1.当前vue实例化的时候会做一个初始化的操作,在这个生命周期函数中我们可以做初始化的 ...

  9. UVa11538 A Chess Queen

    A Chess Queen Problem A Chess Queen  Input: Standard Input Output: Standard Output You probably know ...

  10. “HTTP 错误 404.15 - Not Found 请求筛选模块被配置为拒绝包含的查询字符串过长的请求”之解决办法

    今天同事在做通过接口访问数据时,由于提交的一个参数内容比较多,导致测试时报了以下错误. 同时页面又给出了以下提示: 所以最终根据在网上找了相关资料总结出一下解决办法. 1. 在Web.config配置 ...