CGAffineTransform for beginners(in Burmese)

Kyaw Zay Ya Lin Tun
4 min readOct 14, 2021

--

Photo by Meagan Carsience on Unsplash

Overview

ဒီတစ်ခေါက်ကတော့ UIView တွေကို transform လုပ်ရာမှာအသုံးဝင်တဲ့ CGAffineTransform အကြောင်းကို ပြောပြပေးသွားပါမယ်။ CGAffineTransform ဆိုတဲ့ နာမည်အတိုင်း Core Graphic framework အောက်မှာရှိတဲ့ struct တစ်ခုဖြစ်ပါတယ်။ သင်္ချာရဲ့ affine transformation matrix တွေဆိုတာ တော်တော်လေးရှုပ်ထွေးပါတယ်။ ခင်ဗျားက အဲ့တာတွေကိုသိချင်ရင်တော့ ဒီ article က ခင်ဗျားအတွက်မဟုတ်ပါဘူး။ Apple က CGAffineTransform မှာ လွယ်လွယ်ကူကူနဲ့ affine transformation ရဲ့ power ကိုသုံးလို့ရအောင် api တွေပြင်ဆင်ပေးထားပါတယ်။ ရှေ့က animation article မှာလည်း ဒီ struct ကို သုံးခဲ့ဖူးပါတယ်။ ဒီ article မှာ လက်တွေ့အသုံးဝင်လောက်မယ်ထင်တဲ့ API တွေကို စုစည်းဖော်ပြပေးသွားပါမယ်။​

Getting started

ဒါကတော့ starter code ဖြစ်ပါတယ်။ ဒီ article အတိုင်းလိုက်လုပ်ချင်တယ်ဆိုရင် ဒီ code ကို ကူးထားလိုက်ပါ။

init(rotationAngle: CGFloat)

နာမည်အတိုင်းဘဲ view ကို angle အတိုင်း rotate ပေးတာပါ။ တစ်ခုသတိထားရမှာက “rotationAngle” က radian ကိုဘဲလက်ခံပါတယ်။ Degree ကို radian ပြန်ပြောင်းပေးရပါမယ်။

init(scaleX: CGFloat, y: CGFloat)

View ရဲ့ လက်ရှိ width, height အပေါ်မူတည်ပြီး scale လုပ်ပေးပါတယ်။

init(translationX: CGFloat, y: CGFloat)

View ရဲ့ parent view ထဲက coordinate system အပေါ်မမူတည်ဘဲ လက်ရှိရှိနေတဲ့ x-axis, y-axis တွေကနေ translate လုပ်ပေးပါတယ်။ ပြောချင်တာကတော့ CGAffineTransform ရဲ့ api တွေအားလုံးဟာ current view ရဲ့ properties တွေ position တွေအပေါ်မူတည်ပြီးတော့ဘဲ transform လုပ်တယ်ဆိုတာ သတိပြုမိဖို့ပါ။

Figure I ကိုကြည့်မယ်ဆိုရင် square box ကို (30, 60) positions တွေမှာ render လုပ်ထားတာကိုတွေ့ရပါတယ်။ ဒါက CGAffineTransform မသုံးရသေးတဲ့ initial position in the parent coordinate system လို့ မြင်ကြည့်ပါ။ အဲ့လိုဆိုရင် translation တန်ဖိုးတွေက (0, 0) ဖြစ်နေပါလိမ့်မယ်။ Figure II မှာ translation (30, 20) လုပ်လိုက်ပါပြီ။​ အဲ့အခါမှာ parent coordinate system ရဲ့ position (30, 60) ကနေမှ ထပ်ပြီး (x: 30, y: 20) ထပ်ပေါင်းလိုက်တာကိုတွေ့ရပါမယ်။ အဲ့အခါမှာ parent coordinate system ကနေကြည့်မယ်ဆိုရင်တော့ (x: 60, y: 80) ဖြစ်သွားပါပြီ။ ဒါပေမယ့် transformation ကတော့ box ရဲ့ သူ့ coordinate system (which is always 0, 0) အပေါ်မှာမှ transform လုပ်တယ်ဆိုတာကို နားလည်ထားဖို့လိုပါတယ်။ Rotate လုပ်တာ၊ scale လုပ်တာတွေလည်း ဒီပုံစံအတိုင်းပါဘဲ။​ လက်ရှိ view ရဲ့ properties တွေအပေါ်ကိုဘဲမူတည်ပြီး transform လုပ်ပါတယ်။ Translation မှာပိုမြင်သာမယ်လို့ထင်ပါတယ်။

