„IOS“ - „Frame vs Bounds“

Šis straipsnis yra atsakymo, kurį parašiau apie kamino perpildymą, pakartojimas.

Trumpas aprašymas

  • kadras = rodinio vieta ir dydis, naudojant pagrindinio rodinio koordinačių sistemą (svarbu norint įkelti vaizdą į tėvystę)
  • ribos = rodinio vieta ir dydis naudojant jo naudojamą koordinačių sistemą (svarbu norint pateikti rodinio turinį ar peržiūras pačiame savyje)

Informacija

Norėdamas atsiminti rėmelį, pamatau paveikslo rėmelį ant sienos. Paveikslo rėmelis yra tarsi vaizdo rėmelis. Paveikslą galiu pakabinti ant sienos bet kur, kur noriu. Lygiai taip pat aš galiu perkelti bet kur norimą vaizdą į pagrindinį vaizdą (dar vadinamą supervizija). Tėvų vaizdas yra tarsi siena. Koordinačių sistemos kilmė „iOS“ yra viršuje, kairėje. Savo vaizdą galime įvertinti peržiūros pradžioje, nustatydami vaizdo rėmelio x-y koordinates į (0, 0), tai yra tarsi pakabinti mūsų paveikslėlį pačiame viršutiniame kairiajame sienos kampe. Norėdami perkelti į dešinę, padidinkite x, perkelkite žemyn - padidinkite y.

Norėdamas padėti atsiminti ribas, galvoju apie krepšinio aikštę, kurioje kartais krepšys išmušamas iš užribio. Jūs vairuojate kamuolį visoje krepšinio aikštelėje, bet jums visiškai nesvarbu, kur yra pats teismas. Tai gali būti sporto salėje, lauke vidurinėje mokykloje arba priešais jūsų namą. Nesvarbu. Norite tiesiog žaisti krepšinį. Tokiu pat būdu koordinačių sistema, skirta apžvelgti ribas, rūpinasi tik pačiu vaizdu. Jis nieko nežino apie pagrindiniame rodinyje pateiktą rodinį. Ribų kilmė (taškas (0, 0) pagal numatytuosius nustatymus) yra viršutinis kairysis rodinio kampas. Šiuo klausimu pateikiamos visos nuomonės, kurias šis požiūris pateikė. Tai yra tarsi krepšinio nunešimas į priekinį kairįjį aikštės kampą.

Dabar kyla painiava bandant palyginti rėmus ir ribas. Vis dėlto tai nėra taip blogai, kaip atrodo iš pradžių. Panaudokime keletą nuotraukų, kad padėtume mums suprasti.

Rėmelis prieš ribas

Pirmame paveikslėlyje kairėje turime vaizdą, kuris yra viršutiniame kairiajame jo pagrindinio vaizdo viršuje. Geltonas stačiakampis žymi rodinio rėmelį. Dešinėje mes vėl matome vaizdą, bet šį kartą tėvų vaizdas nerodomas. Taip yra todėl, kad ribos nežinomos apie tėvų rodinį. Žalias stačiakampis žymi rodinio ribas. Raudonas taškas abiejuose vaizduose parodo kadro kilmę arba ribas.

Rėmas
    kilmė = (0, 0)
    plotis = 80
    aukštis = 130
 
 Ribos
    kilmė = (0, 0)
    plotis = 80
    aukštis = 130

Taigi kadras ir ribos toje nuotraukoje buvo visiškai vienodi. Pažvelkime į pavyzdį, kur jie skiriasi.

 Rėmas
     kilmė = (40, 60) // T. y., x = 40 ir y = 60
     plotis = 80
     aukštis = 130
 
 Ribos
     kilmė = (0, 0)
     plotis = 80
     aukštis = 130

Taigi galite pastebėti, kad pakeitus rėmelio x-y koordinates, jis perkeliamas į pradinį vaizdą. Bet pats vaizdo turinys vis tiek atrodo visiškai tas pats. Ribos net neįsivaizduoja, kad kas nors yra kitaip.

Iki šiol rėmo ir apvadų plotis ir aukštis buvo visiškai vienodi. Tačiau tai ne visada yra tiesa. Pažiūrėkite, kas nutiks, jei vaizdą pasukame 20 laipsnių pagal laikrodžio rodyklę. (Sukimas atliekamas naudojant transformacijas. Norėdami gauti daugiau informacijos, skaitykite dokumentus ir šiuos rodinius bei sluoksnių pavyzdžius.)

Rėmas
   kilmė = (20, 52) // Tai tik apytiksliai įvertinimai.
   plotis = 118
   aukštis = 187
 
Ribos
   kilmė = (0, 0)
   plotis = 80
   aukštis = 130

Jūs galite pamatyti, kad ribos vis dar nesiskiria. Jie vis dar nežino, kad kas nors nutiko! Vis dėlto visos kadrų vertės pasikeitė.

