La tua prima applicazione WatchKit l'interazione dell'utente

Nel precedente tutorial, abbiamo esplorato i fondamenti dello sviluppo di WatchKit. Abbiamo creato un progetto in Xcode, aggiunto un'applicazione WatchKit e creato un'interfaccia utente di base.

L'interfaccia utente della nostra applicazione WatchKit visualizza attualmente dati statici. A meno che non si viva nel deserto, non è molto utile per un'applicazione meteorologica. In questo tutorial, inseriremo l'interfaccia utente con i dati e creeremo alcune azioni.

1. Aggiornamento dell'interfaccia utente

Passaggio 1: sostituzione WKInterfaceDate

Prima di popolare l'interfaccia utente con i dati, dobbiamo apportare una piccola modifica. Nel precedente tutorial, abbiamo aggiunto un WKInterfaceDate istanza al gruppo in basso per visualizzare l'ora e la data correnti. Sarebbe più utile, tuttavia, visualizzare l'ora e la data dei dati che stiamo visualizzando. La ragione di questo cambiamento diventerà chiara in pochi istanti.

Aperto Interface.storyboard, Rimuovi il WKInterfaceDate istanza nel gruppo in basso e sostituirlo con a WKInterfaceLabel esempio. Imposta l'etichetta Larghezza attribuire a Relativo al contenitore e l'etichetta Allineamento allineato a destra.

Passaggio 2: aggiunta di punti vendita

Per aggiornare l'interfaccia utente con i dati dinamici, dobbiamo creare alcuni punti vendita nel InterfaceController classe. Apri lo storyboard nell'editor principale e InterfaceController.swift nel Assistente editore sulla destra. Seleziona l'etichetta in alto nel primo gruppo e Control-trascinamento dall'etichetta al InterfaceController classe per creare uno sbocco. Dai un nome alla presa locationLabel.

Ripeti questi passaggi per le altre etichette, nominandole temperatureLabel e dateLabel rispettivamente. Questo è ciò che InterfaceController la classe dovrebbe assomigliare quando hai finito.

import WatchKit import Foundation class InterfaceController: WKInterfaceController @IBOutlet weak var dateLabel: WKInterfaceLabel! @IBOutlet weak var locationLabel: WKInterfaceLabel! @IBOutlet weak var temperatureLabel: WKInterfaceLabel! override func awakeWithContext (context: AnyObject?) super.awakeWithContext (context) override func willActivate () // Questo metodo viene chiamato quando il controller di visualizzazione watch sta per essere visibile all'utente super.willActivate () override func didDeactivate ( ) // Questo metodo viene chiamato quando il controller di visualizzazione dell'orologio non è più visibile super.didDeactivate ()

Ora potrebbe essere un buon momento per dare un'occhiata più da vicino all'implementazione del InterfaceController classe. Nel precedente tutorial, l'ho menzionato InterfaceController eredita da WKInterfaceController. A prima vista, può sembrare che a WKInterfaceController l'istanza si comporta come a UIViewController esempio, ma abbiamo anche imparato nel tutorial precedente che ci sono alcune differenze chiave.

Per aiutarci, Xcode ha popolato il InterfaceController classe con tre metodi sovrascritti. È importante capire quando viene invocato ciascun metodo e per cosa può o deve essere utilizzato.

awakeWithContect (_ :)

Nel awakeWithContext (_ :) metodo, si imposta e si inizializza il controller dell'interfaccia. Forse ti starai chiedendo in che modo differisce da dentro metodo. Il awakeWithContext (_ :) il metodo viene richiamato dopo l'inizializzazione del controller dell'interfaccia. Il metodo accetta un parametro, un oggetto di contesto che consente ai controller di interfaccia di passare le informazioni l'un l'altro. Questo è l'approccio raccomandato per passare informazioni attraverso scene, cioè controller di interfaccia.

willActivate

Il willActivate il metodo è simile al viewWillAppear (_ :) metodo del UIViewController classe. Il willActivate il metodo viene richiamato prima che l'interfaccia utente del controller di interfaccia sia presentata all'utente. È ideale per modificare l'interfaccia utente prima che venga presentata all'utente.

didDeactivate

Il didDeactivate metodo è la controparte del willActivate metodo e viene richiamato quando la scena del controller dell'interfaccia è stata rimossa. Qualsiasi codice di pulizia va in questo metodo. Questo metodo è simile al viewDidDisappear (_ :) metodo trovato nel UIViewController classe.

Tenendo presente quanto sopra, possiamo iniziare a caricare i dati e aggiornare l'interfaccia utente della nostra applicazione WatchKit. Iniziamo con il caricamento dei dati meteo.