CGAffineTransform.identity

View တစ်ခုရဲ့ transform value ကို “CGAffineTransform.identity” ဒါမှမဟုတ် “.identity” လို့ပေးလိုက်တာနဲ့တစ်ပြိုင်နက် ရှေ့မှာသတ်မှတ်ခဲ့သမျှ transform value တွေအကုန်လုံးကို reset လုပ်ပေးပြီးတော့ view ရဲ့မူလ initial state ကိုပြန်ရောက်သွားမှာဖြစ်ပါတယ်။ ဒါ့အပြင် “transform.isIdentity” ဆိုတဲ့ properties နဲ့ လက်ရှိ view က transform လုပ်ထားတာလား သူ့ initial state အတိုင်းရှိနေတာလားဆိုတာကို check လို့ရပါတယ်။ ဒီအပေါ်မူတည်ပြီး ကျွန်တော်တို့ ဉာဏ်ရှိသလို animation တွေလုပ်လို့ရပါတယ်။ သိထားရင် တစ်ကယ်အသုံးဝင်တဲ့ property တစ်ခုဖြစ်ပါတယ်။

Concatenating another transform

ကျွန်တော်တို့ view ကို rotate လည်းလုပ်မယ် scale လည်းလုပ်မယ်ဆိုတာမျိုး ကြုံလာနိုင်ပါတယ်။ အဲ့လိုအခါမျိုးမှာ transform object ကို နောက်ထပ် transform object နဲ့ concatenate လုပ်လို့ရပါတယ်။

Concatenate ကတော့ transform နှစ်ခုကိုပေါင်းချင်တဲ့အခါမှသာ သုံးကြတာများပါတယ်။ ပုံမှန် scale လည်းလုပ် rotate လည်းလုပ်မယ်ဆိုတဲ့အခါမျိုးမှာ method chaining ပုံစံနဲ့လည်းသွားလို့ရပါတယ်။

Anchor points

CGAffineTransform ကိုအသုံးပြုပြီး animation တွေကိုလုပ်တဲ့အခါမှာ အင်မတန်ရိုးရှင်းပါတယ်။ ဒါပေမယ့် သတိထားရမှာတစ်ခုရှိနေပါတယ်။ အဲ့တာကတော့ animation တွေအားလုံးက center point ကနေစတင်ပြီးလုပ်ဆောင်တာဖြစ်ပါတယ်။

အပေါ်က screen ကိုကြည့်မယ်ဆိုရင် box ကို scale လုပ်တဲ့နေရာမှာ center ကနေ scale လုပ်သွားတာဖြစ်ပါတယ်။ ကျွန်တော်တို့က box ရဲ့ top position ကနေ scale လုပ်ချင်တယ်ဆိုတာမျိုးရှိလာနိုင်ပါတယ်။ ဒီလိုအခြေအနေမှာ anchor point ကိုသတ်မှတ်ပေးလို့ရပါတယ်။​ ဒါပေမယ့် anchor point ကထင်သလောက်မရိုးရှင်းပါဘူး။ ကျွန်တော်တို့ anchor point အကြောင်းကို သေချာလေ့လာကြည့်ကြပါမယ်။

အပေါ်ကပုံကိုကြည့်မယ်ဆိုရင် anchor point တွေက 0 ကနေ 1 အထိဘဲရှိတာကိုတွေ့ရမှာပါ။ ကျွန်တော်တို့လုပ်ရမှာကတော့ default anchor point (0.5, 0.5) ကနေ (0.5, 0) ဖြစ်အောင်ပြောင်းပေးဖို့ပါဘဲ။ Anchor point ကိုပြောင်းတာကလည်းလွယ်ပါတယ်။

Scale transform မလုပ်ခင်လေးမှာ အပေါ်က code ကိုရေးထည့်လိုက်ရင်ရပါပြီ။ ဒါပေမယ့် ကျွန်တော်ပြောခဲ့သလိုဘဲ anchor point ကမရိုးရှင်းပါဘူး။​အဲ့အတိုင်း run လိုက်ရင် အောက်ပါအတိုင်းတွေ့ရပါမယ်။

