استفاده از Compose در Views

شما می‌توانید رابط کاربری مبتنی بر Compose را به یک برنامه موجود که از طراحی مبتنی بر View استفاده می‌کند، اضافه کنید.

برای ایجاد یک صفحه نمایش جدید و کاملاً مبتنی بر Compose، از activity خود بخواهید که متد setContent() را فراخوانی کند و هر تابع composable که دوست دارید را به آن ارسال کند.

class ExampleActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent { // In here, we can call composables!
            MaterialTheme {
                Greeting(name = "compose")
            }
        }
    }
}

@Composable
fun Greeting(name: String) {
    Text(text = "Hello $name!")
}

این کد دقیقاً شبیه چیزی است که در یک برنامه فقط-کامپوز (Compose-only) پیدا می‌کنید.

ViewCompositionStrategy برای ComposeView

ViewCompositionStrategy زمان دفع Composition را تعریف می‌کند. مقدار پیش‌فرض، ViewCompositionStrategy.Default ، زمانی که ComposeView زیرین از پنجره جدا می‌شود، Composition را دفع می‌کند، مگر اینکه بخشی از یک ظرف جمع‌آوری مانند RecyclerView باشد. در یک برنامه‌ی تک‌فعالیتی که فقط Compose را پشتیبانی می‌کند، این رفتار پیش‌فرض همان چیزی است که شما می‌خواهید، با این حال، اگر Compose را به تدریج به کدبیس خود اضافه می‌کنید، این رفتار ممکن است در برخی سناریوها باعث از دست رفتن وضعیت شود.

برای تغییر ViewCompositionStrategy ، متد setViewCompositionStrategy() را فراخوانی کرده و یک استراتژی متفاوت ارائه دهید.

جدول زیر سناریوهای مختلفی را که می‌توانید از ViewCompositionStrategy در آنها استفاده کنید، خلاصه می‌کند:

ViewCompositionStrategy شرح و سناریوی تعامل
DisposeOnDetachedFromWindow این Composition زمانی که ComposeView زیرین از پنجره جدا شود، از بین خواهد رفت. از آن زمان تاکنون توسط DisposeOnDetachedFromWindowOrReleasedFromPool جایگزین شده است.

سناریوی تعامل:

* ComposeView چه تنها عنصر در سلسله مراتب View باشد، چه در متن یک صفحه نمایش ترکیبی View/Compose (نه در Fragment).
DisposeOnDetachedFromWindowOrReleasedFromPool ( پیش‌فرض ) مشابه DisposeOnDetachedFromWindow ، زمانی که Composition در یک ظرف pooling مانند RecyclerView نباشد. اگر در یک ظرف pooling باشد، زمانی که خود ظرف pooling از پنجره جدا شود یا زمانی که آیتم در حال دور انداختن باشد (یعنی وقتی pool پر باشد)، dispose می‌شود.

سناریوی تعامل:

* ComposeView چه تنها عنصر در سلسله مراتب View باشد، چه در متن یک صفحه نمایش ترکیبی View/Compose (نه در Fragment).
* ComposeView به عنوان یک آیتم در یک ظرف جمع‌آوری مانند RecyclerView .
DisposeOnLifecycleDestroyed وقتی Lifecycle ارائه شده از بین برود، کامپوزیشن از بین خواهد رفت.

سناریوی اینتراپ

* ComposeView در نمای یک قطعه.
DisposeOnViewTreeLifecycleDestroyed این ترکیب زمانی از بین می‌رود که Lifecycle متعلق به LifecycleOwner که توسط ViewTreeLifecycleOwner.get برگردانده شده است، از پنجره بعدی که View به آن متصل شده است، از بین برود.

سناریوی تعامل:

* ComposeView در نمای یک قطعه.
* ComposeView در نمایی که چرخه حیات آن هنوز مشخص نیست.

ComposeView در قطعات

اگر می‌خواهید محتوای رابط کاربری Compose را در یک فرگمنت یا یک طرح‌بندی View موجود بگنجانید، از ComposeView استفاده کنید و متد setContent() آن را فراخوانی کنید. ComposeView یک View اندروید است.

شما می‌توانید ComposeView درست مانند هر View دیگری در طرح XML خود قرار دهید:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

  <TextView
      android:id="@+id/text"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content" />

  <androidx.compose.ui.platform.ComposeView
      android:id="@+id/compose_view"
      android:layout_width="match_parent"
      android:layout_height="match_parent" />
</LinearLayout>

در کد منبع کاتلین، طرح‌بندی را از منبع طرح‌بندی تعریف‌شده در XML، inflate کنید. سپس ComposeView با استفاده از شناسه XML دریافت کنید، یک استراتژی Composition تنظیم کنید که برای View میزبان بهترین عملکرد را داشته باشد و setContent() را برای استفاده از Compose فراخوانی کنید.