2. Caricamento dei dati meteorologici

Migliori pratiche

Potresti pensare che il prossimo passo riguardi una chiamata API a un servizio meteo, ma non è questo il caso. Se stessimo costruendo un'applicazione iOS, avresti ragione. Tuttavia, stiamo creando un'applicazione WatchKit.

Non è consigliabile effettuare chiamate API complesse per recuperare i dati per popolare l'interfaccia utente di un'applicazione WatchKit. Anche se Apple non menziona esplicitamente questo nella documentazione, un ingegnere Apple ha menzionato questa best practice non scritta nei forum degli sviluppatori Apple.

L'applicazione WatchKit fa parte di un'applicazione iOS ed è l'applicazione iOS che è responsabile del recupero dei dati da un back-end remoto. Ci sono diversi approcci che possiamo fare per fare ciò, mentre il recupero dei dati è una buona scelta. In questo tutorial, tuttavia, non ci concentreremo su questo aspetto.

Al contrario, aggiungeremo dati fittizi al pacchetto dell'estensione WatchKit e caricarli nel file awakeWithContext (_ :) metodo che abbiamo discusso in precedenza.

Crea un file vuoto selezionando Nuovo> File ...  dal File menu. Scegliere Vuoto dal iOS> Altro sezione e nominare il file weather.json. Ricontrolla che stai aggiungendo il file al Estensione RainDrop WatchKit. Non trascurare questo piccolo ma importante dettaglio. Compila il file con i seguenti dati.

"locations": ["location": "Cupertino", "temperatura": 24, "timestamp": 1427429751, "location": "London", "temperature": 11, "timestamp": 1427429751, "location": "Paris", "temperature": 9, "timestamp": 1427429751, "location": "Brussels", "temperature": 11, "timestamp": 1427429751]

Condivisione dei dati

La condivisione dei dati tra l'applicazione iOS e l'applicazione WatchKit è un argomento importante. Tuttavia, questo tutorial si concentra su come far funzionare la tua prima applicazione WatchKit. In un futuro tutorial, mi concentrerò sulla condivisione dei dati tra un'applicazione iOS e un'applicazione WatchKit.

Anche se non copriremo la condivisione dei dati in questo tutorial, è importante sapere che l'applicazione iOS e l'estensione WatchKit non condividono una sandbox. Entrambi gli obiettivi hanno una propria sandbox e questo è ciò che rende i dati di condivisione meno banali di quanto sembri.

Per condividere i dati tra iOS e l'applicazione WatchKit, è necessario sfruttare i gruppi di app. Ma questo è un argomento per un futuro tutorial.

Passaggio 1: aggiunta di SwiftyJSON

Swift è un ottimo linguaggio, ma alcuni compiti sono più semplici in Objective-C che in Swift. Gestire JSON, ad esempio, è una di queste attività. Per semplificare questo compito, ho scelto di sfruttare la famosa libreria SwiftyJSON.

Scarica il repository da GitHub, decomprimi l'archivio e aggiungi SwiftyJSON.swift al Estensione RainDrop WatchKit gruppo. Questo file si trova nel fonte cartella dell'archivio. Ricontrolla quello SwiftyJSON.swift è aggiunto il Estensione RainDrop WatchKit bersaglio.

Passaggio 2: implementazione WeatherData

Per semplificare il lavoro con i dati meteo memorizzati in weather.json, creeremo una struttura chiamata WeatherData. Selezionare Nuovo> File ... a partire dal il File menu, scegliere Swift File dal iOS> Origine sezione e nominare il file WeatherData. Assicurati che il file sia aggiunto al Estensione RainDrop WatchKit bersaglio.

L'implementazione del WeatherData la struttura è breve e semplice La struttura definisce tre proprietà costanti, Data, Posizione, e temperatura.

import Foundation struct WeatherData let date: NSDate let location: String let temperature: Double

Perché il valore della temperatura di weather.json è in Celcius, implementiamo anche una proprietà calcolata fahrenheit per una facile conversione tra Celcius e Fahrenheit.

var fahrentheit: Double temperatura di ritorno * (9/5) + 32

Definiamo anche due metodi di supporto toCelciusString e toFahrenheitString per rendere più facile la formattazione dei valori di temperatura. Non ami l'interpolazione a corda di Swift?

func toCelciusString () -> String return "\ (temperatura) ° C" func aFahrenheitString () -> String return "\ (fahrentheit) ° F"

Come ho detto, l'implementazione del WeatherData la struttura è breve e semplice Questo è l'aspetto che dovrebbe avere l'implementazione.

