Uw eerste WatchKit-toepassing gebruikersinteractie

In de vorige zelfstudie hebben we de basisbeginselen van de ontwikkeling van WatchKit onderzocht. We hebben een project in Xcode gemaakt, een WatchKit-applicatie toegevoegd en een eenvoudige gebruikersinterface gemaakt.

De gebruikersinterface van onze WatchKit-applicatie geeft momenteel statische gegevens weer. Tenzij je in de woestijn woont, is dat niet erg handig voor een weerapplicatie. In deze zelfstudie gaan we de gebruikersinterface vullen met gegevens en een paar acties uitvoeren.

1. De gebruikersinterface bijwerken

Stap 1: Vervangen WKInterfaceDate

Voordat we de gebruikersinterface met gegevens vullen, moeten we een kleine wijziging aanbrengen. In de vorige zelfstudie hebben we een toegevoegd WKInterfaceDate bijvoorbeeld naar de onderste groep om de huidige tijd en datum weer te geven. Het zou echter nuttiger zijn om de tijd en datum weer te geven van de gegevens die we weergeven. De reden voor deze verandering zal in enkele ogenblikken duidelijk worden.

Open Interface.storyboard, Verwijder de WKInterfaceDate bijvoorbeeld in de onderste groep en vervang deze door een WKInterfaceLabel aanleg. Stel de labels in Breedte attribuut aan Ten opzichte van Container en de labels opstelling naar rechts uitgelijnd.

Stap 2: Outlets toevoegen

Om de gebruikersinterface met dynamische gegevens bij te werken, moeten we een paar verkooppunten in de InterfaceController klasse. Open het storyboard in de hoofdeditor en InterfaceController.swift in de Assistent redacteur aan de rechterkant. Selecteer het bovenste label in de eerste groep en Controle-Drag van het label naar de InterfaceController klasse om een ​​outlet te creëren. Geef de outlet een naam locationLabel.

Herhaal deze stappen voor de andere labels, noem ze temperatureLabel en dateLabel respectievelijk. Dit is wat de InterfaceController klasse zou eruit moeten zien als je klaar bent.

importeer WatchKit import Foundation-klasse 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 () // Deze methode wordt aangeroepen wanneer de watchview-controller zichtbaar wordt voor de gebruiker super.willActivate () negeer func didDeactivate ( ) // Deze methode wordt aangeroepen wanneer de weergavecontroller niet meer zichtbaar is super.didDeactivate ()

Het is misschien een goed moment om de implementatie van het InterfaceController klasse. In de vorige tutorial heb ik dat genoemd InterfaceController erft van WKInterfaceController. Op het eerste gezicht lijkt het misschien een WKInterfaceController instantie gedraagt ​​zich als een UIViewController Zo hebben we in de vorige tutorial ook geleerd dat er een aantal belangrijke verschillen zijn.

Om ons te helpen heeft Xcode de InterfaceController klasse met drie overschreven methoden. Het is belangrijk om te weten wanneer elke methode wordt aangeroepen en waarvoor deze kan of moet worden gebruikt.

awakeWithContect (_ :)

In de awakeWithContext (_ :) methode, stelt u de interfacecontroller in en initialiseert u deze. Je vraagt ​​je misschien af ​​hoe het verschilt van het in het methode. De awakeWithContext (_ :) methode wordt aangeroepen nadat de interface-controller is geïnitialiseerd. De methode accepteert één parameter, een contextobject waarmee interfacecontrollers informatie aan elkaar kunnen doorgeven. Dit is de aanbevolen aanpak voor het doorgeven van informatie over scènes, dat wil zeggen, interfacecontrollers.

willActivate

De willActivate methode lijkt op de viewWillAppear (_ :) methode van de UIViewController klasse. De willActivate methode wordt aangeroepen voordat de gebruikersinterface van de interfacecontroller aan de gebruiker wordt gepresenteerd. Het is ideaal om de gebruikersinterface aan te passen voordat deze aan de gebruiker wordt gepresenteerd.

didDeactivate

De didDeactivate methode is de tegenhanger van de willActivate methode en wordt aangeroepen wanneer de scène van de interface-controller is verwijderd. Elke opschoningscode gaat naar deze methode. Deze methode is vergelijkbaar met de viewDidDisappear (_ :) methode gevonden in de UIViewController klasse.

Met het bovenstaande in gedachten, kunnen we beginnen met het laden van gegevens en het updaten van de gebruikersinterface van onze WatchKit-applicatie. Laten we beginnen met het laden van weergegevens.

2. Weergegevens laden

Beste praktijken

