使用Swift开发一个MacOS的菜单状态栏App
2016-11-20 21:34
471 查看
猴子原创,欢迎转载。转载请注明: 转载自Cocos2Der-CSDN,谢谢!
原文地址: http://blog.csdn.net/cocos2der/article/details/52054107
这两天突然想看看OSX下的App开发,看了几篇文章。下面这一篇我觉得入门是非常好的。我仅转述为中文,并非原文翻译。原文地址:http://footle.org/WeatherBar/
下面开始介绍如何使用Swift开发一个Mac Menu Bar(Status Bar) App。通过做一个简单的天气app。天气数据来源于OpenWeatherMap
完成后的效果如下:
打开Xcode,Create a New Project or File ⟶ New ⟶ Project ⟶ Application ⟶ Cocoa Application ( OS X 这一栏)。点击下一步。
打开MainMenu.xib,删除默认的windows和menu菜单。因为我们是状态栏app,不需要菜单栏,不需要主窗口。
添加一个Menu菜单
删除其中默认的2个子菜单选项,仅保留1个。并将保留的这个改名为“Quit”。
打开双视图绑定Outlet
将Menu Outlet到AppDelegate,命名为statusMenu
将子菜单Quit绑定Action到AppDelegate,命名为quitClicked
你可以删除
代码
在AppDelegate.swift中statusMenu下方添加
applicationDidFinishLaunching函数中添加:
2
在quitClicked中添加:
此时你的代码应该如下:
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
运行,你可以看到一个状态栏了。
你应该注意到了,当你运行后,底部Dock栏里出现了一个App启动的Icon。但实际上我们也不需要这个启动icon,打开Info,添加 “Application is agent (UIElement)”为YES。
运行一下,不会出现dock启动icon了。
状态栏icon尺寸请使用18x18
, 36x36(@2x)
,
54x54(@3x),添加这1x和2x两张图到Assets.xcassets中。
在applicationDidFinishLaunching中,修改为如下:
2
3
4
运行一下,你应该看到状态栏icon了。
如果我们进一步写下去,你会发现大量代码在AppDelegate中,我们不希望这样。下面我们为Menu创建一个Controller来管理。
新建一个NSObject的StatusMenuController.swift, File ⟶ New File ⟶ OS X Source ⟶ Cocoa Class ⟶ Next
代码如下:
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
还原AppDelegate,修改为如下:
2
3
4
5
6
7
8
9
10
11
12
13
注意,因为删除了AppDelegate中的Outlet注册,所以你需要重新连Outlet,但在这之前我们需要先做一件事。(你可以试试连接StatusMenuController中的Outlet,看看会怎么样?)
打开MainMenu.xib,添加一个Object。
将该Object的Class指定为StatusMenuController
重建Outlet到StatusMenuController,注意删除之前连接到AppDelegate的Outlet
当MainMenu.xib被初始化的时候,StatusMenuController下的awakeFromNib将会被执行,所以我们在里面做初始化工作。
运行一下,保证你全部正常工作了。
我们使用 OpenWeatherMap的天气数据,所以你得注册一个账号,获取到免费的API
Key。
添加WeatherAPI.swift, File ⟶ New File ⟶ OS X Source ⟶ Swift File ⟶ WeatherAPI.swift,加入如下代码,并使用你自己的API Key。
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
添加一个Update子菜单到Status Menu。
绑定Action到StatusMenuController.swift,取名为updateClicked
开始使用WeatherAPI, 在StatusMenuController中let statusItem下面加入:
在updateClicked中加入:
注意OSX 10.11之后请添加NSAppTransportSecurity,保证http能使用。
运行一下,然后点击Update菜单。你会收到一个json格式的天气数据。
我们再调整下StatusMenuController代码, 添加一个updateWeather函数,修改后如下:
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
你可以使用 SwiftyJSON,但本次我们先不使用第三方库。我们得到的天气数据如下:
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
在WeatherAPI.swift添加天气结构体用于解析son
2
3
4
5
解析son
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
修改fetchWeather函数去调用weatherFromJSONData
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
如果此时你运行,你会收到
给Weather结构体添加一个description
2
3
4
5
6
7
8
9
再运行试试。
在 WeatherAPI.swift中增加delegate协议
2
3
声明
添加初始化
2
3
修改fetchWeather
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
StatusMenuController添加WeatherAPIDelegate
2
3
4
5
6
7
8
9
10
11
12
13
14
Callback实现,修改WeatherAPI.swift中fetchWeather:
修改fetchWeather内容
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
在controller中
2
3
4
5
运行一下,确保都正常。
在MainMenu.xib中添加子菜单 “Weather”(你可以添加2个Separator Menu Item用于子菜单分割线)
在updateWeather中,替换NSLog:
2
3
运行一下,看看天气是不是显示出来了。
打开MainMenu.xib,拖一个Custom View进来。
拖一个Image View到Custom View中,设置ImageView宽高度为50。
拖两个Label进来,分别为City和Temperature
创建一个名为WeatherView的NSView,New File ⟶ OS X Source ⟶ Cocoa Class
在MainMenu.xib中,将Custom View的Class指定为WeatherView
绑定WeatherView Outlet:
2
3
4
5
6
7
并添加update:
2
3
4
5
6
7
8
注意这里使用dispatch_async调用UI线程来刷新UI,因为后面调用此函数的数据来源于网络请求子线程。
StatusMenuController添加weatherView outlet
2
3
4
5
子菜单Weather绑定到视图
2
update中:
2
3
4
5
运行一下。
先添加天气素材到Xcode,天气素材可以在http://openweathermap.org/weather-conditions 这里找到。这里我已经提供了一份icon
zip, 解压后放Xcode。
WeatherAPI.swift的Weather struct中,添加
在weatherFromJSONData中:
2
3
4
5
6
在weatherFromJSONData:
2
3
4
5
6
在WeatherView的update中:
运行一下,Pretty!
在MainMenu.xib MenuItem中,添加一个Menu Item命名为“Preferences…”
并绑定action,命名为“preferencesClicked”
添加NSWindowController命名为PreferencesWindow.swift New ⟶ File ⟶ OS X Source ⟶ Cocoa Class , 勾选同时创建XIB.在XIB中添加Label和Text Field。效果如下:
Outlet cityTextField到PreferencesWindow.swift
在PreferencesWindow.swift中添加:
2
3
windowDidLoad()中修改:
2
3
最终PreferencesWindow.swift如下:
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
StatusMenuController.swift中添加preferencesWindow
awakeFromNib中,注意在updateWeather()之前:
preferencesClicked中:
下面为 preferences window 添加NSWindowDelegate,刷新视图。
并增加
2
3
4
增加协议:
2
3
增加delegate:
在windowWillClose最下面调用
回到StatusMenuController中,添加PreferencesWindowDelegate
实现代理:
2
3
awakeFromNib中:
2
在StatusMenuController中增加默认城市
let DEFAULT_CITY = “Seattle, WA”
修改updateWeather
2
3
4
5
6
7
咱们也可以在PreferencesWindow.swift windowDidLoad中设置city默认值
2
3
运行。一切OK。
其他:
- 你也可以试试使用
- 试试点击天气后跳转到天气中心
- 完整工程: WeatherBar
原文地址: http://blog.csdn.net/cocos2der/article/details/52054107
这两天突然想看看OSX下的App开发,看了几篇文章。下面这一篇我觉得入门是非常好的。我仅转述为中文,并非原文翻译。原文地址:http://footle.org/WeatherBar/
下面开始介绍如何使用Swift开发一个Mac Menu Bar(Status Bar) App。通过做一个简单的天气app。天气数据来源于OpenWeatherMap
完成后的效果如下:
一、开始建立工程
打开Xcode,Create a New Project or File ⟶ New ⟶ Project ⟶ Application ⟶ Cocoa Application ( OS X 这一栏)。点击下一步。
二、开始代码工作
打开MainMenu.xib,删除默认的windows和menu菜单。因为我们是状态栏app,不需要菜单栏,不需要主窗口。 添加一个Menu菜单
删除其中默认的2个子菜单选项,仅保留1个。并将保留的这个改名为“Quit”。
打开双视图绑定Outlet
将Menu Outlet到AppDelegate,命名为statusMenu
将子菜单Quit绑定Action到AppDelegate,命名为quitClicked
你可以删除
@IBOutlet weak var window: NSWindow!,这个app中用不上。
代码
在AppDelegate.swift中statusMenu下方添加
let statusItem = NSStatusBar.systemStatusBar().statusItemWithLength(NSVariableStatusItemLength)1
applicationDidFinishLaunching函数中添加:
statusItem.title = "WeatherBar" statusItem.menu = statusMenu1
2
在quitClicked中添加:
NSApplication.sharedApplication().terminate(self)1
此时你的代码应该如下:
import Cocoa1
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
@IBOutlet weak var statusMenu: NSMenu!
let statusItem = NSStatusBar.systemStatusBar().statusItemWithLength(NSVariableStatusItemLength)
@IBAction func quitClicked(sender: NSMenuItem) {
NSApplication.sharedApplication().terminate(self)
}
func applicationDidFinishLaunching(aNotification: NSNotification) {
statusItem.title = "WeatherBar" statusItem.menu = statusMenu
}
func applicationWillTerminate(aNotification: NSNotification) {
// Insert code here to tear down your application
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
运行,你可以看到一个状态栏了。
三、进阶一步,让App变得更好
你应该注意到了,当你运行后,底部Dock栏里出现了一个App启动的Icon。但实际上我们也不需要这个启动icon,打开Info,添加 “Application is agent (UIElement)”为YES。 运行一下,不会出现dock启动icon了。
四、添加状态栏Icon
状态栏icon尺寸请使用18x18, 36x36(@2x)
,
54x54(@3x),添加这1x和2x两张图到Assets.xcassets中。
在applicationDidFinishLaunching中,修改为如下:
let icon = NSImage(named: "statusIcon") icon?.template = true // best for dark mode statusItem.image = icon statusItem.menu = statusMenu1
2
3
4
运行一下,你应该看到状态栏icon了。
五、重构下代码
如果我们进一步写下去,你会发现大量代码在AppDelegate中,我们不希望这样。下面我们为Menu创建一个Controller来管理。新建一个NSObject的StatusMenuController.swift, File ⟶ New File ⟶ OS X Source ⟶ Cocoa Class ⟶ Next
代码如下:
// StatusMenuController.swift1
import Cocoa
class StatusMenuController: NSObject {
@IBOutlet weak var statusMenu: NSMenu!
let statusItem = NSStatusBar.systemStatusBar().statusItemWithLength(NSVariableStatusItemLength)
override func awakeFromNib() {
let icon = NSImage(named: "statusIcon") icon?.template = true // best for dark mode statusItem.image = icon statusItem.menu = statusMenu
}
@IBAction func quitClicked(sender: NSMenuItem) {
NSApplication.sharedApplication().terminate(self)
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
还原AppDelegate,修改为如下:
// AppDelegate.swift import Cocoa @NSApplicationMain class AppDelegate: NSObject, NSApplicationDelegate { func applicationDidFinishLaunching(aNotification: NSNotification) { // Insert code here to initialize your application } func applicationWillTerminate(aNotification: NSNotification) { // Insert code here to tear down your application } }1
2
3
4
5
6
7
8
9
10
11
12
13
注意,因为删除了AppDelegate中的Outlet注册,所以你需要重新连Outlet,但在这之前我们需要先做一件事。(你可以试试连接StatusMenuController中的Outlet,看看会怎么样?)
打开MainMenu.xib,添加一个Object。
将该Object的Class指定为StatusMenuController
重建Outlet到StatusMenuController,注意删除之前连接到AppDelegate的Outlet
当MainMenu.xib被初始化的时候,StatusMenuController下的awakeFromNib将会被执行,所以我们在里面做初始化工作。
运行一下,保证你全部正常工作了。
六、天气Api
我们使用 OpenWeatherMap的天气数据,所以你得注册一个账号,获取到免费的APIKey。
添加WeatherAPI.swift, File ⟶ New File ⟶ OS X Source ⟶ Swift File ⟶ WeatherAPI.swift,加入如下代码,并使用你自己的API Key。
import Foundation class WeatherAPI { let API_KEY = "your-api-key-here" let BASE_URL = "http://api.openweathermap.org/data/2.5/weather" func fetchWeather(query: String) { let session = NSURLSession.sharedSession() // url-escape the query string we're passed let escapedQuery = query.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet()) let url = NSURL(string: "\(BASE_URL)?APPID=\(API_KEY)&units=imperial&q=\(escapedQuery!)") let task = session.dataTaskWithURL(url!) { data, response, err in // first check for a hard error if let error = err { NSLog("weather api error: \(error)") } // then check the response code if let httpResponse = response as? NSHTTPURLResponse { switch httpResponse.statusCode { case 200: // all good! let dataString = NSString(data: data!, encoding: NSUTF8StringEncoding) as! String NSLog(dataString) case 401: // unauthorized NSLog("weather api returned an 'unauthorized' response. Did you set your API key?") default: NSLog("weather api returned response: %d %@", httpResponse.statusCode, NSHTTPURLResponse.localizedStringForStatusCode(httpResponse.statusCode)) } } } task.resume() } }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
添加一个Update子菜单到Status Menu。
绑定Action到StatusMenuController.swift,取名为updateClicked
开始使用WeatherAPI, 在StatusMenuController中let statusItem下面加入:
let weatherAPI = WeatherAPI(),
在updateClicked中加入:
weatherAPI.fetchWeather("Seattle")
注意OSX 10.11之后请添加NSAppTransportSecurity,保证http能使用。
运行一下,然后点击Update菜单。你会收到一个json格式的天气数据。
我们再调整下StatusMenuController代码, 添加一个updateWeather函数,修改后如下:
import Cocoa1
class StatusMenuController: NSObject {
@IBOutlet weak var statusMenu: NSMenu!
let statusItem = NSStatusBar.systemStatusBar().statusItemWithLength(NSVariableStatusItemLength)
let weatherAPI = WeatherAPI()
override func awakeFromNib() {
statusItem.menu = statusMenu
let icon = NSImage(named: "statusIcon") icon?.template = true // best for dark mode statusItem.image = icon statusItem.menu = statusMenu
updateWeather()
}
func updateWeather() {
weatherAPI.fetchWeather("Seattle")
}
@IBAction func updateClicked(sender: NSMenuItem) {
updateWeather()
}
@IBAction func quitClicked(sender: NSMenuItem) {
NSApplication.sharedApplication().terminate(self)
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
七、解析Json
你可以使用 SwiftyJSON,但本次我们先不使用第三方库。我们得到的天气数据如下:{ "coord": { "lon": -122.33, "lat": 47.61 }, "weather": [{ "id": 800, "main": "Clear", "description": "sky is clear", "icon": "01n" }], "base": "cmc stations", "main": { "temp": 57.45, "pressure": 1018, "humidity": 59, "temp_min": 53.6, "temp_max": 62.6 }, "wind": { "speed": 2.61, "deg": 19.5018 }, "clouds": { "all": 1 }, "dt": 1444623405, "sys": { "type": 1, "id": 2949, "message": 0.0065, "country": "US", "sunrise": 1444659833, "sunset": 1444699609 }, "id": 5809844, "name": "Seattle", "cod": 200 }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
在WeatherAPI.swift添加天气结构体用于解析son
struct Weather { var city: String var currentTemp: Float var conditions: String }1
2
3
4
5
解析son
func weatherFromJSONData(data: NSData) -> Weather? { typealias JSONDict = [String:AnyObject] let json : JSONDict do { json = try NSJSONSerialization.JSONObjectWithData(data, options: []) as! JSONDict } catch { NSLog("JSON parsing failed: \(error)") return nil } var mainDict = json["main"] as! JSONDict var weatherList = json["weather"] as! [JSONDict] var weatherDict = weatherList[0] let weather = Weather( city: json["name"] as! String, currentTemp: mainDict["temp"] as! Float, conditions: weatherDict["main"] as! String ) return weather }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
修改fetchWeather函数去调用weatherFromJSONData
let task = session.dataTaskWithURL(url!) { data, response, error in // first check for a hard error if let error = err { NSLog("weather api error: \(error)") } // then check the response code if let httpResponse = response as? NSHTTPURLResponse { switch httpResponse.statusCode { case 200: // all good! if let weather = self.weatherFromJSONData(data!) { NSLog("\(weather)") } case 401: // unauthorized NSLog("weather api returned an 'unauthorized' response. Did you set your API key?") default: NSLog("weather api returned response: %d %@", httpResponse.statusCode, NSHTTPURLResponse.localizedStringForStatusCode(httpResponse.statusCode)) } } }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
如果此时你运行,你会收到
2016-07-28 11:25:08.457 WeatherBar[49688:1998824] Optional(WeatherBar.Weather(city: "Seattle", currentTemp: 51.6, conditions: "Clouds"))1
给Weather结构体添加一个description
struct Weather: CustomStringConvertible { var city: String var currentTemp: Float var conditions: String var description: String { return "\(city): \(currentTemp)F and \(conditions)" } }1
2
3
4
5
6
7
8
9
再运行试试。
八、Weather用到Controller中
在 WeatherAPI.swift中增加delegate协议protocol WeatherAPIDelegate { func weatherDidUpdate(weather: Weather) }1
2
3
声明
var delegate: WeatherAPIDelegate?
添加初始化
init(delegate: WeatherAPIDelegate) { self.delegate = delegate }1
2
3
修改fetchWeather
let task = session.dataTaskWithURL(url!) { data, response, error in // first check for a hard error if let error = err { NSLog("weather api error: \(error)") } // then check the response code if let httpResponse = response as? NSHTTPURLResponse { switch httpResponse.statusCode { case 200: // all good! if let weather = self.weatherFromJSONData(data!) { self.delegate?.weatherDidUpdate(weather) } case 401: // unauthorized NSLog("weather api returned an 'unauthorized' response. Did you set your API key?") default: NSLog("weather api returned response: %d %@", httpResponse.statusCode, NSHTTPURLResponse.localizedStringForStatusCode(httpResponse.statusCode)) } } }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
StatusMenuController添加WeatherAPIDelegate
class StatusMenuController: NSObject, WeatherAPIDelegate { ... var weatherAPI: WeatherAPI! override func awakeFromNib() { ... weatherAPI = WeatherAPI(delegate: self) updateWeather() } ... func weatherDidUpdate(weather: Weather) { NSLog(weather.description) } ...1
2
3
4
5
6
7
8
9
10
11
12
13
14
Callback实现,修改WeatherAPI.swift中fetchWeather:
func fetchWeather(query: String, success: (Weather) -> Void) {
修改fetchWeather内容
let task = session.dataTaskWithURL(url!) { data, response, error in // first check for a hard error if let error = err { NSLog("weather api error: \(error)") } // then check the response code if let httpResponse = response as? NSHTTPURLResponse { switch httpResponse.statusCode { case 200: // all good! if let weather = self.weatherFromJSONData(data!) { success(weather) } case 401: // unauthorized NSLog("weather api returned an 'unauthorized' response. Did you set your API key?") default: NSLog("weather api returned response: %d %@", httpResponse.statusCode, NSHTTPURLResponse.localizedStringForStatusCode(httpResponse.statusCode)) } } }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
在controller中
func updateWeather() { weatherAPI.fetchWeather("Seattle, WA") { weather in NSLog(weather.description) } }1
2
3
4
5
运行一下,确保都正常。
九、显示天气
在MainMenu.xib中添加子菜单 “Weather”(你可以添加2个Separator Menu Item用于子菜单分割线) 在updateWeather中,替换NSLog:
if let weatherMenuItem = self.statusMenu.itemWithTitle("Weather") { weatherMenuItem.title = weather.description }1
2
3
运行一下,看看天气是不是显示出来了。
十、创建一个天气视图
打开MainMenu.xib,拖一个Custom View进来。拖一个Image View到Custom View中,设置ImageView宽高度为50。
拖两个Label进来,分别为City和Temperature
创建一个名为WeatherView的NSView,New File ⟶ OS X Source ⟶ Cocoa Class
在MainMenu.xib中,将Custom View的Class指定为WeatherView
绑定WeatherView Outlet:
import Cocoa class WeatherView: NSView { @IBOutlet weak var imageView: NSImageView! @IBOutlet weak var cityTextField: NSTextField! @IBOutlet weak var currentConditionsTextField: NSTextField! }1
2
3
4
5
6
7
并添加update:
func update(weather: Weather) { // do UI updates on the main thread dispatch_async(dispatch_get_main_queue()) { self.cityTextField.stringValue = weather.city self.currentConditionsTextField.stringValue = "\(Int(weather.currentTemp))°F and \(weather.conditions)" self.imageView.image = NSImage(named: weather.icon) } }1
2
3
4
5
6
7
8
注意这里使用dispatch_async调用UI线程来刷新UI,因为后面调用此函数的数据来源于网络请求子线程。
StatusMenuController添加weatherView outlet
class StatusMenuController: NSObject { @IBOutlet weak var statusMenu: NSMenu! @IBOutlet weak var weatherView: WeatherView! var weatherMenuItem: NSMenuItem! ...1
2
3
4
5
子菜单Weather绑定到视图
weatherMenuItem = statusMenu.itemWithTitle("Weather") weatherMenuItem.view = weatherView1
2
update中:
func updateWeather() { weatherAPI.fetchWeather("Seattle, WA") { weather in self.weatherView.update(weather) } }1
2
3
4
5
运行一下。
十一、添加天气图片
先添加天气素材到Xcode,天气素材可以在http://openweathermap.org/weather-conditions 这里找到。这里我已经提供了一份iconzip, 解压后放Xcode。
WeatherAPI.swift的Weather struct中,添加
var icon: String
在weatherFromJSONData中:
let weather = Weather( city: json["name"] as! String, currentTemp: mainDict["temp"] as! Float, conditions: weatherDict["main"] as! String, icon: weatherDict["icon"] as! String )1
2
3
4
5
6
在weatherFromJSONData:
let weather = Weather( city: json["name"] as! String, currentTemp: mainDict["temp"] as! Float, conditions: weatherDict["main"] as! String, icon: weatherDict["icon"] as! String )1
2
3
4
5
6
在WeatherView的update中:
imageView.image = NSImage(named: weather.icon)1
运行一下,Pretty!
十二、添加设置
在MainMenu.xib MenuItem中,添加一个Menu Item命名为“Preferences…” 并绑定action,命名为“preferencesClicked”
添加NSWindowController命名为PreferencesWindow.swift New ⟶ File ⟶ OS X Source ⟶ Cocoa Class , 勾选同时创建XIB.在XIB中添加Label和Text Field。效果如下:
Outlet cityTextField到PreferencesWindow.swift
在PreferencesWindow.swift中添加:
override var windowNibName : String! { return "PreferencesWindow" }1
2
3
windowDidLoad()中修改:
self.window?.center() self.window?.makeKeyAndOrderFront(nil) NSApp.activateIgnoringOtherApps(true)1
2
3
最终PreferencesWindow.swift如下:
import Cocoa1
class PreferencesWindow: NSWindowController {
@IBOutlet weak var cityTextField: NSTextField!
override var windowNibName : String! { return "PreferencesWindow" }
override func windowDidLoad() {
super.windowDidLoad()
self.window?.center() self.window?.makeKeyAndOrderFront(nil) NSApp.activateIgnoringOtherApps(true)
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
StatusMenuController.swift中添加preferencesWindow
var preferencesWindow: PreferencesWindow!
awakeFromNib中,注意在updateWeather()之前:
preferencesWindow = PreferencesWindow()
preferencesClicked中:
preferencesWindow.showWindow(nil)
下面为 preferences window 添加NSWindowDelegate,刷新视图。
class PreferencesWindow: NSWindowController, NSWindowDelegate {
并增加
func windowWillClose(notification: NSNotification) { let defaults = NSUserDefaults.standardUserDefaults() defaults.setValue(cityTextField.stringValue, forKey: "city") }1
2
3
4
增加协议:
protocol PreferencesWindowDelegate { func preferencesDidUpdate() }1
2
3
增加delegate:
var delegate: PreferencesWindowDelegate?1
在windowWillClose最下面调用
delegate?.preferencesDidUpdate()1
回到StatusMenuController中,添加PreferencesWindowDelegate
class StatusMenuController: NSObject, PreferencesWindowDelegate {1
实现代理:
func preferencesDidUpdate() { updateWeather() }1
2
3
awakeFromNib中:
preferencesWindow = PreferencesWindow() preferencesWindow.delegate = self1
2
在StatusMenuController中增加默认城市
let DEFAULT_CITY = “Seattle, WA”
修改updateWeather
func updateWeather() { let defaults = NSUserDefaults.standardUserDefaults() let city = defaults.stringForKey("city") ?? DEFAULT_CITY weatherAPI.fetchWeather(city) { weather in self.weatherView.update(weather) } }1
2
3
4
5
6
7
咱们也可以在PreferencesWindow.swift windowDidLoad中设置city默认值
let defaults = NSUserDefaults.standardUserDefaults() let city = defaults.stringForKey("city") ?? DEFAULT_CITY cityTextField.stringValue = city1
2
3
运行。一切OK。
其他:
- 你也可以试试使用
NSRunLoop.mainRunLoop().addTimer(refreshTimer!, forMode: NSRunLoopCommonModes)来定时updateWeather.
- 试试点击天气后跳转到天气中心
NSWorkspace.sharedWorkspace().openURL(url: NSURL))
- 完整工程: WeatherBar
相关文章推荐
- 使用Swift开发一个MacOS的菜单状态栏App
- 使用Swift开发一个MacOS的菜单状态栏App
- 使用Swift开发一个MacOS的菜单状态栏App
- 使用Django开发一个图书管理系统----04.通过admin模块管理我们的app和model
- [Phonegap+Sencha Touch] 移动开发61 使用 URL Schemes实现一个App启动另一个App的功能
- 快速了解微信小程序的使用,一个根据小程序的框架开发的todos app
- 一个高度使用百度地图的App开发实践总结
- 开发一个好项目:二、actvity简便跳转,创建菜单按钮,正确使用fragment
- iOS开发之使用UICollectionView实现美团App的分类功能【偶现大众点评App的一个小bug】
- iOS开发中大部分App的网络数据交换是基于HTTP协议的。本文将简单介绍在Swift中使用HTTP进行网络请求的几种方法。
- 快速了解微信小程序的使用,一个根据小程序的框架开发的todos app
- [swift]iOS开发:使用rar解压库Unrar4iOS遇到的那些坑,另附上自己的一个简易版的本地沙盒文件浏览器
- Swift 中使用 SwiftyJSON 制作一个比特币价格 APP
- swift开发笔记16 - 使用xib自定义一个控件(复合控件)
- 【安卓】安卓App开发思路 一步一个脚印(二)FragmentTabHost实现底部的菜单
- 使用jqMobi开发app基础:真的只能存在一个DOM吗?
- iOS开发使用Picker View实现一个图片浏览的App
- Swift基础使用方法(Swift开发之中的一个)
- 快速了解微信小程序的使用,一个根据小程序的框架开发的todos app