بعد أن رأيت حديثًا حول Android Jetpack Compose على Google IO 2019 ، أردت أن أجربه على الفور. علاوة على ذلك ، فإن النهج الذي تم تنفيذه فيه يذكرنا بشدة بـ " رفرفة" ، والذي كنت مهتمًا به سابقًا .

توجد مكتبة "إنشاء" نفسها في مرحلة ما قبل ألفا ، لذا لا تتوفر الكثير من الوثائق والمقالات المتعلقة بها. بعد ذلك ، سأعتمد على العديد من الموارد التي تمكنت من العثور عليها ، بالإضافة إلى مكتبة المصادر المفتوحة .
هذه الموارد هي:
ما هو الروبوت Jetpack يؤلف؟
في السابق ، كان نظام Android UI بأكمله يعتمد على فئة العرض. كان هذا هو الحال منذ الأيام الأولى لنظام Android. وفي هذا الصدد ، تراكمت العديد من العيوب القديمة والمعمارية ، والتي يمكن تحسينها. لكن القيام بذلك أمر صعب للغاية دون كسر جميع الشفرات المكتوبة على أساسها.
في السنوات الأخيرة ، ظهرت الكثير من المفاهيم الجديدة في عالم تطبيقات العملاء (بما في ذلك اتجاهات Frontend) ، لذلك سلك فريق Google طريقة جذرية وأعاد كتابة مستوى واجهة المستخدم بالكامل في Android من الصفر. لذا ظهرت مكتبة Android Jetpack Compose ، والتي تتضمن الحيل المفاهيمية من React و Litho و Vue و Flutter وغيرها الكثير.
دعنا نذهب من خلال بعض ميزات واجهة المستخدم الحالية ومقارنتها مع تكوين.
1. الاستقلال عن إصدارات أندرويد
ترتبط واجهة المستخدم الحالية ارتباطًا وثيقًا بالمنصة. عندما ظهرت المكونات الأولى لتصميم المواد ، فإنها تعمل فقط مع Android 5 (API21) والإصدارات الأحدث. للعمل على الإصدارات القديمة من النظام ، يجب عليك استخدام مكتبة الدعم.
يعد Compose جزءًا من Jetpack ، مما يجعله مستقلًا عن إصدارات النظام ويمكن استخدامه حتى في الإصدارات القديمة من Android (على الأقل مع API21).
2. كامل Kotlin API
في السابق ، كان عليك التعامل مع ملفات مختلفة لإنشاء واجهة مستخدم. وصفنا الترميز بلغة xml ، ثم استخدمنا كود Java / Kotlin لجعله يعمل. ثم عدنا إلى ملفات xml أخرى من أجل تعيين السمات والرسوم المتحركة والملاحة ... وحتى حاولنا كتابة التعليمات البرمجية في xml (ربط البيانات).
يتيح لك استخدام Kotlin أن تكتب واجهة مستخدم نمطية تعريفية مباشرةً في الكود بدلاً من xml.
3. مركب = مركب: استخدام التكوين بدلا من الميراث
يمكن أن يكون إنشاء عناصر واجهة مستخدم مخصصة مرهقًا إلى حد ما. نحتاج إلى أن نرث من طريقة العرض أو سليلها وأن نعتني بالعديد من الخصائص المهمة قبل أن تبدأ بشكل صحيح. على سبيل المثال ، تحتوي فئة TextView على حوالي 30 ألف سطر من تعليمات Java البرمجية. هذا يرجع إلى حقيقة أنه يحتوي على الكثير من المنطق غير الضروري داخل نفسه الذي ورثته العناصر المنحدرة.
تأليف جاء من ناحية أخرى ، لتحل محل الميراث مع التكوين.
Padding
هو الأنسب لتوضيح ما يدور حوله:
في واجهة المستخدم الحالية ، من أجل تقديم TextView
بادئة في 30dp
:
نحتاج إلى كتابة الكود التالي:
<TextView android:id="@+id/simpleTextView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@color/cyan" android:padding="30dp" <------------------------ NOTE THIS android:text="Drag or tap on the seek bar" />
هذا يعني أنه في مكان ما داخل TextView.java أو الفئات الفائقة ، يوجد منطق يعرف كيفية حساب المسافات البادئة ورسمها.
دعونا نرى كيف يمكنك أن تفعل الشيء نفسه في يؤلف:
التغييرات
أصبح TextView
مجرد Text()
. تحولت خاصية android:padding
إلى التفاف Text
.
الفوائد
وبالتالي ، Text
هو المسؤول فقط عن تقديم النص نفسه. انه لا يعرف كيفية حساب المسافات البادئة. Padding
، من ناحية أخرى ، مسؤولة فقط عن الحشو وليس أكثر من ذلك. يمكن استخدامه حول أي عنصر آخر.
4. دفق البيانات أحادي الاتجاه
يعد تدفق البيانات أحادي الاتجاه مفهومًا مهمًا إذا تحدثنا ، على سبيل المثال ، عن التحكم في حالة CheckBox
في نظام واجهة مستخدم موجود. عندما ينقر المستخدم على CheckBox
، يتم checked = true
حالته checked = true
: يقوم الفصل بتحديث حالة العرض ويستدعي رد اتصال من الكود الذي يراقب تغيير الحالة.
ثم ، في الكود نفسه ، على سبيل المثال ، في ViewModel
، تحتاج إلى تحديث متغير state
المقابل. لديك الآن نسختان من الحالة المضغوطة ، والتي يمكن أن تخلق مشاكل. على سبيل المثال ، سيؤدي تغيير قيمة متغير state
داخل ViewModel
CheckBox
تحديث CheckBox
، والذي قد ينتهي بحلقة لا نهاية لها. لتجنب ذلك ، سيتعين علينا التوصل إلى نوع من العكازات.
سيساعد استخدام "إنشاء" في حل هذه المشكلات ، لأنه يعتمد على مبدأ الضبط الواحد. ستتم معالجة تغيير الحالة داخل الإطار: نحن ببساطة نعطي نموذج البيانات إلى الداخل. بالإضافة إلى ذلك ، لا يغير المكون في إعداد الآن حالته من تلقاء نفسه. بدلاً من ذلك ، يستدعي رد الاتصال فقط ، والآن هي مهمة التطبيق لتغيير واجهة المستخدم.
5. تحسين تصحيح الأخطاء
منذ كتابة واجهة المستخدم بأكملها الآن في Kotlin ، يمكنك الآن تصحيح واجهة المستخدم. لم أحاول ذلك بنفسي ، لكن في البودكاست قالوا إن مصحح الأخطاء ونقاط التوقف تعمل في الإنشاء.
كلمات كافية ، وإظهار الرمز
أعلم ، أريد أن أرى بسرعة شكل واجهة المستخدم في الشفرة (المفسد: تشبه إلى حد كبير Flutter إذا حاولت الكتابة عليه).
سنبدأ بإنشاء بعض View
البسيطة ، ثم نقارن كيف تبدو في واجهة المستخدم الحالية وفي الإنشاء.
1. FrameLayout
مقابل Wrap + Padding + Background
نعيد استخدام مثالنا أعلاه ونحاول جعل TextView
البادئة في 30dp
مع خلفية فيروزية:
واجهة المستخدم الحالية:
<TextView android:id="@+id/simpleTextView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@color/cyan" <-------------- NOTE THIS android:padding="30dp" <------------------------ AND THIS android:text="Drag or tap on the seek bar" />
الآن انظر إلى الكود الذي يفعل الشيء نفسه في إنشاء:
@Composable fun MyText() { Wrap { Padding(30.dp) { DrawRectangle(color = Color.Cyan) Text("Drag or tap on the seek bar") } } }
إليك بعض الأشياء الجديدة. نظرًا لأن Text
يعرف فقط تقديم النص ، فإنه لا يهتم بالحشو والخلفية. لذلك ، لإضافتها ، نحتاج إلى استخدام ثلاث وظائف منفصلة:
DrawRectangle
الخلفية- المسافات البادئة
Padding
Wrap
هي وظيفة FrameLayout
معلمات مثل FrameLayout
.
بسهولة. لكن الأمر يختلف قليلاً عن نظام واجهة المستخدم الحالي الذي اعتدنا عليه جميعًا.
2. عمودي LinearLayout
مقابل Column
الآن دعونا نحاول أن نفعل شيئًا معادلًا لـ LinearLayout
القديم الجيد.
لوضع عنصرين أسفل أحدهما الآخر ، كما في الصورة أدناه ، يمكننا استخدام Column
:
سيبدو الرمز كالتالي:
@Composable fun FormDemo() { Column(crossAxisAlignment = CrossAxisAlignment.Start) { Text("Click the button below: ") Button(text = "Next") } }
متداخلة في عنصر Column
سوف يكون موجودا رأسيا واحد تحت الآخر.
2A. المسافات البادئة
ربما لاحظت أن النص والزر قريبان جدًا من الحافة. لذلك ، إضافة Padding
.
@Composable fun FormDemo() { Padding(10.dp) {
يبدو أفضل:
2B. فترات
يمكننا أيضًا إضافة بعض المسافة البادئة بين Text
Button
:
@Composable fun FormDemo() { Padding(10.dp) { Column(crossAxisAlignment = CrossAxisAlignment.Start) { Text("Click the button below: ") HeightSpacer(10.dp)
كيف تبدو شاشتنا الآن:
2C. أفقي LinearLayout
مقابل Row
ضع الزر الثاني بجانب الأول:
رمز لهذا:
@Composable fun FormDemo() { Padding(10.dp) { Column(crossAxisAlignment = CrossAxisAlignment.Start) { Text("Click the button below: ") HeightSpacer(10.dp) Row {
داخل Row
سيكون الزرين أفقيًا. يضيف WidthSpacer
المسافة بينهما.
2D. Gravity
مقابل Alignment
قم بمحاذاة عناصرنا في الوسط ، كما تفعل gravity
في واجهة المستخدم الحالية. لإظهار الفرق ، سأعلق على الخطوط القديمة وأستبدلها بخطوط جديدة:
@Composable fun FormDemo() { Padding(10.dp) {
سننجح:
باستخدام crossAxisAlignment = CrossAxisAlignment.Center
سيتم crossAxisAlignment = CrossAxisAlignment.Center
العناصر المتداخلة أفقياً. يجب علينا أيضًا تعيين معلمة Row
على mainAxisSize = FlexSize.Min
، تشبه في السلوك layout_width = wrap_content
، بحيث لا تمتد عبر الشاشة بسبب mainAxisSize = FlexSize.Max
، والذي يتصرف مثل layout_width = match_parent
.
2D. تعليق
من خلال ما رأيناه في الأمثلة أعلاه ، يمكنك أن ترى أن جميع العناصر مدمجة في مركب من وظائف منفصلة: padding
وظيفة منفصلة ، spacer
هو وظيفة منفصلة ، بدلاً من أن تكون خصائص داخل Text
أو Button
أو Column
.
هناك عناصر أكثر تعقيدًا مثل RecyclerView
أو ConstraintLayout
قيد التطوير: لذلك ، لم أجد مثالًا معهم في المصادر التجريبية.
3. الأنماط والسمات
ربما لاحظت أن الأزرار أعلاه أرجوانية بشكل افتراضي. هذا لأنهم يستخدمون الأنماط الافتراضية. دعونا نرى كيف تعمل الأنماط في تكوين.
في الأمثلة أعلاه ، FormDemo
وضع علامة @Composable
مع تعليق توضيحي @Composable
. الآن سأوضح كيف يتم استخدام هذا العنصر في Activity
:
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { CraneWrapper{ MaterialTheme { FormDemo() } } } }
بدلاً من وظيفة setContentView()
، نستخدم setContent()
، وهي وظيفة امتداد من مكتبة Compose.kt
.
يحتوي CraneWrapper
على شجرة الإنشاء ويوفر الوصول إلى Context
Density
و FocusManager
و TextInputService
.
MaterialTheme
يسمح لك لتخصيص سمة للعناصر.
على سبيل المثال ، يمكنني تغيير اللون الأساسي للموضوع إلى اللون البني كما يلي:
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { CraneWrapper{
الآن ستبدو شاشتنا كما يلي:
الألوان والخطوط الأخرى التي يمكن تغييرها: MaterialTheme.kt # 57
يوفر نشاط Rally مثالاً جيدًا على كيفية تخصيص موضوع: شفرة المصدر إلى RallyTheme.kt
ماذا ترى / تقرأ
إذا كنت تريد المزيد ، فيمكنك تجميع مشروع العينة وفقًا للتعليمات الموضحة هنا .
بينما يكتب مستخدمو Windows ، الآن لا توجد طريقة رسمية لإطلاق "إنشاء" ، ولكن يوجد دليل غير رسمي من kotlinlang Slack .
يمكن طرح الأسئلة حول "إنشاء" للمطورين في قناة #compose
kotlinlang Slack.
اترك روابط أخرى في التعليقات - سيتم إضافة أكثرها فائدة هنا.
النتائج
تم تطوير هذه المكتبة على قدم وساق ، لذا فإن أي واجهات معروضة هنا عرضة للتغيير. لا يزال هناك الكثير من الأشياء التي يمكنك التعرف عليها في التعليمات البرمجية المصدر ، مثل @Model
وتدفق البيانات أحادي الاتجاه (دفق البيانات أحادي الاتجاه). ربما هذا موضوع للمقالات المستقبلية.