IT rekvalifikace s garancí práce. Seniorní programátoři vydělávají až 160 000 Kč/měsíc a rekvalifikace je prvním krokem. Zjisti, jak na to!
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Lekce 5 - Upomínač narozenin pro macOS - Dokončení UI a propojení

V minulé lekci, Upomínač narozenin pro macOS - Příprava UI, jsme si vytvořili hlavní okno aplikace a propojili UI komponenty s kódem.

Naše tvorba uživatelského rozhraní ještě neskončila, protože ještě potřebujeme druhé okno, kde bude uživatel moci osoby přidávat. Okno bude jednodušší, protože nám bude stačit pouze zadat jméno a pomocí specializované komponenty vybrat datum narození.

Okno pro přidání osoby

Nejdříve si tedy vytvoříme druhé okno.

Vytvoření modálního okna

Otevřeme Main.storyboard a z knihovny komponent přetáhneme Window Controller. Tímto vlastně získáme to samé, co jsme měli při vytvoření projektu, tedy okno a na něj navázaný View Controller.

Měli bychom získat zhruba něco takového:

Nové okno macOS aplikace v Xcode - macOS - Desktopové aplikace ve Swift

Pro větší přehlednost upravíme oknům titulky. Prvnímu oknu nastavíme titulek "BirthdayMinder" podle názvu projektu, tuto vlastnost Title naleznete v Attributes inspektoru.

macOS - Desktopové aplikace ve Swift

U druhého okna musíme upravit Title, ovšem u View Controlleru, protože budeme druhé okno zobrazovat modálním stylem, tedy jako dialog. Zde jako Title nastavíme "Přidat osobu".

Otevření modálního okna

Ještě, než na druhé okno nasázíme komponenty, připravíme si navigaci, abychom se na něj vůbec mohli dostat. Možností je více, my se spolehneme na jednoduché segue, podobně jako u iOS aplikací.

Segue vytvoříme v Main.storyboard pomocí tažení za držení Ctrl z View Controlleru prvního okna (toho hlavního) na View Controller druhého okna. Doporučuji tažení provádět v Document outline (tedy v seznamu komponent v levé části), abyste měli jistotu, že skutečně táhnete z View Controller.

Z nabídky vybereme možnost "Modal", která způsobí, že nové okno bude dočasně hlavním oknem aplikace a na to první nepůjde do zavření nového okna kliknout. Tím dáme uživateli najevo, že musí dokončit práci s druhým oknem, aby mohl pokračovat. Postup pro vytvoření segue si ukažme na animaci:

Postup pro vytvoření segue pro navigaci mezi okny aplikace - macOS - Desktopové aplikace ve Swift

Pokud byste chtěli mít jednoduše jen více oken a uživatele neomezovat, stačilo by zvolit možnost "Show".

Nyní potřebujeme vytvořené segue pojmenovat, protože s ním budeme pracovat v kódu. Nové segue tedy označíme a v Attributes inspektoru mu nastavíme vlastnost Identifier na "AddPersonSegue".

macOS - Desktopové aplikace ve Swift

Segue by bylo možné vytvořit tažením přímo z tlačítka "Přidat" na druhý View Controller, čímž by toto tlačítko automaticky nové okno otevřelo. Manuální spuštění segue je ale flexibilnější, proto ho použijeme.

Dostáváme se do finále a konečně si okno otevřeme. Postačí k tomu jeden řádek kódu. Otevřeme si ViewController.swift a do metody addBtn_Clicked(), která slouží k obsluze tlačítka Přidat, doplníme následující kód:

performSegue(withIdentifier: "AddPersonSegue", sender: self)

Aplikaci můžeme spustit a vyzkoušet:

Modální dialog v macOS a Swift - macOS - Desktopové aplikace ve Swift

Bohužel okno se nezobrazuje relativně vzhledem k tomu hlavnímu. To není něco, co by se dalo v Main.storyboard snadno naklikat, řešení pomocí kódu si ukážeme později.

Tvorba UI modálního okna

Prázdné okno je nám celkem k ničemu, proto jej naplníme komponentami. Budeme potřebovat textové pole pro zadání jména osoby, speciální komponentu Date Picker pro výběr data narození a tlačítko pro potvrzení.

Zavírání okna řešit nebudeme, k tomu má uživatel systémové tlačítko. Jako bonus přidáme dvojici Label komponent, aby uživatel věděl, co má zadat a vybrat. A konečně ještě přidáme obrázek, který se bude měnit podle nastaveného barevného tématu macOS, která systém podporuje od verze Mojave.

Push Button

Trochu netradičně začneme odspodu a přidáme Push Button. Pomocí AutoLayout mu nastavíme horizontální zarovnání a třeba 15 bodů od spodního okraje okna. Ještě nastavíme fixní šířku na 80 a nastavíme text "Přidat". Celkem tak máme tři constraints.

