Aplikasi yang terletak di bilah menu sudah lama dikenal pengguna macOS. Beberapa aplikasi ini memiliki bagian "normal", yang lain hanya terletak di bilah menu.
Dalam panduan ini, Anda akan menulis aplikasi yang menampilkan beberapa kutipan dari orang-orang terkenal di jendela sembulan. Dalam proses membuat aplikasi ini, Anda akan belajar:
- menetapkan ikon aplikasi di bilah menu
- jadikan aplikasi hanya di-host di bilah menu
- tambahkan menu kustom
- perlihatkan jendela sembulan atas permintaan pengguna dan sembunyikan jika perlu, menggunakan Pemantauan Acara
Catatan: panduan ini mengasumsikan bahwa Anda terbiasa dengan Swift dan macOS.
Memulai
Luncurkan Xcode. Selanjutnya, pada menu
File / New / Project ... , pilih template
macOS / Application / Cocoa App dan klik
Next .
Pada layar berikutnya, masukkan Kutipan sebagai
Nama Produk , pilih
Nama Organisasi dan
Pengidentifikasi Organisasi Anda . Kemudian pastikan Swift dipilih sebagai bahasa aplikasi dan kotak centang
Use Storyboards dicentang. Hapus centang pada
Buat Aplikasi Berbasis Dokumen ,
Gunakan Data Inti ,
Sertakan tes Unit dan
Sertakan kotak centang Tes UI .

Terakhir, klik
Next lagi, tentukan lokasi untuk menyimpan proyek dan klik
Buat .
Setelah proyek baru dibuat, buka
AppDelegate.swift dan tambahkan properti berikut ke kelas:
let statusItem = NSStatusBar.system.statusItem(withLength:NSStatusItem.squareLength)
Di sini kita buat di bilah menu Item Status (ikon aplikasi) panjang tetap yang akan terlihat oleh pengguna.
Maka kita perlu menetapkan gambar kita ke item baru ini di menu bar sehingga kita dapat membedakan aplikasi baru kita.
Di navigator proyek, buka Aset.xcassets,
unggah gambar dan seret ke katalog aset.
Pilih gambar dan buka inspektur atribut. Ubah opsi
Render As ke
Templat Gambar .

