أندرويد Jetpack يؤلف الانطباع الأول

بعد أن رأيت حديثًا حول 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 أو الفئات الفائقة ، يوجد منطق يعرف كيفية حساب المسافات البادئة ورسمها.


دعونا نرى كيف يمكنك أن تفعل الشيء نفسه في يؤلف:


 // note: the cyan background color is omitted for now to keep it simple Padding(30.dp) { Text("Drag or tap on the seek bar") } 

التغييرات
أصبح 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` المسافة البادئة في` 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) { //   Column(crossAxisAlignment = CrossAxisAlignment.Start) { Text("Click the button below: ") Button(text = "Next") } } } 

يبدو أفضل:


عنصرين المسافة البادئة

2B. فترات


يمكننا أيضًا إضافة بعض المسافة البادئة بين Text Button :


 @Composable fun FormDemo() { Padding(10.dp) { Column(crossAxisAlignment = CrossAxisAlignment.Start) { Text("Click the button below: ") HeightSpacer(10.dp) //    Button(text = "Next") } } } 

كيف تبدو شاشتنا الآن:


عنصرين ، واحد يأخذ الآخر ، المسافة البادئة والمتباعدة

2C. أفقي LinearLayout مقابل Row


ضع الزر الثاني بجانب الأول:


إضافة الزر الثاني

رمز لهذا:


 @Composable fun FormDemo() { Padding(10.dp) { Column(crossAxisAlignment = CrossAxisAlignment.Start) { Text("Click the button below: ") HeightSpacer(10.dp) Row { //   Button(text = "Back") //   WidthSpacer(10.dp) //    Button(text = "Next") } } } } 

داخل Row سيكون الزرين أفقيًا. يضيف WidthSpacer المسافة بينهما.


2D. Gravity مقابل Alignment


قم بمحاذاة عناصرنا في الوسط ، كما تفعل gravity في واجهة المستخدم الحالية. لإظهار الفرق ، سأعلق على الخطوط القديمة وأستبدلها بخطوط جديدة:


 @Composable fun FormDemo() { Padding(10.dp) { // Column(crossAxisAlignment = CrossAxisAlignment.Start) { Column(crossAxisAlignment = CrossAxisAlignment.Center) { //  Text("Click the button below: ") HeightSpacer(10.dp) // Row { Row(mainAxisSize = FlexSize.Min) { //    Button(text = "Back") WidthSpacer(10.dp) Button(text = "Next") } } } } 

سننجح:


المحاذاة المركزية

باستخدام 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 { MaterialTheme(colors = MaterialColors(primary = Color.Maroon)) { FormDemo() } } } } 

الآن ستبدو شاشتنا كما يلي:


المارون كما اللون الأساسي

الألوان والخطوط الأخرى التي يمكن تغييرها: MaterialTheme.kt # 57


يوفر نشاط Rally مثالاً جيدًا على كيفية تخصيص موضوع: شفرة المصدر إلى RallyTheme.kt


ماذا ترى / تقرأ


إذا كنت تريد المزيد ، فيمكنك تجميع مشروع العينة وفقًا للتعليمات الموضحة هنا .


بينما يكتب مستخدمو Windows ، الآن لا توجد طريقة رسمية لإطلاق "إنشاء" ، ولكن يوجد دليل غير رسمي من kotlinlang Slack .


يمكن طرح الأسئلة حول "إنشاء" للمطورين في قناة #compose kotlinlang Slack.


اترك روابط أخرى في التعليقات - سيتم إضافة أكثرها فائدة هنا.


النتائج


تم تطوير هذه المكتبة على قدم وساق ، لذا فإن أي واجهات معروضة هنا عرضة للتغيير. لا يزال هناك الكثير من الأشياء التي يمكنك التعرف عليها في التعليمات البرمجية المصدر ، مثل @Model وتدفق البيانات أحادي الاتجاه (دفق البيانات أحادي الاتجاه). ربما هذا موضوع للمقالات المستقبلية.

Source: https://habr.com/ru/post/ar461101/


All Articles