Dabar šiek tiek lengviau pastebėti skirtumą tarp kadrų ir ribų, ar ne? Straipsnyje, kurio tikriausiai nesuprantate, rėmeliai ir ribos, rodomas kadras apibūdinamas kaip

... mažiausias to požiūrio langelis tėvų atžvilgiu
koordinačių sistema, įskaitant visas tame vaizde pritaikytas transformacijas.

Svarbu atkreipti dėmesį, kad jei keičiate vaizdą, rėmas tampa neapibrėžtas. Taigi geltonos spalvos rėmelio, kurį piešiau aplink pasuktas žalias ribas aukščiau esančiame paveikslėlyje, iš tikrųjų nėra. Tai reiškia, kad jei sukate, keičiate mastelį ar darote kokį nors kitą pertvarkymą, daugiau neturėtumėte naudoti rėmelio verčių. Vis dėlto vis tiek galite naudoti ribų reikšmes. „Apple“ dokumentai įspėja:

Svarbu: jei rodinio transformavimo ypatybėje nėra tapatybės transformacijos, to rodinio rėmas nėra apibrėžtas, o tai yra ir jo automatinio elgesio rezultatai.

Gana gaila dėl automatinio ... Vis dėlto yra kažkas, ką galite padaryti.

„Apple“ dokumentų būsena:

Kai modifikuojate savo vaizdo transformacijos ypatybę, visos transformacijos atliekamos atsižvelgiant į rodinio centrinį tašką.

Taigi, jei po pertvarkos jums reikia perkelti pagrindinį vaizdą, galite tai padaryti pakeisdami „view.center“ koordinates. Kaip ir rėmas, centras naudoja pagrindinio rodinio koordinačių sistemą.

Gerai, atsikratykime mūsų rotacijos ir sutelkime dėmesį į ribas. Iki šiol ribų kilmė visada išliko (0, 0). Vis dėlto to nereikia. O kas, jei mūsų rodinyje yra didelė antrinė peržiūra, kuri yra per didelė, kad būtų galima rodyti visus iš karto? Padarysime tai „UIImageView“ su dideliu atvaizdu. Čia vėl yra mūsų antrasis paveikslėlis iš viršaus, bet šį kartą galime pamatyti, kaip atrodytų visas mūsų apžvalgos potekstės turinys.

Rėmas
    kilmė = (40, 60)
    plotis = 80
    aukštis = 130
 
Ribos
    kilmė = (0, 0)
    plotis = 80
    aukštis = 130

Tik viršutinis kairysis vaizdo kampas gali tilpti į rodinio ribas. Dabar pažiūrėkite, kas nutiks, jei pakeisime ribų kilmės koordinates.

Rėmas
    kilmė = (40, 60)
    plotis = 80
    aukštis = 130
 
Ribos
    kilmė = (280, 70)
    plotis = 80
    aukštis = 130

Rėmelis nepajudėjo viršutinėje apžvalgoje, bet turinys rėmo viduje pasikeitė, nes ribojamojo stačiakampio kilmė prasideda kitoje vaizdo dalyje. Tai yra visa UIScrollView idėja ir jos poklasiai (pavyzdžiui, UITableView). Norėdami gauti daugiau paaiškinimų, skaitykite „UIScrollView“ supratimas.

Kada naudoti rėmą ir kada naudoti ribas

Kadangi rėmas susijęs su rodinio vieta jo pagrindiniame rodinyje, jūs jį naudojate atlikdami išorinius pakeitimus, pvz., Keičiant jo plotį arba nustatant atstumą tarp rodinio ir jo pagrindinio rodinio viršaus.

Naudokite ribas, kai darote vidinius pakeitimus, pvz., Piešiate dalykus ar rengiate potekstes vaizde. Taip pat naudokite ribas, kad gautumėte vaizdo dydį, jei jūs jį šiek tiek perfrazavote.

Straipsniai tolimesniems tyrimams:

„Apple“ dokumentai

  • Peržiūrėti geometriją
  • Peržiūrų
  • Vaizdo ir langų architektūra

Kiti ištekliai

  • Tikriausiai nesuprantate rėmų ir ribų
  • „iOS“ pagrindai: rėmeliai, ribos ir „CGGeometry“
  • CS193p 5 paskaita - vaizdai, piešimas, animacija

Praktikuok save

Be minėtų straipsnių skaitymo, tai labai padeda sukurti bandomąją programą. Galbūt norėsite pabandyti padaryti kažką panašaus. (Idėja kilo iš šio vaizdo kurso, bet, deja, ji nėra nemokama.)

Čia yra jūsų nuorodos kodas:

