أخيرًا ، لقد حان الوقت عندما لا تحتاج إلى إنشاء Android Studio بنفسك لتجربة إطار واجهة المستخدم التعريفي الجديد لنظام Android. يتوفر Jetpack Compose الآن كأول معاينة Dev على مستودع Google Maven. مع هذا الخبر ، بدأ صباح الاثنين. وعلى الفور ، كانت هناك رغبة لمعرفة مجموعة الأدوات التي كانوا ينتظرونها.

قررت أن أبدأ معرفتي فورًا بمحاولة إدخالها في مشروع الحيوانات الأليفة المنشور على Google Play. علاوة على ذلك ، في ذلك لفترة طويلة كنت أرغب في إنشاء صفحة "حول التطبيق". في هذه المقالة سوف أتحدث عن المكونات الرئيسية وخطوات الاتصال من إعداد:
- اتصال التبعية
- الموضوعات والأساليب. التكامل مع الموجودة في المشروع.
- اختبارات إمكانية الوصول وواجهة المستخدم.
- المكونات الرئيسية ونظائرها من مشاهدة الورثة.
- العمل مع الدولة.
اتصال التبعية
للبدء ، قمت بتحديث الاستوديو من 3.5 إلى 3.5.1 (دون جدوى) ، وأضاف التبعيات الأساسية. يمكن رؤية قائمة كاملة في مقالة كتبها سيريل .
// build.gradle ext.compose_version= '0.1.0-dev01' //build.gradle dependencies{ ... implementation "androidx.compose:compose-runtime:$compose_version" kapt "androidx.compose:compose-compiler:$compose_version" implementation "androidx.ui:ui-layout:$compose_version" implementation "androidx.ui:ui-android-text:$compose_version" implementation "androidx.ui:ui-text:$compose_version" implementation "androidx.ui:ui-material:$compose_version" }
ثم حاولت جمع كل هذا بسبب الإصدارات المشتتة من Firebase. بعدها واجهت عقبات:
app/src/main/AndroidManifest.xml Error: uses-sdk:minSdkVersion 16 cannot be smaller than version 21 declared in library [androidx.ui:ui-layout:0.1.0-dev01] .../ui-layout-0.1.0-dev01/AndroidManifest.xml as the library might be using APIs not available in 16 Suggestion: use a compatible library with a minSdk of at most 16, or increase this project's minSdk version to at least 21, or use tools:overrideLibrary="androidx.ui.layout" to force usage (may lead to runtime failures)
نعم ، لم يكن الإنشاء متاحًا إلا مع minSdk 21 (Lolipop). ربما يكون هذا إجراءً مؤقتًا ، لكن كان من المتوقع دعم الإصدارات السابقة من نظام التشغيل.
لكن هذا ليس كل شيء. يؤلف أعمال على Reflection ، بدلاً من Kotlin Compiler Plugin ، كما ذكر سابقًا ، على سبيل المثال ، هنا . لذلك ، لكي تبدأ كل شيء ، تحتاج إلى إضافة Kotlin Reflect أيضًا وفقًا لما يلي:
implementation "org.jetbrains.kotlin:kotlin-reflect"
حسنا ، للحلوى. يؤلف dp بتنفيذ وظائف الامتداد لـ Int ، Long ، Float ، والتي تحمل علامة أساسية مضمّنة. قد يتسبب هذا خطأ ترجمة جديد:
Cannot inline bytecode built with JVM target 1.8 into bytecode that is being built with JVM target 1.6. Please specify proper '-jvm-target' option * https://stackoverflow.com/questions/48988778/cannot-inline-bytecode-built-with-jvm-target-1-8-into-bytecode-that-is-being-bui
لحل هذه المشكلة ، تحتاج إلى تسجيل إصدار JVM بشكل صريح لـ Kotlin:
android { … kotlinOptions { jvmTarget = "1.8" } }
يبدو أن كل شيء. أسهل بكثير من بناء الاستوديو الخاص بك)
دعونا نحاول تشغيل Hello World (أيضًا من مقالة Cyril ، ولكن على عكسه ، أضف Compose داخل Fragment). تخطيط الجزء هو FrameLayout فارغ.
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { val fragmentView = inflater.inflate(R.layout.fragment_about, container, false) (fragmentView as ViewGroup).setContent { Hello("Jetpack Compose") } return fragmentView } @Composable fun Hello(name: String) = MaterialTheme { FlexColumn { inflexible {
نبدأ ، تظهر الشاشة التالية:
نظرًا لحقيقة أن Composable يستخدم سمة المادة الافتراضية ، فقد حصلنا على AppBar أرجواني. حسنًا ، وكما هو متوقع ، لا يتماشى مطلقًا مع المظهر المظلم للتطبيق:
دعنا نحاول حلها.
الموضوعات والأساليب. التكامل مع الموجودة في المشروع.
من أجل استخدام الأنماط الموجودة داخل Composable ، نقوم بتمريرها داخل مُنشئ MaterialTheme:
@Composable fun Hello(name: String) = MaterialTheme(colors = MaterialColors( primary = resolveColor(context, R.attr.colorPrimary, MaterialColors().primary), secondary = resolveColor(context, R.attr.colorSecondary, MaterialColors().secondary), onBackground = resolveColor(context, R.attr.textColor, MaterialColors().onBackground) )){...}
يتكون MaterialTheme نفسه من جزأين: MaterialColors و MaterialTypography.
لحل الألوان ، استخدمت غلافًا فوق الأنماط:
private fun resolveColor(context: Context?, @AttrRes attrRes: Int, colorDefault: Color) = context?.let { Color(resolveThemeAttr(it, attrRes).data.toLong()) } ?: colorDefault private fun resolveThemeAttr(context: Context, @AttrRes attrRes: Int): TypedValue { val theme = context.theme val typedValue = TypedValue() theme.resolveAttribute(attrRes, typedValue, true) return typedValue }
في هذه المرحلة ، سوف تتحول AppBar إلى اللون الأخضر. ولكن لإعادة طلاء النص ، عليك القيام بعمل إضافي:
Text("Hello $name!", style = TextStyle(color = +themeColor { onBackground }))
يتم تطبيق السمة على عنصر واجهة المستخدم باستخدام عملية unary plus. سنظل نرى ذلك عند العمل مع الدولة.
الآن تبدو الشاشة الجديدة موحدة مع بقية التطبيق في كلا الخيارين للموضوع:
عثر أيضًا على ملف DarkTheme.kt في المصادر ، حيث يمكن استخدام الوظائف لتحديد مشغلات مختلفة لتشغيل سمة مظلمة على Android P و 10.
اختبارات إمكانية الوصول وواجهة المستخدم.
إلى أن تبدأ الشاشة في النمو باستخدام عناصر جديدة ، دعنا نرى كيف تبدو في Layout Inspector ومع عرض حدود العناصر في Dev Mode قيد التشغيل:

هنا سنرى FrameLayout ، بداخله فقط AndroidComposeView. الأدوات الحالية لاختبار Accebility و UI لم تعد قابلة للتطبيق؟ ربما بدلاً من ذلك ستكون هناك مكتبة جديدة: androidx.ui:ui-test
.
المكونات الرئيسية ونظائرها من مشاهدة الورثة.
الآن دعونا نحاول جعل الشاشة أكثر إفادة قليلاً. أولاً ، قم بتغيير النص ، وأضف زرًا يؤدي إلى صفحة التطبيق على Google Play ، وصورة تحمل شعارًا. سأريكم الكود على الفور وما حدث:
@Composable fun AboutScreen() = MaterialTheme(...) { FlexColumn { inflexible { TopAppBar<MenuItem>(title = { Text(getString(R.string.about)) }) } expanded(1F) { VerticalScroller { Column { Image() Title() MyButton() } } } } } private fun Image() { Center { Padding(16.dp) { Container( constraints = DpConstraints( minWidth = 96.dp, minHeight = 96.dp ) ) { imageFromResource(resources, R.drawable.ic_launcher) } } } } private fun Title() { Center { Padding(16.dp) { Text(getString(R.string.app_name) + " " + BuildConfig.VERSION_NAME, style = TextStyle(color = +themeColor { onBackground })) } } } private fun MyButton() { Center { Padding(16.dp) { Button(getString(R.string.about_button), onClick = { openAppInPlayStore() }) } } }
لم تتغير المبادئ الأساسية لتكوين عنصر واجهة المستخدم منذ أول ظهور لمصادر "تكوين" .
من المثير للاهتمام:
الآن دعنا نذهب إلى مجموعة ViewGroup الرئيسية الحالية ومحاولة العثور على نظائرها في إعداد.
بدلاً من FrameLayout ، يمكنك استخدام Stack. كل شيء بسيط هنا: عناصر واجهة المستخدم الفرعية تتداخل ويتم وضعها وفقًا للوظيفة المستخدمة للملحق: محاذاة أو موضعية أو موسعة.
يتم استبدال LinearLayout على الفور بأداة اثنين: Column and Row بدلاً من استخدام android: direction direction. وهي ، بدورها ، تحتوي على FlexColumn و FlexRow مع طبقة من وظيفة غير مرنة على الشجرة الفرعية المتداخلة. حسنًا ، تم بناء FlexColumn و FlexRow بأنفسهم على Flex مع orientation = LayoutOrientation.Vertical
المعلمة orientation = LayoutOrientation.Vertical
أو Horizontal
.
تسلسل هرمي مماثل لعناصر واجهة مستخدم FlowColumn و FlowRow و Flow. الفرق الرئيسي بينهما: إذا كان المحتوى لا يتلاءم مع عمود واحد أو صف واحد ، فسيتم رسمه التالي ، وستتدفق عناصر واجهة المستخدم المضمنة هناك. من الصعب بالنسبة لي أن أتخيل الغرض الحقيقي من هذه الحاجيات.
يتم تحقيق تأثير ScrollView عن طريق وضع عمود أو صف داخل VerticalScroller أو HorizontalScroller. كلاهما يؤلف داخل Scroller ، ويمر في المعلمة isVertical = true
أو false
.
بحثًا عن تناظرية لـ ConstraintLayout ، أو على الأقل واجهت RelativeLayout عنصر واجهة مستخدم جديد في الجدول. حاولت تشغيل نموذج التعليمة البرمجية في تطبيقي: DataTableSamples.kt . لكن ، لأنني لم أحاول تبسيط المثال ، لم ينجح الأمر لجعله يعمل.
العمل مع الدولة
أحد أكثر الابتكارات المتوقعة للإطار هو جاهزيته للاستخدام في بنيات أحادية الاتجاه مبنية على أساس حالة واحدة. وكان من المفترض أن يقدم هذا التعليق التوضيحيModel إلى فئات العلامات التي توفر الولاية لتقديم واجهة المستخدم.
النظر في مثال:
data class DialogVisibleModel(val visible: Boolean, val dismissPushed: Boolean = false) ... @Composable fun SideBySideAlertDialogSample() { val openDialog = +state { DialogVisibleModel(true) } Button(text = "Ok", onClick = { openDialog.value = DialogVisibleModel(true) }) if (openDialog.value.visible) { AlertDialog( onCloseRequest = {
يؤدي هذا إلى إنشاء فئة بيانات لنموذج الحالة ، وليس من الضروري أن يتم وضع علامة عليها مع تعليق توضيحيModel.
يتم إنشاء الحالة الأولية نفسها داخل الدالةComposable باستخدام حالة +.
يتم تحديد رؤية مربع الحوار بواسطة الخاصية المرئية للنموذج التي تم الحصول عليها عن طريق استدعاء خاصية القيمة.
يمكن أيضًا تعيين هذه الخاصية على كائن جديد غير قابل للتغيير ، كما يحدث عند النقر فوق كلا الزرين. الأول يخفي نفسه ، والثاني - يغلق الحوار. يمكن إعادة فتح مربع الحوار بالنقر فوق الزر "موافق" ، المحدد داخل نفس الوظيفةComposable.
عند محاولة إنشاء حالة خارج هذه الوظيفة ، يحدث خطأ:
java.lang.IllegalStateException: Composition requires an active composition context.
يمكن الحصول على السياق عن طريق تعيين قيمة الدالة setContent {} في onCreateView ، ولكن كيفية استخدامها ، على سبيل المثال ، في مقدم العرض أو فئة أخرى غير Fragment أو Activity ، لتغيير الحالة ما زالت غير واضحة.

بهذا نختتم مراجعتنا لمكتبة Jetpack Compose الجديدة. يبرر الإطار اسمه معماريا ، ليحل محل كل الميراث ، الذي كان غير مريح في التسلسل الهرمي للعرض ، مع التكوين. لا يزال هناك الكثير من الأسئلة حول كيفية تطبيق نظائرها لـ ViewGroups الأكثر تعقيدًا ، مثل ConstraintLayout و RecyclerView؛ لا يكفي وثائق ومعاينات.
من الواضح تمامًا أن Compose ليس جاهزًا للاستخدام حتى في التطبيقات القتالية الصغيرة.
ولكن هذه ليست سوى النسخة الأولى من Dev Preview. سيكون من المثير للاهتمام أن نلاحظ تطور مفهوم العمل مع الدولة والمكتبات من المجتمع على أساس تكوين.
إذا وجدت أمثلة أكثر نجاحًا للشفرة أو الوثائق الخاصة بالحالات التي لم أستطع الحصول عليها ، فيرجى كتابة التعليقات.