Rakennusnesterajapinnat

Kuinka luoda luonnollisia eleitä ja animaatioita iOS: lla

WWDC 2018 -tapahtumassa Applen suunnittelijat esittelivät keskustelua nimeltään ”Nesterajapintojen suunnittelu”, jossa selitettiin iPhone X: n gesturaalisen käyttöliittymän taustalla olevat suunnitteluperusteet.

Applen WWDC18-esitys “Nesterajapintojen suunnittelu”

Se on kaikkien aikojen suosikki WWDC-keskusteluani - suosittelen sitä.

Puhe tarjosi joitain teknisiä ohjeita, jotka ovat poikkeuksellisia malliesityksen yhteydessä, mutta se oli pseudokoodi, jättäen paljon tuntemattomia.

Jotkut Swift-tyyppiset koodit esityksestä.

Jos yrität toteuttaa näitä ideoita, saatat huomata aukon inspiraation ja toteutuksen välillä.

Tavoitteenani on korjata tämä aukko tarjoamalla toimivia koodiesimerkkejä jokaisesta esityksen tärkeimmästä aiheesta.

Luomme kahdeksan (8) rajapinta. Painikkeet, jouset, mukautetut vuorovaikutukset ja paljon muuta!

Tässä on tiivistelmä siitä, mitä käsittelemme:

  1. Lyhyt yhteenveto “Fluid Interface” -keskusteluista.
  2. Kahdeksan nestemäistä rajapintaa, suunnitteluteoria niiden taustalla ja koodi niiden rakentamiseksi.
  3. Sovellukset suunnittelijoille ja kehittäjille.

Mitä ovat juoksevat rajapinnat?

Nesterajapinta voi myös olla nimeltään ”nopea”, “sileä”, “luonnollinen” tai “maaginen”. Se on kitkaamaton kokemus, joka tuntuu vain ”oikealta”.

WWDC-esitys puhuu juoksevista rajapinnoista "mielen jatkeena" ja "luonnollisen maailman jatkeena". Rajapinta on sujuvaa, kun se käyttäytyy ihmisten ajattelutavan, ei koneiden ajattelun mukaan.

Mikä tekee heistä nestemäisiä?

Nesterajapinnat ovat reagoivia, keskeytettäviä ja uudelleenohjattavia. Tässä on esimerkki pyyhkäisemällä eleestä iPhone X: ssä:

Sovellukset voidaan sulkea niiden animaation aikana.

Käyttöliittymä reagoi välittömästi käyttäjän syötteeseen, voidaan pysäyttää missä tahansa prosessin vaiheessa ja voi jopa muuttaa kurssin puoliväliin.

Miksi välitämme juoksevista rajapinnoista?

  1. Nestemäiset rajapinnat parantavat käyttäjän kokemusta, jolloin jokainen vuorovaikutus tuntuu nopealta, kevyeltä ja tarkoituksenmukaiselta.
  2. Ne antavat käyttäjälle hallinnan tunteen, mikä lisää luottamusta sovellukseesi ja tuotemerkkiisi.
  3. Niitä on vaikea rakentaa. Sulava käyttöliittymä on vaikea kopioida ja voi olla kilpailuetu.

Rajapinnat

Tämän viestin loppuosaan näytän sinulle kuinka rakentaa kahdeksan (8) käyttöliittymää, jotka kattavat kaikki esityksen tärkeimmät aiheet.

Kuvakkeet edustavat kahdeksan (8) rajapintaamme.

Liitäntä # 1: Laskin-painike

Tämä on painike, joka jäljittelee painikkeiden käyttäytymistä iOS-laskinsovelluksessa.

Avainominaisuudet

  1. Korostaa heti koskettamalla.
  2. Voidaan napsauttaa nopeasti myös animaation puolivälissä.
  3. Käyttäjä voi koskettamalla alas ja vetämällä painikkeen ulkopuolelle peruuttaaksesi hanan.
  4. Käyttäjä voi koskettaa alas, vetää ulos, vetää takaisin sisään ja vahvistaa napautuksen.