importuoti UIKit
 
   klasės „ViewController“: „UIViewController“ {
 
 
    @IBOutlet silpnas var myView: UIView!
 
    // Etiketės
    @IBOutlet silpnas var frameX: UILabel!
    @IBOutlet silpnas var frameY: UILabel!
    @IBOutlet silpnas var frameWidth: UILabel!
    @IBOutlet silpnas var frameHeight: UILabel!
    @IBOutlet silpnos var ribosX: UILabel!
    @IBOutlet silpnos įvairios ribosY: UILabel!
    @IBOutlet silpnos var ribosPlatumas: UILabel!
    @IBOutlet silpnas var boundsHeight: UILabel!
    @IBOutlet silpnas var centreX: UILabel!
    @IBOutlet silpnas įvairus centras: UILabel!
    @IBOutlet silpnas var sukimasis: UILabel!
 
    // Skaidrės
    @IBOutlet silpnas var frameXSlider: UISlider!
    @IBOutlet silpnas var frameYSlider: UISlider!
    @IBOutlet silpnas var frameWidthSlider: UISlider!
    @IBOutlet silpnas var frameHeightSlider: UISlider!
    @IBOutlet silpnos var ribosXSlider: UISlider!
    @IBOutlet silpnas gali ribotiYSlider: UISlider!
    @IBOutlet silpnos įvairios ribosWidthSlider: UISlider!
    @IBOletlet silpnos var boundsHeightSlider: UISlider!
    @IBOutlet silpnas var centreXSlider: UISlider!
    @IBOutlet silpnas var centreYSlider: UISlider!
    @IBOutlet silpnas var rotationSlider: UISlider!
 
    // Skaidrių veiksmai
    @IBAction func frameXSliderChanged (siuntėjas: AnyObject) {
        „myView.frame.origin.x = CGFloat“ („frameXSlider.value“)
        updateLabels ()
    }
    @IBAction func frameYSliderChanged (siuntėjas: AnyObject) {
        „myView.frame.origin.y = CGFloat“ („frameYSlider.value“)
        updateLabels ()
    }
    @IBAction func frameWidthSliderChanged (siuntėjas: AnyObject) {
        „myView.frame.size.width“ = „CGFloat“ („frameWidthSlider.value“)
        updateLabels ()
    }
    @IBAction funkcijos „frameHeightSliderChanged“ (siuntėjas: „AnyObject“) {
        „myView.frame.size.height = CGFloat“ („frameHeightSlider.value“)
        updateLabels ()
    }
    @IBAction „func boundsXSliderChanged“ (siuntėjas: „AnyObject“) {
        „myView.bounds.origin.x“ = „CGFloat“ („boundsXSlider.value“)
       updateLabels ()
    }
    @IBAction funkcijos ribosYSliderChanged (siuntėjas: AnyObject) {
        myView.bounds.origin.y = CGFloat („boundsYSlider.value“)
        updateLabels ()
    }
    @IBAction funkcijos ribosWidthSliderChanged (siuntėjas: AnyObject) {
        myView.bounds.size.width = CGFloat („boundsWidthSlider.value“)
        updateLabels ()
    }
    @IBAction funkcijos ribosHeightSliderChanged (siuntėjas: AnyObject) {
        myView.bounds.size.height = CGFloat („boundsHeightSlider.value“)
        updateLabels ()
    }
    @IBAction funkcijų centrasXSliderChanged (siuntėjas: AnyObject) {
        „myView.center.x = CGFloat“ („centreXSlider.value“)
        updateLabels ()
    }
    @IBAction func centreYSliderChanged (siuntėjas: AnyObject) {
        myView.center.y = CGFloat (centreYSlider.value)
        updateLabels ()
    }
    @IBAction func rotationSliderChanged (siuntėjas: AnyObject) {
        tegul rotation = CGAffineTransform (rotationAngle: CGFloat (rotationSlider.value))
        myView.transform = pasukimas
        updateLabels ()
    }
 
    „private func updateLabels“) () {
 
        frameX.text = „kadras x = \ (vidinis („ myView.frame.origin.x) “)“
        frameY.text = „frame y = \ (Int (myView.frame.origin.y))“
        frameWidth.text = „kadro plotis = \ (vidinis („ myView.frame.width “))“
        frameHeight.text = „kadro aukštis = \ (vidinis („ myView.frame.height “))“
        boundsX.text = „ribos x = \ (vidinis („ myView.bounds.origin.x) “)“
        boundsY.text = „ribojasi y = \ (vidinis („ myView.bounds.origin.y) “)“
        boundsWidth.text = “bounds plot = \ (Int (myView.bounds.width))”
        boundsHeight.text = „ribos aukštis = \ (vidinis („ myView.bounds.height) “)“
        centreX.text = „centras x = \ (vidinis („ myView.center.x) “)“
        centreY.text = „centras y = \ (vidinis („ myView.center.y) “)“
        rotation.text = „rotation = \ ((rotationSlider.value))“
 
    }
 
}