CGAffineTransformation ja UI elementit

Affiinit kuvaukset ovat käytännössä pakon sanelemina tuttuja kaikille 3D grafiikkaohjelmointia harrastaneille mutta ne ovat aivan yhtä hyodyllisiä (joskaan eivät samalla tavalla edellytys) tasossa toimiessa. iOS:n Cocoa Touch tarjoaa useita tapoja manipuloida UIView:ien (jokaisen näkyvän UI widgetin kantaluokka) paikkaa; framen sijainnin muuttaminen taitaa olla päivittäisessa käytössä yleisin tapa ja se onkin riittävä ja oikea valinta suurimpaan osaan tapauksia.Mutta jos elementtejä halutaan skaalata tai kiertää (rotate), tarvitaan muita konsteja.

CGAffineTransformation esittää 3×3 matriisia jolla tason (2D) affiinit kuvaukset voidaan esittää. UIView luokalla on transformation niminen property, jonka animoitavuus tekee affiineista kuvauksista erittäin voimakkaan työkalun. Esimerkiksi UIView:n siirtäminen koordinaatteihin (tx,ty) tapahtuu CGAffineTransformation:n avulla seuraavasti:

CGAffineTransform transform = CGAffineTransformMakeTranslation(tx, ty);
view.transform = transform;

Jos on tottunut siirtelemään elementtejä muokkaamalla framen sijaintia, kannattaa huomioida että CGAffineTransformation:lla tehtävät siirrot (translation) kohdistuvat elementin keskipisteeseen eivätkä esim. sen vasempaan yläkulmaan.

Kuvauksia voi (ja pitää) yhdistää; usean operaation lopputulos mahtuu yhteen samaan kuvausmatriisiin sen ominaisuuksien vuoksi. Eri kuvausmatriisit kerrotaan yhteen oikeassa järjestyksessä ja lopputuloksella “kuvataan” (transform, v.)  elementti uuteen sijaintiin, skaalaan ja/tai orientaatioon. Esimerkiksi voidaan yhdistää translate – scale – rotate:

CGAffineTransform transform = CGAffineTransformIdentity;
transform = CGAffineTransformTranslate(transform, tx, ty);
transform = CGAffineTransformScale(transform, kScaleFactor, kScaleFactor);
transform = CGAffineTransformRotate(transform, kRotationAngle * M_PI / 180.0);
view.transform = transform;

Kuten aina affiinien kuvausten kanssa, on huomioitava operaatioiden järjestys; translaatio ensin, rotaatio sitten -järjestys siirtää kappaletta origosta ja sen jälkeen kiertää sitä kehää pitkin; rotaatio ensin, translaatio sitten -järjestys kiertää kappaletta oman keskipisteensä ympäri ja sen jälkeen siirtää kappaletta uuteen paikkaansa.

Esimerkkitoteutus

Ohessa yksinkertainen single-view sovellus joka pyrkii esittelemään yllä läpikäydyn asian joustavuuden ja voiman visualisoimalla ristinollaruudukon ja 5 kpl kumpaakin pelimerkkia O / X; koskettamalla pelimerkkiä kyseinen merkki tarttuu mukaan ja sille tehdään pieni skaalaus / rotaatio ihan vain demonstraation takia. Kaikki kappaleen manipulaatio tehdään CGAffineTransformation:lla.

Esimerkkisovelluksen ruutukaappaus
Esimerkkisovelluksen ruutukaappaus

Esimerkkisovelluksen lähdekoodi Xcode projektina (42kB)

 

 

 

 

 

 

ps. jos termi “affiini kuvaus” tuntuu kryptiseltä niin käytännössä sen määritelmä on että kys. operaatiossa “kuvattava” eli transformoitava kappale ei muuta mittasuhteitaan tai muotoaan; neliö pysyy neliönä niin sitä siirrettäessä, skaalatessa kuin kierrettäessäkin.

Lisää aiheesta