Suunnitteluteoria

Haluamme painikkeet, jotka tuntevat olevansa reagoivia ja tunnustavat käyttäjälle, että ne ovat toimivia. Lisäksi haluamme, että toiminta peruutetaan, jos käyttäjä päättää toimintansa vastaisesti kosketuksensa jälkeen. Tämän avulla käyttäjät voivat tehdä nopeampia päätöksiä, koska he voivat suorittaa toimia samanaikaisesti ajattelun kanssa.

Diat WWDC-esityksestä osoittavat, kuinka eleet ajatuksen rinnalla nopeuttavat toimia.

Kriittinen koodi

Ensimmäinen vaihe tämän painikkeen luomiseksi on käyttää UIControl-alaluokkaa, ei UIButton-alaluokkaa. UIB-painike toimisi hyvin, mutta koska räätälöimme vuorovaikutusta, emme tarvitse mitään sen ominaisuuksista.

Laskinpainike: UIControl {
    julkinen muuttujan arvo: Int = 0 {
        didSet {label.text = “\ (arvo)”}
    }
    yksityinen laiska var -tunniste: UILabel = {...} ()
}

Seuraavaksi käytämme UIControlEvents-toimintoa toimintojen määrittämiseen erilaisille kosketusvuorovaikutuksille.

addTarget (itse, toiminta: # valitsin (touchDown), kohteelle: [.touchDown, .touchDragEnter])
addTarget (itse, toiminta: # valitsin (kosketa ylös), kohteelle: [.touchUpInside, .touchDragExit, .touchCancel])

Ryhmittelemme touchDown- ja touchDragEnter-tapahtumat yhdeksi ”tapahtumaksi”, jota kutsutaan touchDownksi, ja voimme ryhmitellä touchUpInside-, touchDragExit- ja touchCancel-tapahtumat yhdeksi tapahtumaksi nimeltään touchUp.

(Katso kuvaus kaikista käytettävissä olevistaUIControlEvents-ohjelmistoista.)

Tämä antaa meille kaksi toimintoa animaatioiden käsittelemiseen.

yksityinen var-animaattori = UIViewPropertyAnimator ()
@objc yksityinen func touchDown () {
    animator.stopAnimation (tosi)
    backgroundColor = korostettu väri
}
@objc yksityinen func touchUp () {
    animaattori = UIViewPropertyAnimator (kesto: 0,5, käyrä: .easeOut, animaatiot: {
        self.backgroundColor = itse.normalColor
    })
    animator.startAnimation ()
}

TouchDown-tilassa peruutamme tarvittaessa olemassa olevan animaation ja asetamme värin heti korostettuun väriin (tässä tapauksessa vaaleanharmaan).

Kosketusnäytöllä luomme uuden animaattorin ja aloitamme animaation. Kohdeanimaation peruuttaminen on helppoa UIViewPropertyAnimatorin avulla.

(Sivuhuomautus: Tämä ei ole iOS-laskinsovelluksen painikkeiden tarkka toiminta, jotka sallivat toisesta painikkeesta alkaneen kosketuksen aktivoida sen, jos kosketus vedettiin painikkeen sisään. Useimmissa tapauksissa yhden kaltainen painike Luomasi tässä on tarkoitettu käyttäytyminen iOS-painikkeille.)

Rajapinta # 2: Kevään animaatiot

Tämä käyttöliittymä osoittaa, kuinka kevään animaatio voidaan luoda määrittelemällä ”vaimennus” (heilahdus) ja ”vaste” (nopeus).

Avainominaisuudet

  1. Käyttää “suunnitteluystävällisiä” parametreja.
  2. Ei animaation keston käsitettä.
  3. Helppo keskeyttää.

Suunnitteluteoria

Jouset tekevät mahtavia animaatiomalleja nopeuden ja luonnollisen ulkonäön vuoksi. Kevätanimaatio alkaa uskomattoman nopeasti viettämällä suurimman osan ajastaan ​​vähitellen lähestyen lopputilaansa. Tämä sopii erinomaisesti rajapintojen luomiseen, jotka tuntevat olevansa reagoivia - ne alkavat elämään!

Muutamia lisämuistutuksia kevään animaatioiden suunnittelussa:

  1. Jousien ei tarvitse olla joustavia. Vaimennusarvon 1 avulla luodaan animaatio, joka hitaasti lepää ilman mitään pomppuvuutta. Suurimmassa osassa animaatioita tulisi käyttää vaimennusarvoa 1.
  2. Yritä välttää ajattelemasta kestoa. Teoriassa jousi ei koskaan täysin lepää, ja jousen keston pakottaminen voi aiheuttaa sen tuntuman luonnotonta. Sen sijaan leiki vaimennus- ja vastearvoilla, kunnes se tuntuu oikealta.
  3. Keskeytykset ovat kriittisiä. Koska jouset viettävät niin suuren osan ajastaan ​​lähellä lopullista arvoaan, käyttäjät voivat ajatella, että animaatio on valmis ja yrittää olla vuorovaikutuksessa sen kanssa uudelleen.

Kriittinen koodi

UIKit-ohjelmassa voimme luoda kevään animaation UIViewPropertyAnimator ja UISpringTimingParameters -objektien avulla. Valitettavasti ei ole alustajaa, joka vain vaimentaisi ja vastaisi. Lähin, mitä voimme saada, on UISpringTimingParameters -alusta, joka ottaa massan, jäykkyyden, vaimennuksen ja alkuperäisen nopeuden.

UISpringTimingParameters (massa: CGFloat, jäykkyys: CGFloat, vaimennus: CGFloat, alkuperäinenVelocity: CGVector)

Haluamme luoda mukavuusalustimen, joka ottaa vaimennuksen ja vasteen ja kartoittaa sen vaadittuun massaan, jäykkyyteen ja vaimennukseen.

Hieman fysiikan avulla voimme saada tarvittavat yhtälöt:

Ratkaisu jousen vakio- ja vaimennuskerrointa varten.

Tämän tuloksen avulla voimme luoda omat UISpringTimingParameterit tarkalleen haluamillamme parametreilla.

laajennus UISpringTimingParameters {
    mukavuusindeksi (vaimennus: CGFloat, vastaus: CGFloat, InitVelocity: CGVector = .zero) {
        anna jäykkyys = pow (2 * .pi / vaste, 2)
        anna kostea = 4 * .pi * vaimennus / vaste
        itsenäinen (massa: 1, jäykkyys: jäykkyys, vaimennus: kostea, alkuperäinenVelocity: alkuperäinenVelocity)
    }
}

Näin määrittelemme kevään animaatiot kaikille muille rajapinnoille.

Kevätanimaatioiden taustalla oleva fysiikka

Haluatko syventää kevään animaatioita? Katso tämä Christian Schnorrin uskomaton viesti: UIKitin kevään animaatioiden demystifisointi.

Luettuani hänen viestinsä kevätanimaatiot napsauttivat vihdoin minua. Valtava huutaus Christianille siitä, että hän auttoi minua ymmärtämään näiden animaatioiden taustalla olevan matematiikan ja opetti minulle kuinka ratkaista toisen asteen differentiaaliyhtälöt.

Rajapinta # 3: Taskulampun painike

Toinen painike, mutta käyttäytyy paljon eri tavalla. Tämä jäljittelee taskulamppupainikkeen käyttämistä iPhone X: n lukitusnäytössä.

Avainominaisuudet

  1. Edellyttää tahallisen eleen 3D-kosketuksella.
  2. Bounciness viittaa vaadittuun eleeseen.
  3. Haptinen palaute vahvistaa aktivoinnin.

Suunnitteluteoria

Apple halusi luoda painikkeen, joka oli helposti ja nopeasti saatavissa, mutta jota ei voitu laukaista vahingossa. Voimapaineen vaatiminen taskulampun aktivoimiseksi on hieno valinta, mutta siitä puuttuu saatavuus ja palaute.

Näiden ongelmien ratkaisemiseksi painike on joustava ja kasvaa käyttäjän käyttäessä voimaa vihjaamalla vaadittuun eleeseen. Lisäksi on olemassa kaksi erillistä haptisen palautteen värähtelyä: yksi tarvittavaa voimamäärää käytettäessä ja toinen, kun painike aktivoituu voiman pienentyessä. Nämä haptikot matkivat fyysisen painikkeen käyttäytymistä.

Kriittinen koodi

Painikkeeseen kohdistuvan voiman määrän mittaamiseen voidaan käyttää kosketustapahtumissa annettua UITouch-objektia.

ohittaa func-kosketuksetMoved (_ kosketukset: Aseta , tapahtumalla: UIEvent?) {
    super.touchesMoved (koskettaa, seuraavilla: tapahtuma)
    vartija anna koskettaa = koskettaa.fisyö muuta {paluu}
    anna voima = touch.force / touch.maximumPossibleForce
    anna asteikko = 1 + (enimmäisleveys / minleveys - 1) * voima
    muuntaa = CGAffineTransform (asteikkoX: mittakaava, y: mittakaava)
}

Laskemme asteikon muutoksen nykyisen voiman perusteella, niin että painike kasvaa paineen kasvaessa.

Koska painiketta voidaan painaa, mutta sitä ei vielä ole aktivoitu, meidän on seurattava painikkeen nykyistä tilaa.

enum ForceState {
    tapauksen palautus, aktivointi, vahvistus
}
yksityinen anna resetForce: CGFloat = 0,4
yksityinen anna activationForce: CGFloat = 0,5
yksityinen anna vahvistusForce: CGFloat = 0,49

Vahvistusvoiman ollessa hiukan alhaisempi kuin aktivointivoima estää käyttäjää aktivoimasta ja poistamasta painiketta nopeasti nopeasti ylittämällä voimakynnyksen.

Haptisen palautteen saamiseksi voimme käyttää UIKitin palautegeneraattoreita.

yksityinen anna activationFeedbackGenerator = UIImpactFeedbackGenerator (tyyli: .light)
yksityinen anna vahvistusFeedbackGenerator = UIImpactFeedbackGenerator (tyyli: .medium)

Viimeinkin, pomppisanimaatioissa voimme käyttää UIViewPropertyAnimatoria aiemmin luomien mukautettujen UISpringTimingParameters-alustusohjelmien kanssa.

anna params = UISpringTimingParameters (vaimennus: 0,4, vastaus: 0,2)
anna animaattori = UIViewPropertyAnimator (kesto: 0, timingParameters: params)
animator.addAnimations {
    itse.transformaatio = CGAffineTransform (asteikkoX: 1, y: 1)
    self.backgroundColor = self.isOn? self.onColor: self.offColor
}
animator.startAnimation ()

Rajapinta # 4: Kuminauha

Kuminauhat tapahtuvat, kun näkymä vastustaa liikettä. Esimerkki on, kun vieritysnäkymä saavuttaa sisällön lopun.

Avainominaisuudet

  1. Rajapinta on aina reagoiva, vaikka toiminta olisi virheellinen.
  2. Synkronoimaton kosketusseuranta osoittaa rajan.
  3. Liikkeen määrä vähenee kauempana rajasta.

Suunnitteluteoria

Kuminauha on loistava tapa kommunikoida virheellisten toimien kanssa samalla, kun antaa käyttäjälle hallinnan tunteen. Se osoittaa pehmeästi rajan, vetäen ne takaisin voimassa olevaan tilaan.

Kriittinen koodi

Kuminauha on onneksi helppo toteuttaa.

offset = pow (offset, 0,7)

Käyttämällä eksponenttia välillä 0 - 1 näkymän poikkeama siirretään sitä kauemmaksi, mitä kauempana se on lepoasennostaan. Käytä suurempaa eksponenttia vähemmän liikettä varten ja pienempää eksponenttia enemmän liikettä varten.

Hieman enemmän asiayhteyttä varten tämä koodi toteutetaan yleensä UIPanGestureRecognizer-soittopyynnössä aina, kun kosketus liikkuu. Siirtymä voidaan laskea nykyisen ja alkuperäisen kosketuskohdan välisellä deltalla, ja siirtymää voidaan soveltaa käännösmuunnoksella.

var offset = touchPoint.y - originalTouchPoint.y
offset = offset> 0? pow (offset, 0,7): -pow (-offset, 0,7)
view.transform = CGAffineTransform (translationX: 0, y: offset)

Huomaa: Apple ei tällä tavalla tee kuminauhoja esimerkiksi vieritysnäkymien avulla. Pidän tästä menetelmästä sen yksinkertaisuuden takia, mutta eri käyttäytymisille on monimutkaisempia toimintoja.

Rajapinta # 5: Kiihtyvyystauko

Tarkastellaksesi sovelluksenvaihtoa iPhone X: ssä, käyttäjä pyyhkäisee näytön alaosasta ylös ja pysähtyy puoliväliin. Tämä käyttöliittymä luo tämän käytön uudelleen.

Avainominaisuudet

  1. Tauko lasketaan eleen kiihtyvyyden perusteella.
  2. Nopeampi pysähtyminen johtaa nopeampaan vastaukseen.
  3. Ei ajastimia.

Suunnitteluteoria

Nesterajapintojen tulisi olla nopeita. Ajastimen viive, vaikka lyhytkin, voi tehdä käyttöliittymästä hidas.

Tämä käyttöliittymä on erityisen viileä, koska sen reaktioaika perustuu käyttäjän liikkeeseen. Jos ne keskeytyvät nopeasti, käyttöliittymä reagoi nopeasti. Jos tauko hitaasti, se reagoi hitaasti.

Kriittinen koodi

Kiihtyvyyden mittaamiseksi voimme seurata panoroinnin nopeuden viimeisimpiä arvoja.

yksityiset muuttujan nopeudet = [CGFloat] ()
yksityinen func track (nopeus: CGFloat) {
    jos nopeudet.laskuta 

Tämä koodi päivittää nopeusryhmän siten, että sillä on aina seitsemän viimeistä nopeutta, joita käytetään kiihtyvyyden laskemiseen.

Jotta voidaan määrittää, onko kiihtyvyys riittävän suuri, voimme mitata taulukkomme ensimmäisen nopeuden erotuksen nykyisestä nopeudesta.

jos abs (nopeus)> 100 || abs (offset) <50 {paluu}
anna suhde = abs (firstRecordedVelocity - nopeus) / abs (firstRecordedVelocity)
jos suhde> 0,9 {
    pauseLabel.alpha = 1
    feedbackGenerator.impactOccurred ()
    hasPaused = totta
}

Tarkastamme myös varmistaaksemme, että liikkeellä on minimaalinen siirtymä ja nopeus. Jos ele on menettänyt yli 90% nopeudesta, katsomme, että ele on keskeytetty.

Toteutukseni ei ole täydellinen. Testauksessani se näyttää toimivan melko hyvin, mutta kiihtyvyyden mittaamiseksi on mahdollisuus parempaan heuristiikkaan.

Interface # 6: Palkitseminen vauhtia

Vetolaatikko, jossa on avoimet ja suljetut tilat, jossa on heikkous eleen nopeuden perusteella.

Avainominaisuudet

  1. Napauttamalla laatikkoa avaat sen ilman pomppumista.
  2. Laatikon napsauttaminen avaa sen pomppuvalla tavalla.
  3. Interaktiivinen, keskeytettävä ja palautuva.

Suunnitteluteoria

Tämä laatikko näyttää palkkion myöntämisen käsitteen. Kun käyttäjä pyyhkäisee näkymää nopeudella, on paljon ilahduttavampaa animoida näkymä hellävaraisesti. Tämä tekee käyttöliittymästä elävän ja hauskan.

Kun laatikkoa napautetaan, se elää ilman pomppoutta, mikä tuntuu tarkoituksenmukaiselta, koska hanalla ei ole vauhtia tiettyyn suuntaan.

Suunniteltaessa mukautettuja vuorovaikutuksia on tärkeää muistaa, että rajapinnoissa voi olla erilaisia ​​animaatioita erilaisille vuorovaikutuksille.

Kriittinen koodi

Napauttamisen ja panoroinnin logiikan yksinkertaistamiseksi voimme käyttää mukautetun eleiden tunnistimen alaluokkaa, joka siirtyy heti aloitustilaan koskettamalla.

luokka InstantPanGestureRecognizer: UIPanGestureRecognizer {
    ohittaa func touchesBegan (_ koskettaa: Aseta , tapahtumalla: UIEvent) {
        super.touchesBegan (koskettaa, tapahtuman kanssa)
        oma.valtio = .aloitettu
    }
}

Tämän avulla käyttäjä voi myös napauttaa laatikkoa liikkeensa aikana keskeyttääksesi sen, samalla tavalla kuin napauttamalla vieritysnäkymää, jota tällä hetkellä vieritetään. Hanojen käsittelemiseksi voimme tarkistaa, onko nopeus nolla eleen loputtua, ja jatkaa animaatiota.

jos yVelocity == 0 {
    animator. ContinueAnimation (withTimingParameters: nolla, durationFactor: 0)
}

Jotta ele voidaan käsitellä nopeudella, meidän on ensin laskettava sen nopeus suhteessa jäljellä olevaan kokonaissiirtoon.

anna fractionRemaining = 1 - animator.fractionComplete
anna distanceRemaining = osuusRemaining * closedTransform.ty
jos distanceRemaining == 0 {
    animator. ContinueAnimation (withTimingParameters: nolla, durationFactor: 0)
    tauko
}
olkoon relatiivinenVelocity = abs (yVelocity) / distanceRemaining

Voimme käyttää tätä suhteellista nopeutta jatkaaksesi animaatiota ajoitusparametreilla, jotka sisältävät vähän pomppuvuutta.

anna timingParameters = UISpringTimingParameters (vaimennus: 0,8, vaste: 0,3, alkuperäinenVelocity: CGVector (dx: suhteellinenVelocity, dy: suhteellinenVelocity))
anna newDuration = UIViewPropertyAnimator (kesto: 0, timingParameters: timingParameters) .duration
anna durationFactor = CGFloat (newDuration / animator.duration)
animator. ContinueAnimation (withTimingParameters: timingParameters, durationFactor: durationFactor)

Tässä luomme uuden UIViewPropertyAnimator -sovelluksen animaation laskemiseen tarvittavan ajan laskemiseksi, jotta voimme tarjota oikean kestonkestäjän jatkaessasi animaatiota.

Animaation kääntämiseen liittyy monimutkaisempia asioita, joita en aio käsitellä täällä. Jos haluat lisätietoja, kirjoitin tämän komponentin täydellisen opetusohjelman: Parempien iOS-sovellusanimaatioiden rakentaminen.

Rajapinta # 7: FaceTime PiP

IOS FaceTime -sovelluksen kuva-kuvassa -käyttöliittymän luominen uudelleen.

Avainominaisuudet

  1. Kevyt, ilmava vuorovaikutus.
  2. Suunniteltu sijainti perustuu UIScrollView-hidastuvuuteen.
  3. Jatkuva animaatio, joka kunnioittaa eleen alkuperäistä nopeutta.

Kriittinen koodi

Päätavoitteemme on kirjoittaa jotain tällaista.

anna params = UISpringTimingParameters (vaimennus: 1, vaste: 0,4, alkuperäinenVelocity: suhteellinenInitialVelocity)
anna animaattori = UIViewPropertyAnimator (kesto: 0, timingParameters: params)
animator.addAnimations {
    self.pipView.center = lähinCornerPosition
}
animator.startAnimation ()

Haluamme luoda animaation alkuperäisellä nopeudella, joka vastaa panoroinnin nopeutta, ja animoida pip lähimpään nurkkaan.

Lasketaan ensin alkuperäinen nopeus.

Tätä varten meidän on laskettava suhteellinen nopeus nykyisen nopeuden, nykyisen sijainnin ja kohteen sijainnin perusteella.

anna reliaInitialVelocity = CGVector (
    dx: suhteellinenVelocity (forVelocity: nopeus.x, alkaen: pipView.center.x, kohteeseen: lähimpiinCornerPosition.x),
    dy: suhteellinenVelocity (forVelocity: nopeus.y, alkaen: pipView.center.y, kohteeseen: lähinCornerPosition.y)
)
func santykVelocity (forVelocity-nopeus: CGFloat, nykyisestä arvosta: CGFloat, kohdearvoon: CGFloat) -> CGFloat {
    vartija currentValue - targetValue! = 0 else {return 0}
    paluunopeus / (targetValue - currentValue)
}

Voimme jakaa nopeuden sen x- ja y-komponentteihin ja määrittää suhteellisen nopeuden jokaiselle.

Lasketaan seuraavaksi PiP: n kulma animaatioksi.

Jotta käyttöliittymämme tuntuisi luonnolliselta ja kevyeltä, aiomme projisoida PiP: n lopullisen sijainnin sen nykyisen liikkeen perusteella. Jos PiP liukuisi ja pysähtyisi, minne se laskeutuisi?

anna hidastuvuusRate = UIScrollView.DecelerationRate.normal.rawValue
anna nopeus = tunnistin.kehitys (näkymässä)
anna projectedPosition = CGPoint (
    x: pipView.center.x + projekti (alkuperäinenVelocity: nopeus.x, hidastuvuusarvo: hidastuvuusarvo),
    y: pipView.center.y + projekti (alkuperäinenVelocity: nopeus.y, hidastuvuusarvo: hidastuvuusRate)
)
anna lähinCornerPosition = lähinCorner (kohteeseen: projectedPosition)

Voimme käyttää UIScrollView: n hidastuvuusastetta tämän lepoasennon laskemiseen. Tämä on tärkeää, koska se viittaa käyttäjän lihaksen muistiin vierittämistä varten. Jos käyttäjä tietää kuinka pitkälle näkymä vierii, hän voi käyttää tätä aikaisempaa tietoa intuitiivisesti arvataksesi, kuinka paljon voimaa tarvitaan siirtämään PiP haluttuun kohteeseen.

Tämä hidastumisnopeus on myös melko runsas, mikä tekee vuorovaikutuksesta kevyen - tarvitaan vain pieni välähdys PiP: n lähettämiseksi lentäen koko näytön poikki.

Voimme käyttää ”Suunnittelu nestemäiset rajapinnat” -puhelun projisointitoimintoa laskeaksesi lopullisen projisoidun sijainnin.

/// Kuljettu matka, kun hidastuminen nollaanopeuteen on vakiona.
func-projekti (alkuperäinenVelocity: CGFloat, hidastuvuusarvo: CGFloat) -> CGFloat {
    paluu (alkuperäinenVelocity / 1000) * hidastuvuusarvo / (1 - hidastuvuusarvo)
}

Viimeinen puuttuva pala on logiikka löytää lähin kulma ennustetun sijainnin perusteella. Tätä varten voimme silmukoida kaikkien kulma-asentojen läpi ja löytää se, jolla on pienin etäisyys suunniteltuun laskeutumispaikkaan.

func lähinCorner (kohtaan: CGPoint) -> CGPoint {
    var minDistance = CGFloat.greatestFiniteMagnitude
    var closeestPosition = CGPoint.zero
    sijainti pipPositions {
        anna etäisyys = piste.distanssi (sijaintiin: sijainti)
        jos etäisyys 

Yhteenvetona lopullisesta toteutuksesta: Käytämme UIScrollView-hidastuvuusastetta projisoidaksesi pipin liikkeen lopulliseen lepoasentoonsa ja laskemalla suhteellinen nopeus syöttämällä se kaikki UISpringTimingParameters -yksikköön.

Rajapinta # 8: Kierto

Käsitteiden soveltaminen PiP-käyttöliittymästä kiertoanimaatioon.

Avainominaisuudet

  1. Käyttää projektiota eleen nopeuden kunnioittamiseen.
  2. Päättyy aina pätevään suuntaan.

Kriittinen koodi

Tässä oleva koodi on hyvin samanlainen kuin edellinen PiP-käyttöliittymä. Käytämme samoja rakennuspalikoita, paitsi vaihtamalla lähinCorner-toiminto lähimmänkulmafunktioon.

func-projekti (...) {...}
func suhteellinenVelocity (...) {...}
func lähinAngle (...) {...}

Kun on aika lopulta luoda UISpringTimingParameters, meidän on käytettävä CGVectoria alkuperäiselle nopeudelle, vaikka rotaatiollamme olisi vain yksi ulottuvuus. Joka tapauksessa, kun animoidulla ominaisuudella on vain yksi ulottuvuus, aseta dx-arvo haluttuun nopeuteen ja aseta dy-arvo nollaan.

anna timingParameters = UISpringTimingParameters (
    vaimennus: 0,8,
    vaste: 0,4,
    alkuperäinenVelocity: CGVector (dx: suhteellinenInitialVelocity, dy: 0)
)

Animaattori jättää sisäisesti huomioimatta dy-arvon ja luo dx-arvon ajoituskäyrän luomiseksi.

Kokeile itse!

Nämä rajapinnat ovat paljon hauskempia oikeassa laitteessa. Voit pelata näiden rajapintojen kanssa itse, demosovellus on saatavana GitHubissa.

Nesterajapintojen esittelysovellus, saatavana GitHubista!

Käytännön sovellukset

Suunnittelijoille

  1. Ajattele rajapintoja nestemäisinä ilmaisuväliaineina, ei staattisten elementtien kokoelmina.
  2. Mieti animaatioita ja eleitä suunnitteluprosessin varhaisessa vaiheessa. Sketchin kaltaiset asettelutyökalut ovat fantastisia, mutta eivät tarjoa laitteen täydellistä ilmaisua.
  3. Prototyyppi kehittäjien kanssa. Hanki suunnittelijamiehiä, jotka auttavat prototyyppianimaatioita, eleitä ja haptikoja.

Kehittäjille

  1. Käytä näiden käyttöliittymien vinkkejä omiin komponentteihisi. Ajattele kuinka ne voidaan yhdistää uusilla ja mielenkiintoisilla tavoilla.
  2. Kouluta suunnittelijoita uusista mahdollisuuksista. Monet eivät ole tietoisia 3D-kosketuksen, haptikoiden, eleiden ja kevään animaatioiden täydestä voimasta.
  3. Prototyyppi suunnittelijoiden kanssa. Auta heitä näkemään mallinsa oikealla laitteella ja luomaan työkaluja, joiden avulla he voivat suunnitella tehokkaammin.

Jos nautit tästä viestistä, jätä joitain claps.

Voit taputtaa jopa 50 kertaa, joten napsauta / napauta!

Jaa viesti iOS-suunnittelijallesi / iOS-kehittäjäystävillesi valitsemassasi sosiaalisen median puolella.

Jos pidät tällaisista asioista, sinun tulisi seurata minua Twitterissä. Postitan vain korkealaatuisia tweettejä. twitter.com/nathangitter

Kiitos David Okunille tämän viestin luonnoksen tarkistamisesta.