import Foundation struct WeatherData let date: NSDate let location: String let temperatura: Double var fahrentheit: Double temperatura di ritorno * (9/5) + 32 func toCelciusString () -> String return "\ (temperatura) ° C"  func toFahrenheitString () -> String return "\ (fahrentheit) ° F"

Passaggio 3: caricamento dei dati

Prima di caricare i dati da weather.json, dobbiamo dichiarare una proprietà per la memorizzazione dei dati meteorologici. La proprietà, weatherData, è di tipo [WeatherData] e conterrà il contenuto di weather.json come esempi del WeatherData struttura.

var weatherData: [WeatherData] = []

Per facilità d'uso, dichiariamo anche una proprietà calcolata, tempo metereologico, che ci dà accesso al primo elemento del weatherData array. Sono i dati di questo WeatherData istanza che mostreremo nel controller dell'interfaccia. Riuscite a indovinare perché dobbiamo dichiarare il tempo metereologico proprietà come facoltativo?

var weather: WeatherData? return weatherData.first

Carichiamo i dati da weather.json nel awakeWithContext (_ :) metodo. Per mantenere l'implementazione pulita, invochiamo un metodo di supporto denominato loadWeatherData.

override func awakeWithContext (context: AnyObject?) super.awakeWithContext (context) // Carica dati meteo loadWeatherData ()

L'implementazione di loadWeatherData è probabilmente lo snippet di codice più scoraggiante che vedremo in questo tutorial. Come ho detto, l'analisi di JSON non è banale in Swift. Fortunatamente, SwiftyJSON fa la maggior parte del lavoro pesante per noi.

func loadWeatherData () let path = NSBundle.mainBundle (). pathForResource ("weather", ofType: "json") se lasciato path = path let data = NSData (contentsOfFile: path) se let data = data let weatherData = JSON (data: data) lascia location = weatherData ["locations"]. Array se let locations = locations per posizione in locations let timestamp = location ["timestamp"]. let date = NSDate (timeIntervalSinceReferenceDate: timestamp) lascia model = WeatherData (data: date, location: location ["posizione"]. stringa !, temperatura: posizione ["temperatura"] .doppia!) self.weatherData.append (modello) 

Otteniamo il percorso per weather.json e carica il suo contenuto come un NSData oggetto. Usiamo SwiftyJSON per analizzare il JSON, passando in NSData oggetto. Otteniamo un riferimento alla matrice per la chiave posizioni e loop su ogni posizione.

Normalizziamo i dati meteorologici convertendo il timestamp in un NSDate istanza e inizializzare a WeatherData oggetto. Infine, aggiungiamo il WeatherData oggetto al weatherData schieramento.

Spero tu accetti che l'implementazione non è poi così difficile. Poiché Swift ci obbliga a fare un numero di controlli, l'implementazione sembra più complessa di quanto non sia in realtà.

3. Compilazione dell'interfaccia utente

Con i dati meteo pronti all'uso, è ora di aggiornare l'interfaccia utente. Come ho spiegato in precedenza, l'aggiornamento dell'interfaccia utente deve avvenire nel willActivate metodo. Diamo un'occhiata all'implementazione di questo metodo.

override func willActivate () // Questo metodo viene chiamato quando il controller di visualizzazione watch sta per essere visibile all'utente super.willActivate () se let weather = self.weather locationLabel.setText (weather.location) // Aggiorna etichetta di temperatura self .updateTemperatureLabel () // Aggiorna etichetta data self.updateDateLabel ()

Dopo aver invocato il willActivate metodo della superclasse, scartiamo il valore memorizzato nel file tempo metereologico proprietà. Per aggiornare l'etichetta della posizione, invochiamo setText, passando il valore memorizzato nel Posizione proprietà del tempo metereologico oggetto. Per aggiornare le etichette di temperatura e data, invochiamo due metodi di supporto. Preferisco mantenere il willActivate metodo breve e conciso, e, cosa più importante, non mi piace ripetere me stesso.

Prima di esaminare questi metodi di supporto, è necessario sapere se la temperatura deve essere visualizzata in Celsius o Fahrenheit. Per risolvere questo problema, dichiarare una proprietà, Celsius, di tipo Bool e impostare il suo valore iniziale su vero.

var celcius: Bool = true

L'implementazione di updateTemperatureLabel è facile da capire. Scartiamo il valore memorizzato in modo sicuro tempo metereologico e aggiornare l'etichetta della temperatura in base al valore di Celsius. Come puoi vedere, i due metodi di supporto di WeatherData la struttura che abbiamo creato in precedenza è utile.

func updateTemperatureLabel () if let weather = self.weather if self.celcius temperatureLabel.setText (weather.toCelciusString ()) else temperatureLabel.setText (weather.toFahrenheitString ())