မြင်တဲ့အတိုင်း ကျွန်တော်တို့ရဲ့ box က top ကနေ scale လုပ်သွားပေမယ့် y position ကလည်း အောက်ကိုကျသွားပါတယ်။​ ဒါကဘာကြောင့်လဲဆိုတော့ ကျွန်တော်တို့ထင်နေတာက anchor point ကို ပြောင်းလိုက်ရင် ကျွန်တော်တို့ရဲ့ anchor point ကနေရာရွေ့သွားမယ်လို့ထင်နေတာပါ။ တစ်ကယ်တော့ anchor point ကဘယ်တော့မှ မရွေ့ပါဘူး။ တစ်ကယ်ရွေ့နေတာက anchor point အပေါ်လိုက်ပြီး view ကရွေ့နေတာပါ။ အခုကျွန်တော်တို့ သူ့ရဲ့ anchor point y value ကို 0.5 ကနေ 0 ပြောင်းလိုက်ပါပြီ။ အဲ့တာဆိုရင် ကျွန်တော်တို့ view ရဲ့ center y position ကိုလည်း 50% top ကိုပြန်တိုးပေးမှ scaling position မှန်ပါမယ်။

အပေါ်က code ကိုကြည့်မယ်ဆိုရင် box ရဲ့ center y value ကို အပေါ်ကို တစ်ဝက်ပြန်တိုးထားတာ တွေ့ရပါမယ်။ ဒီနေရာမှာသဘောမပေါက်သေးဘူးဆိုရင် x,y axis အမျိုးမျိုးနဲ့ ကိုယ့်ဘာသာပြန်စမ်းကြည့်ဖို့ တိုက်တွန်းလိုပါတယ်။

ဒါပေမယ့်လည်း ကျွန်တော်တို့ရဲ့ပြသနာကမပြီးသေးပါဘူး။​ ကျွန်တော့်ရဲ့ anchor point section က code ကိုကြည့်လိုက်မယ်ဆိုရင် ကျွန်တော်က box ကို tap လုပ်တာနဲ့ scale မလုပ်ရသေးရင် scale လုပ်ပြီး 2x scale လုပ်ထားပြီးရင်တော့ identity matrix ကို reset ပြန်လုပ်ထားတာကို တွေ့ရပါမယ်။ အခုလက်ရှိကျွန်တော်ရေးထာတာအရဆိုရင် view ကို 2x scale လုပ်တဲ့အခါတိုင်းမှာ y position က အပေါ်ကို view height ရဲ့ 50% တက်တက်သွားပါလိမ့်မယ်။ အဲ့တာကိုကာကွယ်ဖို့အတွက် identity matrix အဖြစ် reset လုပ်တဲ့အချိန်မှာ box ရဲ့ မူရင်း center y value နဲ့ default anchor point ကိုလည်းပြန် reset လုပ်ပေးဖို့လိုပါတယ်။

ဒါကတော့ final code ဖြစ်ပါတယ်။ ဒါကို run ကြည့်မယ်ဆိုရင်တော့ ကျွန်တော်တို့လိုချင်တဲ့အတိုင်း အလုပ်လုပ်သွားတာကိုတွေ့ရမှာပါ။

ဒါကတော့ ကျွန်တော်က သူ့ရဲ့နောက်ကွယ်က အလုပ်လုပ်ပုံကို solid သိစေချင်လို့ ရှင်းပြပေးထားတာဖြစ်ပါတယ်။ Anchor point တွေကို သုံးရပိုလွယ်အောင် Paul Hudson က UIView extension တစ်ခုရေးပေးထားပါတယ်။ နောက်ကွယ်ကအလုပ်လုပ်ပုံကိုသိပြီဆိုရင်တော့ Hacking with swift မှာ သူ့ရဲ့ extension ကိုအသင့်သွားယူသုံးလို့ရပါတယ်။

Conclusion

ဒီတစ်ခေါက်မှာတော့ UIView animation တွေလုပ်ရာမှာ အသုံးဝင်တဲ့ CGAffineTransform အကြောင်းကို ပြောပြပေးခဲ့တာဖြစ်ပါတယ်။ ဒါအကုန်လားဆိုတော့ မဟုတ်သေးပါဘူး။ နောက်မှာ rotation matrix တွေကိုသုံးပြီး trigonometric angle တွေနဲ့ skew လုပ်တဲ့အပိုင်းတစ်ပိုင်းကျန်ပါသေးတယ်။ အဲ့တာကတော့ affine transformation နဲ့ trigonometric function တွေအကြောင်း သေချာသိထားရမှာမို့လို့ advance article အနေနဲ့သပ်သပ်ထပ်ရေးသွားပါဉီးမယ်။

--

--

Kyaw Zay Ya Lin Tun
Kyaw Zay Ya Lin Tun

Written by Kyaw Zay Ya Lin Tun

Lead iOS Dev @CodigoApps • Programming Mentor • Swift enthusiast • Community Builder • Organising CocoaHeads Myanmar 🇲🇲

No responses yet