Po Swifcie rzutem na taśmę przejrzałem z grubsza zmiany w ostatnich dwóch wersjach iOS 8 i 9. Generalnie zaskoczenia nie ma, a większość rzeczy jest jakby już skądś znanych. Skąd? Odnajduję kilka analogii, czasami wprost do tego, co można było zaobserwować w Windows 8.x czy 10. Ale teraz już pokolei pozwolę skomentować sobie, co najbardziej istotne.
- aplikacje uniwersalne - jeden widok z warunkami na różne ekrany (Windows 10 też wprowadził taką możliwość, powiedziałbym, że warunki ma zrealizowane bardziej uniwersalnie)
- dynamics frameworks - dzielone biblioteki między aplikacje (dopiero w wersji 8?)
- view debugging - jak Live DOM w Visual Studio dla XAML (trzeba przyznać, że Apple poszło dalej i wizualizuje także warstwowo w przestrzeni)
- iOS extensions - no proszę, mi się jednoznacznie kojarzą z kontraktami/rozszerzeniami Windows od 8.x, np. sharowanie, file picker (komunikacja za pomocą linka też jest w aplikacjach Windows Store)
- UIStackView - nareszcie coś na kształt w miarę normalnego StackPanel z XAML, aczkolwiek trochę urozmaicony
- UILayoutGuide - pewne uproszczenia mocno niezjadliwego definiowania warunków layoutu w kodzie, aczkolwiek w dalszym ciągu nie widzę tutaj odpowiedniej prostoty
- Multitasking - wyświetlanie kilku aplikacji na jednym ekranie, snapowanie? znamy to z Windows 8!, aczkolwiek Apple urozmaicił to trybem over oraz pokazywaniem ramki video
- “pliki nagłówkowe” dla Swift - widok podsumowujący “interfejs” klasy C# mamy od dawna w VS
- App Thinning - pobieranie tylko potrzebnych zasobów dla danego urządzenia, kompilacja w Store, znamy to od Windows/Windows Phone 8.1
- API do kontaktów - nareszcie jakieś sensowne API, mocno nawiązujące IMHO do hm… API z Windows
- Search API - wyszukiwanie frazy powiązanej z aplikacją hm… również jakoś nie zaskakuje
iOS 8
w skrócie
- uniwersalne aplikacje
- więcej możliwości interakcji z innymi aplikacjami
- ułatwienia w autentykacji
- ułatwienia w płatnościach mobilnych (Apple Pay)
- wsparcie dla Swift
XCode 6
wsparcie dla Swift prawie takie samo jak dla Objective-C (m.in brak refaktoringu)
testy - m.in Swift i asynchroniczność
iOS 8 Dynamic Frameworks
- dzielone między wiele aplikacji
- wcześniej tylko dzielenie źródeł lub statyczne biblioteki
- szablon: iOS –> Framework & Library –> Cocoa Touch Framework
App Layout
iPhone 480 x 320
Retina: iPhone4 960 x 320
iPhone 5, 5c, 5s 1136 x 640
iPhone 6 1334 x 750
iPhone 6+ 2208 x 1242
Universal Storyboards w Xcode 6
stare: iPhone.storyboard & iPad.storyboard
Live View Rendering
od Xcode 6 także własne widoki
- trzeba dodać atrybut @IBDesignable i nadpisać metodę prepareForInterfaceBuilder
- dodajemy atrybut @IBInspectable to propercji, które chcemy pokazać w inspektorze
Debugowanie
od Xcode 6 wsparcie dla View Debugging (jak Live DOM w VS)
UIKit
Size Classes - “Responsive” design w iOS 8
kompatybilność wstecz z iOS 7 (dodawany dodatkowy kod)
SizeClass enum: Unspecified (Any), Regular, Compact
w runtime jedna dla szerokości i jedna dla wysokości
deklaratywnie
Compact (W), Compact(H): compact
Regular (W), Compact (H): landscape
Compact (W), Regular (H): iphone portret
Regular (W), Regular (H) ipad
Widoki UIKit
- wiele zostało rozszerzonych pod klasy rozmiarów
- UIImage - działa automatycznie z klasami rozmiarów, gdy jest razem z obiektem UIImageAsset
- UISplitViewController - podział jest kontrolowany przez horyzontalną klasę rozmiaru
obiekt UITraitCollection
- klasy rozmiaru horyzontalne i wertykalne
- wartość skalowania
+ Auto Layout
- klasy rozmiaru integrują się z nim
- warunki mogą bazować na klasie rozmiaru
- Xcode 6: wsparcie dla klas rozmiaru w warunkach
+ Views
- widoki mogą być instalowane/usuwane na podstawie klasy Size
pasek na dole pod designerem: w h
na dole bocznego paska z właściwościami: check installed (+ dodajemy warunek), check przy installed decyduje o widoczności
Size Inspector: Constraints This Size Class (ustawiamy względem klasy Size)
można też w kodzie:
view
public override func traitCollectionDidChange (previousTraitCollection: UITraitCollection?) {
let c = self.constraints().filter {
el –> Bool in
if el.firstAttribute == NSLayoutAttribte.Width {
return true
}
return false
}
if let realC = c[0] as? NSLayoutConstraint {
self.layer.cornerRadius = realC.constant / 2
}
}
iOS Extensions
- wystawienie funkcjonalności jednej aplikacji dla innych
- wcześniej tylko deep linki
- iOS 8 (także OSX Yosemite)
Typy
- Share (np. obrazek)
- Actions (np. potrzebujemy aplikację do edycji obrazka, audio, …)
- Photo Editing
- File Provider
- Document Provider
- Today (własne UI do panelu Today w centrum notyfikacyjnym)
Extension Points
- zdefiniowane w System Frameworks
- kontrolują sposób uruchamiania oraz czy extension wyświetla View czy jest niewizualne
Model wykonywania extension
- ładowane w innym, zarządzanym przez system procesie niż aplikacja
- ładowanie do Extension Host, każda instancja extension do osobnego hosta
- proces extension jest izolowany, ale korzysta z grup aplikacji, może przekazywać klucze, domyślnego usera .itp
Extension Context
- zamiast delegatu UIApplication, główny obiekt w extension
- propercja view controllera extension
Today extension
- view controller
- ładować możliwie najszybciej
- centrum notyfikacyjne ustawia ramki
- rozmiary – autolayout lub za pomocą setPreferredContentSize
- animacja rozmiarów za pomocą viewWillTransitionToSize
- protokół NCWidgetProviding do aktualizacji zawartości
szablon: iOS –> Application Extension –> Today Extension
*.appex
Supporting Files: Info.pblist - definicja wspieranego protokołu URL
obsługa otwarcia aplikacji przez plik
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
…
func application(application: UIApplication, handleOpenURL url: NSURL) –> Bool {
…
return true;
}
}
view controller:
let url = “mytoday://newsstoryid”
if let realURL = NSURL(string: url) {
self.extensionContext !.openURL (realURL, completionHandler: nil) //otwieramy naszą aplikację
}
Touch ID
KeyChain - specjalizowana baza używana głównie do przechowywania haseł
Access Control List
- aplikacje w tej samej grupie dla keychain
- zabezpiecza przed innymi aplikacjami
TouchID
dodany do iOS z iPhone 5s i iOS7
odciski palców jako dodatkowy mechanizm autentykacyjny
teraz może być użyty jako dodatkowa warstwa ochrony elementów keychain
Local Authentication – udowadnia, że użytkownik korzysta z aplikacji
iOS 9
- UIKit
- Xcode 7
- Swift 2
- nowe API
UIKit
- UIStackview
- UIKitDynamics
- UILayoutGuide
- Multitasking
UIStackView
automatycznie zakłada constrainty na ciągły układ elementów w kolumnie lub wierszu
orientacja, wyrównanie, sposób wypełnienia kontenera przez elementy (np. rozciągnięte), odstępy
let aStackview: UIStackView = UIStackView()
let aView = UIView()
aStackview.addArrangedSubview(aView)
aStackview.removeArrangedSubview(aView)
aView.removeFromSuperview()
automatyczna enkapsulacja zaznaczonych elementów po wybraniu Stackview
UIKitDynamics
od iOS7 (fizyka)
nowości:
UIFieldBehavior – wektor siły na element
rodzaje:
- linear
- radial
- custom (np. siły z 2 stron)
let radialGrav:UIFieldBehavior = UIFieldBehavior.radialGravityFieldWithPosition(CGPointZero)
radialGrav.region = UIRegion.infiniteRegion()
radialGrav.strength = 0.5
radialGrav.falloff = 0.2
radialGrav.minimumRadius = 0.4
UIDynamicAnimator
ImageView
User Interaction Enabled
view controller:
private var animator: UIDynamicAnimator = UIDynamicAnimator()
override func viewDidLoad() {
…
self.animator = UIDynamicAnimator(referenceView: self.vwContainer)
let imgTap = UITapGestureRecognizer(target: self, action: “enableNoise:”)
self.imageAvatar.AddGestureRecognizer(imgTap)
}
func enableNoise(tap: UITapGestureRecognizer) {
let noiseField = UIFieldBehavior.noiseFieldWithSmoothness(5, animationSpeed: 1)
noiseField.addItem(self.imgAvatar)
let boundsCollision = UICollisionBehavior(items: [self.imgAvatar])
boundsCollision.translatesReferenceBoundsIntoBoundary = true
self.animator.addBehavior(noiseField)
self.animator.addBehavior(boundsCollision)
}
…
coś uwalniamy palcem i jak dotknie granicy, to się odbije i wróci do centrum
UILayoutGuide
Prostokątna przestrzeń, która wchodzi w interakcję z layoutem.
Definiowanie warunków na widok kontenera bez zaśmiecania hierarchii widoków.
- layoutMarginGuide
- readableContentGuide (w orientacji pionej tekst u góry w kilku liniach, w orientacji poziomej w jednej linii centralnie)
let guideRef = self.view.layoutMarginsGuide
let readingContentRef = self.view.readableContentGuide
let container = UILayoutGuide()
self.view.addLayoutGuide(container)
self.view.removeLayoutGuide(container)
self.view.layoutGuides
self.view.layoutMarginsGuide.trailingAnchor
Factory do tworzenia obiektów NSLayoutConstraint przy użyciu fluentnego API. Nie trzeba używać inicjalizatora z dużą ilością parametrów.
let margins = view.layoutMarginsGuide
subview.leadingAnchor.constraintEqualToAnchor(margins.leadingAnchor).active = true
…
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
Multitasking
kilka aplikacji na ekranie
3 rodzaje
- Slide Over - z prawej strony przysnapowane okno nad aplikacją
- Split View - podział ekranu na dwie aplikacje (osobne paski stanu, drugi ekran, wywołanie PiP, regularny; używać auto layout, size classes, smart state transition)
- Picture in Picture - mały ekran z video nad aplikacją (Audio & AirPlay, używać AVKit, AVFoundation, WebKit, MPMoviePlayerViewController, MPMoviePlayerController)
kompatybilność iPad
iPad Mini 2 & 3: Slide Over, PiP (picture in picture)
iPad Air: Slide Over, PiP
iPad Air 2: Splitview, Slide Over, PiP
włączenie:
- Launch Screen capability
- wspierać wszystkie orientacje
wyłączenie:
- UIRequiresFullscreen
wywoływana funkcja w aplikacji:
func applicationWillResignActive(application: UIApplication) [utrzymywać stan aplikacji]
Xcode 7
- Storyboard References
- wsparcie dla plików nagłówkowych
- Playground Additions
- App Thinning
Storyboard references
podział na małe, stawne instancje
let storyboard = UIStoryboard(name: “A_Storyboard”, bundle: NSBundle.mainBundle())
let viewController = storyboard.instantiateInitialViewController()
if let viewController = viewController {
self.presentViewController(viewController, animated: true, completion: nil)
}
Storyboard Reference
przeciągamy na designer ze Storyboard
łączamy controller z referencją (Storyboard, Referenced ID, Bundle)
albo
zanaczamy kontroler, Editor –> Refactor to Storyboard…
nowy storyboard zawiera poprzednio wskazany kontroler
główny storyboard odnosi się do nowego storyboard zamiast wskazanego kontrolera
pliki nagłówkowe (Swift)
zalety plików .h bez ich minusów
plik Swift: Navigate –> Jump to Generated Interface
App Thinning
- Slices - na różnych urządzeniach nie są potrzebne te same assety (np. obrazki)
- Bitcoin - AppStore odpowiedzialny za ostateczną kompilację (różne procesory armv6, armv7, armv7s, optymalizacje)
- zasoby na żądanie - hostowane w AppStore i pobierane w razie potrzeby (NSBundleResourceRequest)
Nowe API
Contacts & ContactsUI
nowe API w miejsce starego opartego na C (Address Book deprecated)
CNContact
- nazwa
- numer telefonu
CNLabeledValue - złożone typy
import Contacts
let homeEmail = CNLabeledValue(label: CNLabelHome, value: “xxx@yyy.co”)
CNContactPickerViewController
wybór kontaktu:
view controller: UIViewController, CNContactPickerDelegate
// import ContactsUI
let contactPicker = CNContactPickerViewController()
viewDidLoad:
contactPicker.delegate = self
contactPicker.displayedPropertyKeys = [CNContactPhoneNumbersKeys]
action:
self.presentViewController(contactPicker, animated: true, completion: nil)
…
func contactPicker(picker: CNContactPickerViewController, didSelectContactProperty contactProperty: CNContactProperty) {
let contact = contactProperty.contact
let phoneNumber = contactProperty.value as! CNPhoneNumber
//contact. givenName, contact.familyName, phoneNumber.stringValue
dodanie nowego kontaktu:
let contact = CNMutableContact()
contact.givenName = “xxx”
contact.familyName = “yyy”
…
let homeAddress = CNMutablePostalAddress()
homeAddress.street = “…”
…
contact.postalAddresses = [CNLabeledValue(label: CNLabelHome, value: homeAddress)]
…
let store = CNContactStore()
let saveRequest = CNSaveResquest()
saveRequest.addContact(contact, toContainerWithIdentifier: nil)
do {
try store.executeSaveRequest(saveRequest)
}
catch {
…
}
Search API
znajdowanie informacji wewnątrz aplikacji, nawet jeśli nie jest zainstalowana
- NSUserActivity
- Core Spotlight Framework
- Web Markup
SFSafariViewController
- standardowy interfejs do przeglądania web
- funkcjonalności Safari (Reader, AutoFill, Fraudulent Website Detection, klucze, cookies, dane, blokowanie zawartości)
import SafariServices
let svc = SFSafariViewController(URL: NSURL(string: “https://xxx.yyy.com”))
self.presentViewController(svc, animated: true, completion: nil)
Brak komentarzy:
Prześlij komentarz