U denkt misschien dat de volgende stap een API-aanroep naar een weerservice betreft, maar dat is niet het geval. Als we een iOS-applicatie aan het bouwen waren, zou je gelijk hebben. We maken echter een WatchKit-toepassing.

Het wordt niet aanbevolen om complexe API-aanroepen te maken om gegevens op te halen om de gebruikersinterface van een WatchKit-toepassing te vullen. Hoewel Apple dit niet expliciet vermeldt in de documentatie, noemde een ingenieur van Apple deze ongeschreven best practice in Apple's ontwikkelaarsforums.

De WatchKit-applicatie maakt deel uit van een iOS-applicatie en het is de iOS-applicatie die verantwoordelijk is voor het ophalen van gegevens van een externe backend. Er zijn verschillende manieren om dit te doen, achtergrond ophalen is een goede keuze. In deze zelfstudie concentreren we ons echter niet op dat aspect.

In plaats daarvan voegen we dummy-gegevens toe aan de bundel van de WatchKit-extensie en laden deze in de awakeWithContext (_ :) methode die we eerder hebben besproken.

Maak een leeg bestand door te selecteren Nieuw> Bestand ...  van de het dossier menu. Kiezen Leeg van de iOS> Anders sectie en noem het bestand weather.json. Controleer nogmaals of u het bestand aan de RainDrop WatchKit-extensie. Laat dit kleine maar belangrijke detail niet over het hoofd. Vul het bestand met de volgende gegevens in.

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

Gegevens delen

Het delen van gegevens tussen de iOS-applicatie en de WatchKit-applicatie is een belangrijk onderwerp. Deze zelfstudie is echter gericht op het operationeel maken van uw eerste WatchKit-toepassing. In een toekomstige zelfstudie zal ik me richten op het delen van gegevens tussen een iOS- en een WatchKit-toepassing.

Hoewel we het delen van gegevens in deze tutorial niet zullen behandelen, is het belangrijk om te weten dat de iOS-applicatie en de WatchKit-extensie geen sandbox delen. Beide doelen hebben een eigen sandbox en dat maakt het delen van gegevens minder triviaal dan het lijkt.

Als u gegevens wilt delen tussen de iOS- en de WatchKit-app, moet u gebruikmaken van app-groepen. Maar dat is een onderwerp voor een toekomstige zelfstudie.

Stap 1: SwiftyJSON toevoegen

Swift is een geweldige taal, maar sommige taken zijn eenvoudiger in Objective-C dan in Swift. JSON behandelen is bijvoorbeeld zo'n taak. Om deze taak eenvoudiger te maken, heb ik ervoor gekozen om gebruik te maken van de populaire SwiftyJSON-bibliotheek.

Download de repository van GitHub, pak het archief uit en voeg toe SwiftyJSON.swift naar de RainDrop WatchKit-extensie groep. Dit bestand bevindt zich in de Bron map van het archief. Controleer dat eens SwiftyJSON.swift is de RainDrop WatchKit-extensie doelwit.

Stap 2: Implementeren WeatherData

Om het gemakkelijker te maken om te werken met de weergegevens opgeslagen in weather.json, we gaan een structuur met de naam maken WeatherData. kiezen Nieuw> Bestand ... van de het dossier menu, kies Swift-bestand van de iOS> Bron sectie en geef het bestand een naam WeatherData. Zorg ervoor dat het bestand is toegevoegd aan de RainDrop WatchKit-extensie doelwit.

De implementatie van de WeatherData structuur is kort en eenvoudig. De structuur definieert drie constante eigenschappen, datum, plaats, en temperatuur-.

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

Omdat de temperatuurwaarde van weather.json is in Celcius, we implementeren ook een berekend eigendom Fahrenheit voor eenvoudige conversie tussen Celcius en Fahrenheit.

var fahrentheit: Dubbele retourtemperatuur * (9/5) + 32

We definiëren ook twee hulpmethoden toCelciusString en toFahrenheitString om opmaak temperatuurwaarden gemakkelijker te maken. Hou je niet van Swift's snarige interpolatie?

func toCelciusString () -> String return "\ (temperature) ° C" func toFahrenheitString () -> String return "\ (fahrentheit) ° F"

Zoals ik al zei, de implementatie van de WeatherData structuur is kort en eenvoudig. Dit is hoe de implementatie eruit zou moeten zien.

import Stichting struct WeatherData let date: NSDate verhuurt locatie: String laat temperatuur: Double var fahrentheit: Double retourtemperatuur * (9/5) + 32 func toCelciusString () -> String return "\ (temperatuur) ° C"  func toFahrenheitString () -> String return "\ (fahrentheit) ° F"