Hodí se říci, že zrovna tato tvorba UI je spíše doporučení. Jestli chcete experimentovat a máte lepší nápad, jak komponenty poskládat, tak určitě směle do toho :-)

Date Picker

Nad tlačítko přetáhneme z knihovny komponentu Date Picker. Opět ji zarovnáme horizontálně na střed a nastavíme spodní constraint na 15 bodů, tedy na 15 bodů od dříve přidaného tlačítka. Výchozí nastavení komponenty nám vyhovuje a nic není třeba měnit.

Text Field

Poslední z nutných komponent je Text Field, který bude sloužit k vyplnění jména osoby. Opět mu nastavíme zarovnání na horizontální střed, 15 bodů od spodní hrany a fixní šířku 90.

Aktuální UI vypadá zhruba takto:

Modální okno pro zadání nové osoby ve Swift - macOS - Desktopové aplikace ve Swift

Labely

Přidáme Label komponenty, abychom uživateli připomněli, co má zadat. Komponentám nastavíme velikost fontu System Small a zarovnáme vertikálně s komponentou, ke které patří.

Zarovnání labelu s komponentou v macOS aplikaci v Xcode - macOS - Desktopové aplikace ve Swift

Potom již bude stačit nastavit jen odsazení z pravé strany. Já jsem zvolil hodnotu 3. To samé provedeme pro Label patřící k Date Picker.

Obrázky pro světlé i tmavé téma macOS

Jak asi víte, macOS od verze Mojave nabízí možnost zapnout tmavé téma. A pokud si nenastavíme vlastní barvy komponent, bude aplikace vypadat dobře v obou případech. Na té naší to můžeme vyzkoušet. Stačí v Xcode přepnout "View as: Dark Appearance" na světlé téma.

Aplikace pro macOS ve světlém tématu - macOS - Desktopové aplikace ve Swift

My chceme naše okno pro přidání nové osoby doplnit obrázkem. Protože se jedná o jednobarevný obrázek, tak chceme, aby aplikace pro každé téma použila jiný. To se dá velmi snadno zařídit. Obě varianty obrázku najdete ve zdrojových souborech k této lekci.

Image Set

V první řadě si otevřeme Assets.xcassets a pomocí tlačítka + dole přidáme New Image Set. Ten z výchozího Image přejmenujeme na Person. Otevřeme si Attributes inspektor tohoto obrázku a najdeme položku Apperances. Ta je ve výchozím stavu nastavena na None. My vybereme možnost Any, Dark.

Hned můžeme vidět, že se změnily "kolonky" pro obrázky a máme možnost přidat obrázek pro tmavé téma:

Kolonky pro přidání obrázků - macOS - Desktopové aplikace ve Swift

Zbývá přesunout obrázky:

Obrázek v kolonkách pro přidání obrázků - macOS - Desktopové aplikace ve Swift

A to je vše! Nyní již stačí tento obrázek použít a systém automaticky vybere správný podle nastaveného tématu.

Vrátíme se do Main.storyboard a dokončíme druhé okno.

Image View

Přidáme komponentu Image View pro zobrazování obrázků a rovnou ji jako obrázek nastavíme Person, který jsme si připravili. Stačí nastavit AutoLayout a bude hotovo.

Image View tradičně zarovnáme horizontálně na střed, nastavíme vzdálenost 20 od horní hrany, minimálně 15 od spodní hrany (tedy od textového pole) a maximální výšku na 150. Opět platí, že se jedná o návrhy a můžete samozřejmě experimentovat.

Constraints pro obrázek vypadají takto:

Constraints pro macOS obrázek v Xcode - macOS - Desktopové aplikace ve Swift

A hotové druhé okno aplikace:

Dokončené modální okno - macOS - Desktopové aplikace ve Swift

Můžeme také vyzkoušet, že fungují správné obrázky:

Přepínání motivu macOS aplikace v Xcode - macOS - Desktopové aplikace ve Swift

Propojení UI a kódu

Uživatelské rozhraní druhého okna je hotové, nyní ho propojíme s kódem. Potřebujeme @IBOutlet pro Text Field a Date Picker. Pro tlačítko Přidat vytvoříme @IBAction. Jedná se o opakování, v AddPersonViewController bychom měli mít:

@IBOutlet var nameTextField: NSTextField!
@IBOutlet var datePicker: NSDatePicker!

@IBAction func confirmBtn_Clicked(_ sender: NSButton) {
}

Komunikace mezi okny

Na závěr této lekce si obě okna propojíme, abychom v té další mohli pohodlně začít přidávat osoby.

Prvním krokem je vytvoření View Controlleru pro druhé okno. Nezapomeňte při vytváření souboru vybrat Cocoa Class a na další obrazovce nastavit jako subclass NSViewController. Šlo by to i ručně, ale tento způsob je rychlejší. Jako název zvolíme AddPersonViewController. Před potvrzením zkontrolujte, že není zaškrtnuta možnost "Also create XIB file for user interface". To nechceme.