L'implementazione di updateDateLabel non è nemmeno difficile. Inizializziamo un NSDateFormatter esempio, impostalo formato data proprietà e convertire la data del tempo metereologico oggetto chiamando stringFromDate (_ :) sul dateFormatter oggetto. Questo valore viene utilizzato per aggiornare l'etichetta della data.

func updateDateLabel () var data: NSDate = NSDate () // Initialize Date Formatter let dateFormattter = NSDateFormatter () // Configure Date Formatter dateFormattter.dateFormat = "d / MM HH: mm" se let weather = self.weather date = weather.date // Aggiorna data Etichetta dateLabel.setText (dateFormattter.stringFromDate (date))

Costruisci ed esegui l'applicazione per vedere il risultato. L'interfaccia utente dovrebbe ora essere popolata con i dati da weather.json.

4. Passare a Fahrenheit

Questo sembra buono. Ma non sarebbe bello se avessimo aggiunto il supporto sia a Celcius che a Fahrenheit? Questo è facile da fare poiché abbiamo già posto la maggior parte delle basi.

Se la forza dell'utente tocca l'interfaccia utente di un controller dell'interfaccia utente, viene visualizzato un menu. Naturalmente, funziona solo se è disponibile un menu. Vediamo come funziona.

Aperto Interface.storyboard e aggiungere un menu al Controller di interfaccia nel Struttura del documento sulla sinistra. Per impostazione predefinita, un menu ha una voce di menu. Abbiamo bisogno di due voci di menu, quindi aggiungi un'altra voce di menu al menu.

Si noti che il menu e le relative voci di menu non sono visibili nell'interfaccia utente. Questo non è un problema poiché non possiamo configurare il layout del menu. Quello che possiamo cambiare sono il testo di una voce di menu e la sua immagine. Capirai meglio cosa significa quando presentiamo il menu.

Seleziona la voce del menu in alto, apri il Ispettore degli attributi, impostato TitoloCelsius, e ImmagineAccettare. Seleziona la voce del menu in basso e imposta TitoloFahrenheit e ImmagineAccettare.

Avanti, aperto InterfaceController.swift nel Assistente editore sulla destra. Control-trascinamento dalla voce del menu in alto a InterfaceController.swift e creare un'azione chiamata toCelcius. Ripeti questo passaggio per la voce del menu in basso, creando un'azione chiamata toFahrenheit.

L'implementazione di queste azioni è breve. Nel toCelcius, controlliamo se il Celsius la proprietà è impostata su falso, e, se lo è, impostiamo la proprietà su vero. Nel toFahrenheit, controlliamo se il Celsius la proprietà è impostata su vero, e, se lo è, impostiamo la proprietà su falso.

@IBAction func toCelcius () if! Self.celcius self.celcius = true @IBAction func aFahrenheit () if self.celcius self.celcius = false

Se il valore di Celsius modifiche, abbiamo bisogno di aggiornare l'interfaccia utente. Quale modo migliore per realizzare questo implementando un osservatore di proprietà sul Celsius proprietà. Dobbiamo solo implementare a didSet osservatore di proprietà.

var celcius: Bool = true didSet if celcius! = oldValue updateTemperatureLabel ()

L'unico dettaglio degno di nota è che l'interfaccia utente viene aggiornata solo se il valore di Celsius ha fatto cambiare. L'aggiornamento dell'interfaccia utente è semplice come la chiamata updateTemperatureLabel. Costruisci ed esegui l'applicazione WatchKit in iOS Simulator per testare il menu.

Vale la pena ricordare che il simulatore iOS imita la reattività di un dispositivo fisico. Cosa significa? Ricorda che l'estensione WatchKit gira su un iPhone mentre l'applicazione WatchKit gira su un Apple Watch. Quando l'utente tocca una voce di menu, l'evento tattile viene inviato tramite una connessione Bluetooth all'iPhone. L'estensione WatchKit elabora l'evento e invia eventuali aggiornamenti indietro all'Apple Watch. Questa comunicazione è piuttosto veloce, ma non è veloce come se l'estensione e l'applicazione dovessero essere eseguite sullo stesso dispositivo. Questo breve ritardo è imitato da iOS Simulator per aiutare gli sviluppatori a farsi un'idea delle prestazioni.

Conclusione

Dopo aver spostato la testa sull'architettura di un'applicazione WatchKit, diventa molto più facile comprendere le possibilità e i limiti della prima generazione di applicazioni WatchKit. In questo tutorial, abbiamo coperto solo gli elementi essenziali dello sviluppo di WatchKit. C'è molto altro da scoprire ed esplorare. Rimanete sintonizzati.