Stap 3: Gegevens laden

Voordat we de gegevens laden weather.json, we moeten een property declareren voor het opslaan van de weergegevens. Het eigendom, weatherData, is van het type [WeatherData] en bevat de inhoud van weather.json als exemplaren van de WeatherData structuur.

var weatherData: [WeatherData] = []

Voor gebruiksgemak geven we ook een berekende eigenschap aan, weer, dat geeft ons toegang tot het eerste item van de weatherData matrix. Het zijn de gegevens hiervan WeatherData bijvoorbeeld dat we zullen weergeven in de interface-controller. Kun je raden waarom we het moeten declareren weer eigendom als een optionele?

var weer: WeatherData? return weatherData.first

We laden de gegevens van weather.json in de awakeWithContext (_ :) methode. Om de implementatie schoon te houden, roepen we een helper-methode genaamd aan loadWeatherData.

override func awakeWithContext (context: AnyObject?) super.awakeWithContext (context) // Load Weather Data loadWeatherData ()

De implementatie van loadWeatherData is waarschijnlijk het meest ontmoedigende codefragment dat we in deze zelfstudie zullen zien. Zoals ik al zei, is het parseren van JSON niet triviaal in Swift. Gelukkig doet SwiftyJSON het grootste deel van het zware werk voor ons.

func loadWeatherData () let path = NSBundle.mainBundle (). pathForResource ("weather", ofType: "json") if let path = path let data = NSData (contentsOfFile: path) if let data = data let weatherData = JSON (data: data) laat locaties = weatherData ["locaties"]. Array als let locaties = locaties voor locatie op locaties let timestamp = location ["timestamp"]. Double! let date = NSDate (timeIntervalSinceReferenceDate: timestamp) laat model = WeatherData (datum: datum, locatie: locatie ["locatie"]. string !, temperatuur: locatie ["temperatuur"]. dubbel!) self.weatherData.append (model) 

We krijgen het pad naar weather.json en laad de inhoud ervan als een NSData voorwerp. We gebruiken SwiftyJSON om de JSON te analyseren, door te geven in de NSData voorwerp. We krijgen een verwijzing naar de array voor de sleutel locaties en loop over elke locatie.

We normaliseren de weergegevens door de tijdstempel om te zetten naar een NSDate instance en initialiseer a WeatherData voorwerp. Ten slotte voegen we de WeatherData bezwaar tegen de weatherData rangschikking.

Ik hoop dat u het ermee eens bent dat de implementatie niet zo moeilijk is. Omdat Swift ons dwingt een aantal controles uit te voeren, ziet de implementatie er complexer uit dan ze in werkelijkheid is.

3. De gebruikersinterface vullen

Met de weergegevens klaar voor gebruik, is het tijd om de gebruikersinterface te updaten. Zoals ik eerder heb uitgelegd, moet het bijwerken van de gebruikersinterface gebeuren in de willActivate methode. Laten we de implementatie van deze methode eens bekijken.

override func willActivate () // Deze methode wordt aangeroepen wanneer de watchview-controller zichtbaar is voor de gebruiker super.willActivate () als het weer is = self.weer locationLabel.setText (weather.location) // Update Temperature Label self .updateTemperatureLabel () // Datumetiket updaten self.updateDateLabel ()

Na het aanroepen van de willActivate methode van de superklasse, we pakken de waarde uit die is opgeslagen in de weer eigendom. Om het locatielabel bij te werken, roepen we aan setText, doorgeven van de waarde die is opgeslagen in de plaats eigendom van de weer voorwerp. Om de temperatuur- en datumlabels bij te werken, roepen we twee hulpmethoden aan. Ik geef er de voorkeur aan om de willActivate methode kort en bondig, en, nog belangrijker, ik hou er niet van mezelf te herhalen.

Voordat we naar deze hulpmethoden kijken, moeten we weten of de temperatuur in Celcius of Fahrenheit moet worden weergegeven. Los een property op om dit probleem op te lossen, celcius, van type Bool en stel de beginwaarde in op waar.

var celcius: Bool = true

De implementatie van updateTemperatureLabel is gemakkelijk te begrijpen. We pakken de opgeslagen waarde veilig uit weer en werk het temperatuurlabel bij op basis van de waarde van celcius. Zoals je kunt zien, zijn de twee hulpmethoden van de WeatherData structuur die we eerder hebben gemaakt van pas komen.

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