Nyní musíme do Main.storyboard a nastavit nově vytvořenou třídu druhému View Controlleru v jeho Identity inspektoru:

Identity inspector druhého View Controlleru - macOS - Desktopové aplikace ve Swift

Vrátíme se do AddPersonViewController a přidáme si následující vlastnost:

weak var delegateVC: ViewController!

Možností, jak komunikovat mezi okny, je nespočet. My si ukážeme jednoduchou z nich, inspirovanou návrhovým vzorem delegát. Pomocí této vlastnosti získáme přístup k View Controlleru hlavního okna a budeme ho moci informovat o tom, že uživatel vyplnil údaje a chce přidat osobu. Samozřejmě bychom zde mohli využít protokol, ale my tvoříme jednoduchou aplikaci.

Vlastnost musí být weak, aby mezi oběma View Controllery nevznikl retain cycle, kdy se objekty vlastní navzájem a nemůže proto dojít k jejich dealokaci.

Vrátíme se do ViewController a přetížíme metodu prepare(), která je automaticky zavolána těsně předtím, než proběhne segue.

Její kostra vypadá takto:

override func prepare(for segue: NSStoryboardSegue, sender: Any?) {

}

Zde zjistíme, jestli jde o "AddPersonSegue" a pokud ano, tak z něj získáme cílový View Controller, což bude právě náš AddPersonViewController a nastavíme mu vlastnost delegateVC, čímž oba controllery propojíme:

override func prepare(for segue: NSStoryboardSegue, sender: Any?) {
        if segue.identifier == "AddPersonSegue" {
            let addPersonVC = segue.destinationController as! AddPersonViewController
            addPersonVC.delegateVC = self
        }
}

Víme, jakého typu má být destinationController, takže použití as! je v pořádku a dává smysl. Pak už jen nastavíme vlastnost delegateVC.

Našemu ViewController ještě přidáme následující metodu, abychom mohli propojení snadno otestovat:

func addPerson(name: String) {
        print("Adding: \(name)")
}

Zbývá zamířit do AddPersonViewController a doplnit provizorní kód tlačítka Přidat:

@IBAction func confirmBtn_Clicked(_ sender: NSButton) {
        delegateVC.addPerson(name: "Test")
}

Aplikaci můžete zapnout a zkontrolovat výpis konzole v Xcode. Pomocí addPerson() metody později budeme osoby přidávat již doopravdy.

Oprava pozice druhého okna

Na úplný závěr si opravíme startovní pozici druhého okna, jak máme slíbeno. Využijeme na to přetíženou metodu viewDidAppear(). Nemůžeme použít viewDidLoad(), protože v tomto stádiu ještě není plně inicializované okno (i když k tomu název svádí) a nedostali bychom se k němu.

Pro jistotu nezapomeneme také zavolat super.viewDidAppear().

Základní kostra metody v AddPersonViewController tedy vypadá takto:

override func viewDidAppear() {
        super.viewDidAppear()
}

Co vlastně potřebujeme udělat?

Nejdříve získat pozici prvního okna, získat rámeček druhého okna (kvůli rozměrům), vypočítat korektní pozici a nastavit ji druhému oknu. Celá metoda bude vypadat takto:

override func viewDidAppear() {
        super.viewDidAppear()
        let mainWindowFrame = delegateVC.view.window!.frame
        let addPersonFrame = view.window!.frame
        let yPosition = mainWindowFrame.midY - addPersonFrame.height / 2
        let xPosition = mainWindowFrame.midX - addPersonFrame.width / 2
        view.window!.setFrameOrigin(CGPoint(x: xPosition, y: yPosition))
}

macOS počítá pozice od levého dolního rohu, zatímco iOS (v UIKit) od levého horního.

Pro korektní pozici tedy zjistíme střední Y a X souřadnice a od každé odečteme polovinu šířky respektive výšky, čímž získáme korektní pozici pro druhé okno.

Můžeme vyzkoušet:

Otevření dialogového okna na střed v macOS a Swift - macOS - Desktopové aplikace ve Swift

Tímto jsme úspěšně dokončili celé UI, propojili okna mezi sebou a také jsme vyřešili pozicování druhého okna.

V následující lekci, Upomínač narozenin pro macOS - Table View a práce s datem, zprovozníme přidávání osob a oživíme Table View.


 

Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.

Stáhnout

Stažením následujícího souboru souhlasíš s licenčními podmínkami

Staženo 12x (114.77 kB)
Aplikace je včetně zdrojových kódů v jazyce Swift

 

Předchozí článek
Upomínač narozenin pro macOS - Příprava UI
Všechny články v sekci
macOS - Desktopové aplikace ve Swift
Přeskočit článek
(nedoporučujeme)
Upomínač narozenin pro macOS - Table View a práce s datem
Článek pro vás napsal Filip Němeček
Avatar
Uživatelské hodnocení:
Ještě nikdo nehodnotil, buď první!
Autor se věnuje vývoji iOS aplikací (občas macOS)
Aktivity