class ExampleFragmentXml : Fragment() {

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        val view = inflater.inflate(R.layout.fragment_example, container, false)
        val composeView = view.findViewById<ComposeView>(R.id.compose_view)
        composeView.apply {
            // Dispose of the Composition when the view's LifecycleOwner
            // is destroyed
            setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
            setContent {
                // In Compose world
                MaterialTheme {
                    Text("Hello Compose!")
                }
            }
        }
        return view
    }
}

به عنوان یک روش جایگزین، می‌توانید با ارجاع به کلاس اتصال تولید شده برای فایل طرح‌بندی XML خود، از view binding برای دریافت ارجاعات به ComposeView استفاده کنید:

class ExampleFragment : Fragment() {

    private var _binding: FragmentExampleBinding? = null

    // This property is only valid between onCreateView and onDestroyView.
    private val binding get() = _binding!!

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        _binding = FragmentExampleBinding.inflate(inflater, container, false)
        val view = binding.root
        binding.composeView.apply {
            // Dispose of the Composition when the view's LifecycleOwner
            // is destroyed
            setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
            setContent {
                // In Compose world
                MaterialTheme {
                    Text("Hello Compose!")
                }
            }
        }
        return view
    }

    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }
}

دو عنصر متنی کمی متفاوت، یکی بالای دیگری

شکل ۱. این خروجی کدی را نشان می‌دهد که عناصر Compose را در سلسله مراتب رابط کاربری View اضافه می‌کند. متن "Hello Android!" توسط یک ویجت TextView نمایش داده می‌شود. متن "Hello Compose!" توسط یک عنصر متن Compose نمایش داده می‌شود.

همچنین اگر تمام صفحه شما با Compose ساخته شده باشد، می‌توانید یک ComposeView مستقیماً در یک فرگمنت قرار دهید، که به شما امکان می‌دهد از استفاده کامل از یک فایل طرح‌بندی XML اجتناب کنید.

class ExampleFragmentNoXml : Fragment() {

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        return ComposeView(requireContext()).apply {
            // Dispose of the Composition when the view's LifecycleOwner
            // is destroyed
            setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
            setContent {
                MaterialTheme {
                    // In Compose world
                    Text("Hello Compose!")
                }
            }
        }
    }
}

چندین نمونه ComposeView در یک طرح‌بندی یکسان

اگر چندین عنصر ComposeView در یک طرح‌بندی وجود داشته باشد، هر کدام باید یک شناسه منحصر به فرد داشته باشند تا savedInstanceState بتواند کار کند.

class ExampleFragmentMultipleComposeView : Fragment() {

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View = LinearLayout(requireContext()).apply {
        addView(
            ComposeView(requireContext()).apply {
                setViewCompositionStrategy(
                    ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed
                )
                id = R.id.compose_view_x
                // ...
            }
        )
        addView(TextView(requireContext()))
        addView(
            ComposeView(requireContext()).apply {
                setViewCompositionStrategy(
                    ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed
                )
                id = R.id.compose_view_y
                // ...
            }
        )
    }
}

شناسه‌های ComposeView در فایل res/values/ids.xml تعریف شده‌اند:

<resources>
  <item name="compose_view_x" type="id" />
  <item name="compose_view_y" type="id" />
</resources>

پیش‌نمایش ترکیبات در ویرایشگر طرح‌بندی

همچنین می‌توانید پیش‌نمایش Composableها را در ویرایشگر طرح‌بندی برای طرح‌بندی XML خود که حاوی ComposeView است، مشاهده کنید. انجام این کار به شما امکان می‌دهد ببینید که Composableهای شما در یک طرح‌بندی ترکیبی از Views و Compose چگونه به نظر می‌رسند.

فرض کنید می‌خواهید ترکیب‌بندی زیر را در ویرایشگر طرح‌بندی نمایش دهید. توجه داشته باشید که ترکیب‌بندی‌هایی که با @Preview حاشیه‌نویسی شده‌اند، گزینه‌های خوبی برای پیش‌نمایش در ویرایشگر طرح‌بندی هستند.

@Preview
@Composable
fun GreetingPreview() {
    Greeting(name = "Android")
}

برای نمایش این composable، از ویژگی tools:composableName tools استفاده کنید و مقدار آن را برابر با نام کامل composable قرار دهید تا در طرح‌بندی پیش‌نمایش داده شود.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

  <androidx.compose.ui.platform.ComposeView
      android:id="@+id/my_compose_view"
      tools:composableName="com.example.compose.snippets.interop.InteroperabilityAPIsSnippetsKt.GreetingPreview"
      android:layout_height="match_parent"
      android:layout_width="match_parent"/>

</LinearLayout>

قابل ترکیب در ویرایشگر طرح نمایش داده می‌شود

مراحل بعدی

حالا که با APIهای قابلیت همکاری برای استفاده از Compose در Views آشنا شدید، یاد بگیرید که چگونه از Views در Compose استفاده کنید.

{% کلمه به کلمه %} {% فعل کمکی %} {% کلمه به کلمه %} {% فعل کمکی %}