ماتريكس — هي فئة من Android SDK (android.graphics.Matrix) تمثل تحويلاً أفينياً عبر مصفوفة 3×3. تُستخدم لتحويل الكائنات الرسومية — النقل والقياس والتدوير والإمالة. وفقاً لوثائق مطوري أندرويد (2026)، تُعد ماتريكس الأداة الرئيسية للعمل مع التحويلات في Canvas وBitmap وDrawable، مما يوفر تحكماً دقيقاً في الإحداثيات عند الرسم المخصص.
النقاط الرئيسية
ماتريكس (android.graphics.Matrix) — هي فئة من Android SDK تمثل مصفوفة رياضية 3×3 تُستخدم لتحويل الإحداثيات ثنائية الأبعاد. تُعد ماتريكس اللبنة الأساسية لجميع التحويلات الرسومية في أندرويد — من تحريك Canvas وتغيير حجمه إلى التشوهات المنظورية المعقدة لـ Bitmap.
على عكس iOS، الذي يستخدم هياكل منفصلة CGAffineTransform (أفيني) وCATransform3D (ثلاثي الأبعاد)، يجمع أندرويد بين التحويلات الأفينية والمنظورية في فئة واحدة ماتريكس. تسمح المصفوفة 3×3 بتمثيل كل من العمليات الأفينية القياسية (الصف الأخير [0, 0, 1]) والتشوهات المنظورية عندما يحتوي الصف الأخير على قيم عشوائية. هذا يوفر مرونة أكبر ولكنه يتطلب فهم رياضيات المصفوفات.
ماتريكس مدمجة بإحكام مع واجهة Canvas API. عندما يستدعي المطور canvas.translate() أو canvas.scale() أو canvas.rotate()، تقوم هذه الطرق بتعديل مصفوفة السياق الرسومي داخلياً. يمكنك الحصول على مصفوفة Canvas الحالية عبر canvas.getMatrix() وتطبيق مصفوفة مخصصة يدوياً عبر canvas.setMatrix() أو canvas.concat().
ماتريكس تدعم أربعة أنواع أساسية من التحويلات الأفينية: translate، scale، rotate، skew (إمالة). لكل نوع طرق للضرب المسبق (pre) والضرب اللاحق (post) والتعيين (set). الفرق بين preTranslate وpostTranslate يكمن في ترتيب ضرب المصفوفات، مما يؤثر على التحويل النهائي عند دمج العمليات.
| العملية | الطريقة | المعلمات | الوصف |
|---|---|---|---|
| نقل | setTranslate / preTranslate / postTranslate | dx, dy | الإزاحة على طول المحورين X وY |
| قياس | setScale / preScale / postScale | sx, sy, px, py | القياس مع نقطة ارتكاز |
| تدوير | setRotate / preRotate / postRotate | degrees, px, py | التدوير حول نقطة ارتكاز |
| إمالة | setSkew / preSkew / postSkew | kx, ky | الإمالة (القص) على طول المحاور |
Translate يغير موضع جميع النقاط بإزاحة معينة dx, dy. dx موجب يحرك لليمين، dy — للأسفل (في نظام إحداثيات شاشة أندرويد، المحور Y يتجه للأسفل). Translate لا يغير شكل الكائن — فقط موضعه. هذه هي أبسط وأكثر العمليات استخداماً لتحديد موضع العناصر.
Scale يغير حجم كائن بعوامل sx (على X) وsy (على Y). تحدد المعلمات px, py نقطة ارتكاز القياس. إذا لم يتم تحديد px, py، يتم القياس بالنسبة لنقطة الأصل (0, 0). عندما sx = sy، يتغير حجم الكائن بشكل منتظم. القيم السالبة تنشئ انعكاساً.
Rotate يدور كائن بزاوية معينة (بالدرجات) حول نقطة ارتكاز (px, py). الدرجات الموجبة تقابل الدوران مع عقارب الساعة (على عكس iOS/macOS، حيث الزاوية الموجبة عكس عقارب الساعة). إذا لم يتم تعيين px, py، يتم الدوران حول نقطة الأصل.
Skew (القص) يشوه كائنًا بإمالته على طول المحور X (kx) أو المحور Y (ky). القيمة 1.0 تميل بزاوية 45 درجة. يُستخدم Skew لإنشاء تأثيرات الإمالة والمظهر شبه ثلاثي الأبعاد وتشويه المنظور.
ماتريكس تخزن عناصرها 3×3 في مصفوفة داخلية من 9 قيم فاصلة عائمة (float[9]). ترتيب التخزين هو عمودي رئيسي (column-major)، بما يتوافق مع التمثيل الرياضي القياسي. يتم الوصول إلى العناصر الفردية من خلال الثوابت: Matrix.MSCALE_X وMatrix.MSKEW_Y وMatrix.MTRANS_X وهكذا.
تم تنظيم المصفوفة على النحو التالي: العمودان الأولان (MSCALE_X, MSKEW_X, MSKEW_Y, MSCALE_Y) يتعاملان مع القياس والتدوير والإمالة. العمود الثالث (MTRANS_X, MTRANS_Y, MPERSP_2) يتعامل مع النقل والمنظور. للتحويلات الأفينية، MPERSP_0 وMPERSP_1 يساويان 0، وMPERSP_2 يساوي 1.
للحصول على قيم المصفوفة، استخدم getValues(float[] values)، الذي يملأ مصفوفة من 9 عناصر. لتعيينها، استخدم setValues(float[] values). هذا يسمح بالتلاعب المباشر بالمصفوفة للتحويلات المخصصة المعقدة التي تتجاوز الطرق القياسية translate وscale وrotate وskew.
ماتريكس توفر عدة طرق لتصنيف الحالة الحالية. isIdentity() يتحقق مما إذا كانت المصفوفة مصفوفة وحدة. isAffine() يتحقق مما إذا كانت تحتوي فقط على تحويلات أفينية (MPERSP_0 = 0, MPERSP_1 = 0, MPERSP_2 = 1). هذه الفحوصات مفيدة للتحسين: إذا كانت المصفوفة مصفوفة وحدة، يمكن تخطي التحويل.
ماتريكس تدعم عدة فئات من العمليات: التعيين (set)، الضرب المسبق (pre)، الضرب اللاحق (post)، التسلسل (concat)، الانعكاس (invert) والتخطيط (map). كل فئة تخدم غرضها عند بناء التحويلات المعقدة.
preTranslate يضرب المصفوفة الحالية من اليسار بمصفوفة النقل: result = translate × current. postTranslate يضرب من اليمين: result = current × translate. الفرق في ترتيب التطبيق: عمليات pre تُطبق قبل التحويلات الحالية، عمليات post تُطبق بعدها. نفس الشيء ينطبق على preScale، postScale، preRotate، postRotate وpreSkew، postSkew.
invert(Matrix inverse) يحسب المصفوفة العكسية. إذا كانت المصفوفة الأصلية شاذة (المحدد يساوي صفراً)، يُرجع false. concat(Matrix other) يضرب المصفوفة الحالية بالمصفوفة المعطاة: set = set × other. للترتيب العكسي، استخدم setConcat(other, this).
mapRect(RectF rect) يحول مستطيلاً ويعيد النتيجة في RectF جديد. mapPoints(float[] dst, float[] src) يحول مصفوفة من النقاط. mapVectors(float[] dst, float[] src) يحول المتجهات — دون مراعاة النقل. mapRect مفيد لحساب المربعات المحيطة (bounding boxes) بعد التحويل.
ماتريكس تُستخدم بنشاط في سيناريوهين رئيسيين لرسومات أندرويد: تحويل Canvas وتحويل Bitmap. في كلتا الحالتين، تحدد ماتريكس كيفية تعديل المخرجات الرسومية.
Canvas يوفر canvas.setMatrix(matrix) للاستبدال الكامل للمصفوفة الحالية وcanvas.concat(matrix) لضرب التحويل الحالي بالمعطى. بعد تطبيق ماتريكس، كل الرسم اللاحق — استدعاءات drawBitmap وdrawRect وdrawPath — يتم في نظام الإحداثيات المحول. Canvas يحتفظ أيضاً بمكدس الحالات المحفوظة الخاص به عبر save() وrestore().
Bitmap.createBitmap(Bitmap source, int x, int y, int width, int height, Matrix matrix, boolean filter) ينشئ Bitmap جديداً مع تطبيق التحويل المعطى. هذه أداة قوية لإنشاء نسخ مقاسة أو مدورة أو مشوهة من الصور دون فقدان Bitmap الأصلي. تتحكم معلمة filter في التنعيم أثناء استيفاء البكسل.
setPolyToPoly(float[] src, int srcIndex, float[] dst, int dstIndex, int pointCount) — قدرة فريدة لماتريكس ليس لها مقابل مباشر في CGAffineTransform. تحسب مصفوفة تحول نقاطاً معينة من مضلع إلى آخر. مع pointCount = 4، يتم إنشاء تحويل منظور (إسقاطي) كامل، مما يسمح بتراكب Bitmap مع تشويه منظور.
لنلقِ نظرة على أمثلة عملية لاستخدام ماتريكس لتحويل الرسومات في تطبيق أندرويد بلغة Kotlin.
المثال ينشئ ماتريكس لتحويل مدمج: نقل بمقدار (100, 50)، قياس بمقدار 1.5x وتدوير بزاوية 45 درجة. استخدام postTranslate بعد preRotate وpreScale يغير ترتيب تطبيق العمليات.
val matrix = Matrix()
matrix.preScale(1.5f, 1.5f)
matrix.preRotate(45f)
matrix.postTranslate(100f, 50f)
// التطبيق على النقاط
val pts = floatArrayOf(0f, 0f, 100f, 100f)
matrix.mapPoints(pts)
// التطبيق على المستطيل
val rect = RectF(0f, 0f, 200f, 100f)
matrix.mapRect(rect)
المثال يوضح تطبيق ماتريكس على Canvas في onDraw لتدوير وتغيير حجم دائرة حول مركزها. حفظ واستعادة حالة Canvas يضمن أن التحويل لا يؤثر على عناصر الرسم اللاحقة.
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
val cx = width / 2f
val cy = height / 2f
val radius = 100f
canvas.save()
val matrix = Matrix()
matrix.postTranslate(cx, cy)
matrix.postRotate(30f)
matrix.postScale(1.2f, 1.2f)
canvas.concat(matrix)
val paint = Paint().apply {
color = Color.BLUE
style = Paint.Style.FILL
}
canvas.drawCircle(0f, 0f, radius, paint)
canvas.restore()
}
المثال يستخدم setPolyToPoly لإنشاء تشويه منظور لـ Bitmap. أربع نقاط مصدر (زوايا المستطيل الأصلي) تُخطط إلى أربع نقاط هدف تشكل شبه منحرف. النتيجة هي تأثير صورة مائلة في الفضاء.
fun applyPerspective(
bitmap: Bitmap,
skew: Float
): Bitmap {
val w = bitmap.width.toFloat()
val h = bitmap.height.toFloat()
val src = floatArrayOf(0f, 0f, w, 0f,
0f, h, w, h)
val dst = floatArrayOf(skew, 0f, w - skew, 0f,
0f, h, w, h)
val matrix = Matrix()
matrix.setPolyToPoly(src, 0, dst, 0, 4)
return Bitmap.createBitmap(
bitmap, 0, 0,
w.toInt(), h.toInt(),
matrix, true
)
}
الأسئلة الشائعة
ماتريكس تعمل مع التحويلات الأفينية والمنظورية ثنائية الأبعاد من خلال مصفوفة واحدة 3×3. الكاميرا (android.graphics.Camera) هي فئة عالية المستوى تحاكي كاميرا ثلاثية الأبعاد: تنشئ دوراناً ثلاثي الأبعاد ثم تسقط النتيجة في ماتريكس ثنائية الأبعاد. الكاميرا تستخدم ماتريكس داخلياً.
أنشئ ماتريكس مع postRotate(90f) ومرره إلى Bitmap.createBitmap(original, 0, 0, w, h, matrix, true). لاحظ أنه عند التدوير بمقدار 90 درجة، فإن عرض وارتفاع النتيجة يتبادلان. للتدوير بزاوية عشوائية، قد يكون الاقتصاص ضرورياً لتجنب المناطق الفارغة.
استخدم matrix.invert(resultMatrix). يعيد الأسلوب true إذا كان الانعكاس ناجحاً ويكتب المصفوفة العكسية في resultMatrix. قد يكون الانعكاس مستحيلاً إذا كانت المصفوفة شاذة (مثلاً، عند قياس صفري). تحقق دائماً من القيمة المعادة.
pre تضرب التحويل الجديد من اليسار: result = operation × current — تُطبق العملية قبل التحويلات الحالية. post تضرب من اليمين: result = current × operation — تُطبق العملية بعدها. لتسلسل preRotate + postTranslate: أولاً التدوير، ثم النقل.
نعم، تُستخدم ماتريكس في Jetpack Compose من خلال فئة android.graphics.Matrix في التفاعل مع Canvas Compose. في Compose، graphicsLayer متاح للتحويلات (scale، rotationX، translationX وغيرها)، ولكن للتحويلات المعقدة لـ Bitmap، تُستخدم ماتريكس في كود drawWithContent أو drawBehind.
الملخص
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.