De implementatie van updateDateLabel is ook niet moeilijk. We initialiseren een NSDateFormatter bijvoorbeeld, stel zijn datumnotatie property en converteer de datum van de weer object door te bellen stringFromDate (_ :) op de dateFormatter voorwerp. Deze waarde wordt gebruikt om het datumlabel bij te werken.

func updateDateLabel () var date: NSDate = NSDate () // Initialize Date Formatter let dateFormattter = NSDateFormatter () // Datum datum formatterenFormattter.dateFormat = "d / MM UU: mm" indien weer = zelf.weergeven datum = weather.date // Datum update Label datum labelLabel.setText (dateFormattter.stringFromDate (date))

Bouw en voer de applicatie uit om het resultaat te zien. De gebruikersinterface moet nu worden gevuld met de gegevens van weather.json.

4. Overschakelen naar Fahrenheit

Dit ziet er goed uit. Maar zou het niet geweldig zijn als we ondersteuning toevoegen voor zowel Celcius als Fahrenheit? Dit is gemakkelijk te doen, aangezien we al het grootste deel van de basis hebben gelegd.

Als de gebruikerskracht de gebruikersinterface van een gebruikersinterfacecontroller raakt, wordt een menu weergegeven. Dit werkt natuurlijk alleen als een menu beschikbaar is. Laten we kijken hoe dit werkt.

Open Interface.storyboard en voeg een menu toe aan de Interface Controller in de Documentoverzicht aan de linkerzijde. Standaard heeft een menu één menu-item. We hebben twee menu-items nodig, dus voeg een ander menu-item toe aan het menu.

Merk op dat het menu en zijn menu-items niet zichtbaar zijn in de gebruikersinterface. Dit is geen probleem omdat we de lay-out van het menu niet kunnen configureren. Wat we kunnen veranderen, zijn de tekst van een menu-item en de afbeelding ervan. Je zult beter begrijpen wat dat betekent wanneer we het menu presenteren.

Selecteer het bovenste menu-item, open de Kenmerken Inspector, reeks Titel naar Celcius, en Beeld naar Aanvaarden. Selecteer het onderste menu-item en stel in Titel naar Fahrenheit en Beeld naar Aanvaarden.

Open vervolgens InterfaceController.swift in de Assistent redacteur aan de rechterkant. Controle-Drag van het bovenste menu-item tot InterfaceController.swift en maak een actie met de naam toCelcius. Herhaal deze stap voor het onderste menu-item en maak een actie met de naam toFahrenheit.

De uitvoering van deze acties is kort. In toCelcius, we controleren of het celcius eigenschap is ingesteld op vals, en als dat zo is, stellen we het eigendom in waar. In toFahrenheit, we controleren of het celcius eigenschap is ingesteld op waar, en als dat zo is, stellen we het eigendom in vals.

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

Als de waarde van celcius wijzigingen, moeten we de gebruikersinterface bijwerken. Wat is een betere manier om dit te bereiken door een eigenschapwaarnemer op het celcius eigendom. We hoeven alleen maar een didSet eigenschap waarnemer.

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

Het enige detail dat het vermelden waard is, is dat de gebruikersinterface alleen wordt bijgewerkt als de waarde van celcius is veranderd. Het bijwerken van de gebruikersinterface is net zo eenvoudig als bellen updateTemperatureLabel. Bouw en run de WatchKit-applicatie in de iOS Simulator om het menu te testen.

Het is de moeite waard te vermelden dat de iOS Simulator het reactievermogen van een fysiek apparaat nabootst. Wat betekent dat? Vergeet niet dat de WatchKit-extensie op een iPhone wordt uitgevoerd terwijl de WatchKit-app op een Apple Watch wordt uitgevoerd. Wanneer de gebruiker op een menu-item tikt, wordt de aanraakgebeurtenis via een Bluetooth-verbinding naar de iPhone verzonden. De WatchKit-extensie verwerkt de gebeurtenis en verzendt eventuele updates terug naar de Apple Watch. Deze communicatie verloopt redelijk snel, maar het is niet zo snel alsof zowel extensie als applicatie op hetzelfde apparaat zouden worden uitgevoerd. Die korte vertraging wordt nagebootst door de iOS Simulator om ontwikkelaars te helpen een idee te krijgen van de prestaties.

Conclusie

Als u eenmaal uw hoofd rond de architectuur van een WatchKit-toepassing hebt gewikkeld, wordt het veel gemakkelijker om de mogelijkheden en beperkingen van de eerste generatie WatchKit-toepassingen te begrijpen. In deze zelfstudie hebben we alleen de essentiële aspecten van de ontwikkeling van WatchKit besproken. Er is nog veel meer te ontdekken en te ontdekken. Blijf kijken.