Jika Anda menggunakan gambar Anda sendiri, pastikan bahwa gambar itu hitam dan putih dan konfigurasikan sebagai
gambar Templat sehingga ikon tampak hebat pada bilah menu gelap dan terang.
Kembali ke
AppDelegate.swift , dan tambahkan kode berikut ke
applicationDidFinishLaunching (_ :) if let button = statusItem.button { button.image = NSImage(named:NSImage.Name("StatusBarButtonImage")) button.action = #selector(printQuote(_:)) }
Di sini kita menetapkan ikon aplikasi yang baru saja kita tambahkan ke ikon aplikasi dan menetapkan
tindakan ketika kita mengkliknya.
Tambahkan metode berikut ke kelas:
@objc func printQuote(_ sender: Any?) { let quoteText = "Never put off until tomorrow what you can do the day after tomorrow." let quoteAuthor = "Mark Twain" print("\(quoteText) — \(quoteAuthor)") }
Metode ini hanya mencetak kutipan ke konsol.
Perhatikan
arahan metode
objc . Ini memungkinkan Anda menggunakan metode ini sebagai respons terhadap klik tombol.
Bangun dan jalankan aplikasi, dan Anda akan melihat aplikasi baru di bilah menu. Hore!
Setiap kali Anda mengklik ikon di bilah menu, perkataan Mark Twain yang terkenal ditampilkan di konsol Xcode.
Kami menyembunyikan jendela utama dan ikon di dok
Ada beberapa hal kecil yang perlu kita lakukan sebelum berhadapan langsung dengan fungsi:
- hapus ikon dock
- hapus jendela utama aplikasi yang tidak perlu
Untuk menghapus ikon dok, buka
Info.plist . Tambahkan kunci
Application is agent (UIElement) baru dan tetapkan nilainya ke
YES .

Sekarang saatnya berurusan dengan jendela aplikasi utama.
- buka Main.storyboard
- pilih adegan Window Controller dan hapus
- Lihat adegan Controller controller , kami akan segera menggunakannya

Bangun dan jalankan aplikasi. Sekarang aplikasi tidak memiliki jendela utama dan ikon yang tidak perlu di dok. Hebat!
Tambahkan menu ke Item Status
Respons satu klik jelas tidak cukup untuk aplikasi serius. Cara termudah untuk menambah fungsionalitas adalah dengan menambahkan menu. Tambahkan fungsi ini di akhir
AppDelegate .
func constructMenu() { let menu = NSMenu() menu.addItem(NSMenuItem(title: "Print Quote", action: #selector(AppDelegate.printQuote(_:)), keyEquivalent: "P")) menu.addItem(NSMenuItem.separator()) menu.addItem(NSMenuItem(title: "Quit Quotes", action: #selector(NSApplication.terminate(_:)), keyEquivalent: "q")) statusItem.menu = menu }
Dan kemudian tambahkan panggilan ini di akhir
applicationDidFinishLaunching (_ :) constructMenu()
Kami membuat
NSMenu , menambahkan 3 instance
NSMenuItem ke dalamnya, dan mengatur menu ini sebagai menu ikon aplikasi.
Beberapa poin penting:
- Judul item menu adalah teks yang muncul di menu. Tempat yang bagus untuk melokalkan aplikasi (jika perlu).
- aksi , seperti aksi tombol atau kontrol lainnya, adalah metode yang dipanggil ketika pengguna mengklik item menu
- keyEquivalent adalah pintasan keyboard yang dapat Anda gunakan untuk memilih item menu. Huruf kecil menggunakan Cmd sebagai pengubah, dan huruf kecil menggunakan Cmd + Shift . Ini hanya berfungsi jika aplikasi berada di paling atas dan aktif. Dalam kasus kami, perlu bahwa menu atau jendela lain terlihat, karena aplikasi kita tidak memiliki ikon di dok
- separatorItem adalah item menu tidak aktif dalam bentuk garis abu-abu antara elemen lain. Gunakan untuk grup
- printQuote adalah metode yang sudah Anda tentukan di AppDelegate , dan terminasi adalah metode yang ditentukan oleh NSApplication .
Luncurkan aplikasi dan Anda akan melihat menu dengan mengklik ikon aplikasi.

Coba klik pada menu - memilih
Print Quote akan menampilkan penawaran di konsol Xcode, dan
Quit Quotes mengakhiri aplikasi.
Tambahkan sembulan
Anda melihat betapa mudahnya menambahkan menu dari kode, tetapi menampilkan kutipan di konsol Xcode jelas bukan yang diharapkan pengguna dari aplikasi. Sekarang kita akan menambahkan controller tampilan sederhana untuk menampilkan kutipan dengan cara yang benar.
Buka menu
File / New / File ... , pilih template
macOS / Source / Cocoa Class dan klik
Next .

- beri nama kelas QuotesViewController
- membuat pewaris NSViewController
- pastikan kotak centang Juga buat file XIB untuk antarmuka pengguna tidak dicentang
- atur bahasa ke Swift
Terakhir, klik
Next lagi, pilih lokasi untuk menyimpan file, dan klik
Buat .
Sekarang buka
Main.storyboard . Rentangkan
View Controller Scene dan pilih
View Controller instance .

Pertama-tama pilih
Inspektur Identitas dan ubah kelas menjadi
QuotesViewController , lalu atur
Storyboard ID ke
QuotesViewControllerSekarang tambahkan kode berikut ke akhir file
QuotesViewController.swift :
extension QuotesViewController {
Apa yang terjadi di sini:
- kami mendapatkan tautan ke Main.storyboard .
- buat pengidentifikasi adegan yang cocok dengan yang baru saja kita instal di atas.
- buat instance dari QuotesViewController dan kembalikan.
Anda membuat metode ini, jadi sekarang semua orang yang menggunakan
QuotesViewController tidak perlu tahu bagaimana itu dibuat. Itu hanya bekerja.
Perhatikan
fatalError di dalam pernyataan
penjaga . Bisa menyenangkan untuk menggunakannya atau
pernyataan Kegagalan sehingga jika ada sesuatu yang salah dalam pengembangan, Anda sendiri, dan anggota tim pengembangan lainnya, mengetahui.
Sekarang kembali ke
AppDelegate.swift . Tambahkan properti baru.
let popover = NSPopover()
Kemudian ganti
pplicationDidFinishLaunching (_ :) dengan kode berikut:
func applicationDidFinishLaunching(_ aNotification: Notification) { if let button = statusItem.button { button.image = NSImage(named:NSImage.Name("StatusBarButtonImage")) button.action = #selector(togglePopover(_:)) } popover.contentViewController = QuotesViewController.freshController() }
Anda telah mengubah aksi klik untuk memanggil metode
togglePopover (_ :) , yang akan kami tulis sedikit kemudian. Selain itu, alih-alih mengonfigurasi dan menambahkan menu, kami mengonfigurasi jendela sembulan yang akan menampilkan sesuatu dari
QuotesViewController .
Tambahkan tiga metode berikut ke
AppDelegate :
@objc func togglePopover(_ sender: Any?) { if popover.isShown { closePopover(sender: sender) } else { showPopover(sender: sender) } } func showPopover(sender: Any?) { if let button = statusItem.button { popover.show(relativeTo: button.bounds, of: button, preferredEdge: NSRectEdge.minY) } } func closePopover(sender: Any?) { popover.performClose(sender) }
showPopover () menunjukkan munculan. Anda cukup menunjukkan dari mana asalnya, macOS memposisikannya dan menggambar panah, seolah-olah itu muncul dari menu bar.
closePopover () baru saja menutup popup, dan
togglePopover () adalah metode yang menunjukkan atau menyembunyikan popup, tergantung pada
kondisinya .
Luncurkan aplikasi dan klik ikonnya.

Semuanya baik-baik saja, tetapi di mana isinya?
Kami menerapkan Pengendali Tampilan Penawaran
Pertama, Anda membutuhkan model untuk menyimpan kutipan dan atribut. Buka menu
File / New / File ... dan pilih
template macOS / Source / Swift File , lalu
Next . Beri nama file
Penawaran dan klik
Buat .
Buka file
Quote.swift dan tambahkan kode berikut ke dalamnya:
struct Quote { let text: String let author: String static let all: [Quote] = [ Quote(text: "Never put off until tomorrow what you can do the day after tomorrow.", author: "Mark Twain"), Quote(text: "Efficiency is doing better what is already being done.", author: "Peter Drucker"), Quote(text: "To infinity and beyond!", author: "Buzz Lightyear"), Quote(text: "May the Force be with you.", author: "Han Solo"), Quote(text: "Simplicity is the ultimate sophistication", author: "Leonardo da Vinci"), Quote(text: "It's not just what it looks like and feels like. Design is how it works.", author: "Steve Jobs") ] } extension Quote: CustomStringConvertible { var description: String { return "\"\(text)\" — \(author)" } }
Di sini kita mendefinisikan struktur kutipan sederhana dan properti statis yang mengembalikan semua kutipan. Karena kami membuat
kutipan yang sesuai dengan protokol
CustomStringConvertible , kami dapat dengan mudah mendapatkan teks yang diformat dengan mudah.
Ada kemajuan, tetapi kami masih membutuhkan kontrol untuk menampilkan semua ini.
Tambahkan elemen antarmuka
Buka Main.storyboard dan tarik keluar 3 tombol (
Push Button ) dan label (
Multiline Label) pada pengontrol tampilan.
Posisikan tombol dan label sehingga terlihat seperti ini:

Pasang tombol kiri ke tepi kiri dengan celah 20 dan tengah secara vertikal.
Pasang tombol kanan ke tepi kanan dengan celah 20 dan tengah secara vertikal.
Pasang tombol bawah ke tepi bawah dengan celah 20 dan tengah secara horizontal.
Pasang tepi kiri dan kanan tanda ke tombol dengan celah 20, di tengah secara vertikal.

Anda akan melihat beberapa kesalahan tata letak, karena tidak ada informasi yang cukup untuk
tata letak otomatis untuk mengetahuinya.
Tetapkan
Prioritas Memeluk Konten Horizontal ke 249 untuk memungkinkan label untuk mengubah ukuran.

Sekarang lakukan hal berikut:
- atur gambar tombol kiri ke NSGoLeftTemplate dan hapus judulnya
- atur gambar tombol kanan ke NSGoRightTemplate dan hapus judulnya
- atur judul tombol di bawah ini ke Quit Quotes .
- atur perataan teks label ke tengah.
- pastikan Line Break pada label diatur ke Word Wrap .
Sekarang buka
QuotesViewController.swift dan tambahkan kode berikut untuk implementasi kelas
QuotesViewController :
@IBOutlet var textLabel: NSTextField!
Tambahkan ekstensi ini ke implementasi kelas. Sekarang di
QuotesViewController.swift ada dua ekstensi kelas.
Kami baru saja menambahkan
outlet untuk label yang akan kami gunakan untuk menampilkan kutipan, dan 3 metode rintisan yang akan kami sambungkan dengan tombol.
Menghubungkan kode dengan Interface Builder
Catatan: Xcode telah menempatkan lingkaran di sebelah kiri kode Anda - di sebelah kata kunci
IBAction dan
IBOutlet .

Kami akan menggunakannya untuk menghubungkan kode ke UI.
Sambil menahan tombol
alt , klik
Main.storyboard di
navigator proyek . Dengan demikian,
storyboard terbuka di
Asisten Editor di sebelah kanan, dan kode di sebelah kiri.
Seret lingkaran ke kiri
textLabel ke label pada
pembuat antarmuka . Dengan cara yang sama, gabungkan metode
sebelumnya ,
berikutnya, dan
keluar dengan tombol kiri, kanan, dan bawah.

Luncurkan aplikasi Anda.

Kami menggunakan ukuran sembulan default. Jika Anda ingin popup yang lebih besar atau lebih kecil, cukup ubah ukurannya di
storyboard .
Menulis kode untuk tombol
Jika Anda belum menyembunyikan
Asisten Editor , klik
Cmd-Return atau
Vew> Editor Standar> Tampilkan Editor StandarBuka
QuotesViewController.swift dan tambahkan properti berikut ke implementasi kelas:
let quotes = Quote.all var currentQuoteIndex: Int = 0 { didSet { updateQuote() } }
Properti
kutipan berisi semua kutipan, dan
currentQuoteIndex adalah indeks kutipan yang saat ini sedang ditampilkan.
CurrentQuoteIndex juga memiliki
pengamat properti untuk memperbarui konten label dengan kutipan baru ketika indeks berubah.
Sekarang tambahkan metode berikut:
override func viewDidLoad() { super.viewDidLoad() currentQuoteIndex = 0 } func updateQuote() { textLabel.stringValue = String(describing: quotes[currentQuoteIndex]) }
Saat tampilan dimuat, kami menetapkan indeks kutipan ke 0, yang pada gilirannya mengarah ke pembaruan ke antarmuka.
updateQuote () cukup memperbarui label teks untuk menampilkan penawaran. sesuai
sekarangQuoteIndex .
Akhirnya, perbarui metode ini dengan kode berikut:
@IBAction func previous(_ sender: NSButton) { currentQuoteIndex = (currentQuoteIndex - 1 + quotes.count) % quotes.count } @IBAction func next(_ sender: NSButton) { currentQuoteIndex = (currentQuoteIndex + 1) % quotes.count } @IBAction func quit(_ sender: NSButton) { NSApplication.shared.terminate(sender) }
Metode
berikutnya () dan
sebelumnya () menggilir semua kutipan.
berhenti menutup aplikasi.
Luncurkan aplikasi:

Pemantauan acara
Ada satu hal lagi yang diharapkan pengguna dari aplikasi kita - sembunyikan jendela sembul ketika pengguna mengklik di suatu tempat di luarnya. Untuk melakukan ini, kita memerlukan mekanisme yang disebut
macOS global event monitor .
Buat file Swift baru, sebut saja
EventMonitor , dan ganti kontennya dengan kode berikut:
import Cocoa public class EventMonitor { private var monitor: Any? private let mask: NSEvent.EventTypeMask private let handler: (NSEvent?) -> Void public init(mask: NSEvent.EventTypeMask, handler: @escaping (NSEvent?) -> Void) { self.mask = mask self.handler = handler } deinit { stop() } public func start() { monitor = NSEvent.addGlobalMonitorForEvents(matching: mask, handler: handler) } public func stop() { if monitor != nil { NSEvent.removeMonitor(monitor!) monitor = nil } } }
Saat menginisialisasi turunan dari kelas ini, kami memberikannya masker acara yang akan kami dengarkan (seperti penekanan tombol, gulungan roda mouse, dll.) Dan pengendali acara.
Ketika kita siap untuk mulai mendengarkan,
mulai () panggil
addGlobalMonitorForEventsMatchingMask (_: handler :) , yang mengembalikan objek yang kita simpan. Segera setelah peristiwa yang terkandung dalam topeng terjadi, sistem memanggil penangan Anda.
Untuk berhenti memantau acara,
removeMonitor () disebut in
stop () dan kami menghapus objek dengan
menyetelnya ke nil.
Yang tersisa bagi kami adalah memanggil
start () dan
stop () pada waktu yang tepat. Kelas juga memanggil
stop () pada deinitializer untuk membersihkan.
Menghubungkan Monitor Acara
Buka
AppDelegate.swift untuk terakhir kalinya dan tambahkan properti baru:
var eventMonitor: EventMonitor?
Kemudian tambahkan kode ini untuk mengonfigurasi
acara monitor di akhir
applicationDidFinishLaunching (_ :) eventMonitor = EventMonitor(mask: [.leftMouseDown, .rightMouseDown]) { [weak self] event in if let strongSelf = self, strongSelf.popover.isShown { strongSelf.closePopover(sender: event) } }
Ini akan menginformasikan aplikasi Anda ketika Anda mengklik tombol kiri atau kanan. Harap dicatat: pawang tidak akan dipanggil untuk menanggapi klik mouse di dalam aplikasi Anda. Inilah sebabnya mengapa popup tidak akan ditutup saat Anda mengklik di dalamnya.
Kami menggunakan referensi yang
lemah untuk
diri sendiri untuk menghindari bahaya dari siklus tautan yang kuat antara
AppDelegate dan
EventMonitor .
Tambahkan kode berikut di akhir metode
showPopover (_ :) :
eventMonitor?.start()
Di sini kita mulai memantau acara ketika jendela sembul muncul.
Sekarang tambahkan kode di akhir metode
closePopover (_ :) :
eventMonitor?.stop()
Di sini kita mengakhiri pemantauan ketika popup ditutup.
Aplikasi sudah siap!
Kesimpulan
Di sini Anda akan menemukan kode lengkap untuk proyek ini.
Anda telah belajar cara mengatur menu dan pop-up di aplikasi yang terletak di bilah menu. Mengapa tidak bereksperimen dengan banyak tag atau teks berformat untuk mendapatkan tanda kutip yang lebih baik? Atau hubungkan backend untuk menerima penawaran dari Internet? Atau Anda ingin menggunakan keyboard untuk bernavigasi di antara kutipan?
Tempat yang baik untuk penelitian adalah dokumentasi resmi:
NSMenu ,
NSPopover dan
NSStatusItem .