استفاده از «نوشتن» در «نماها»

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

برای ایجاد صفحه‌نمایش جدیدی که کاملاً مبتنی بر Compose باشد، فعالیتتان را وادار کنید متد setContent() را فراخوانی کند و هر تابع ترکیب‌پذیری را که می‌خواهید ارسال کند.

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 تعیین می‌کند که چه زمانی «ترکیب‌بندی» باید دور انداخته شود. پیش‌فرض، ViewCompositionStrategy.Default، «ترکیب‌بندی» را وقتی ComposeView زیرین از پنجره جدا می‌شود دور می‌اندازد، مگراینکه بخشی از یک محفظه ادغام مانند RecyclerView باشد. در برنامه تک‌فعالیتی فقط Compose، این رفتار پیش‌فرض همان چیزی است که می‌خواهید، اما اگر به‌تدریج Compose را به پایگاه کد خود اضافه می‌کنید، این رفتار ممکن است در برخی سناریوها باعث ازدست رفتن وضعیت شود.

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

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

ViewCompositionStrategy شرح و سناریو تعامل‌پذیری
DisposeOnDetachedFromWindow وقتی ComposeView زیرین از پنجره جدا شود، «ترکیب‌بندی» دور انداخته خواهد شد. از آن زمان با DisposeOnDetachedFromWindowOrReleasedFromPool جایگزین شده است.

سناریو Interop:

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

سناریو Interop:

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

سناریو Interop

* ComposeView در «نمای» Fragment.
DisposeOnViewTreeLifecycleDestroyed The Composition will be disposed when the Lifecycle owned by the LifecycleOwner returned by ViewTreeLifecycleOwner.get of the next window the View is attached to is destroyed.

Interop scenario:

* ComposeView in a Fragment's View.
* ComposeView در «نمایی» که «چرخه حیات» آن هنوز مشخص نیست.

‫ComposeView در Fragments (مرحله انتقالی)

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

می‌توانید 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>

در کد منبع Kotlin، چیدمان را از منبع چیدمان تعریف‌شده در XML باد کنید. سپس ComposeView را بااستفاده از شناسه XML دریافت کنید، استراتژی «ترکیب‌بندی» را که برای میزبان 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
    }
}

یا می‌توانید از اتصال نما برای دریافت ارجاع به ComposeView با ارجاع به کلاس اتصال تولیدشده برای فایل چیدمان XML استفاده کنید:

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 اضافه می‌کند. نوشتار «سلام Android!» توسط ابزارک TextView نمایش داده می‌شود. نوشتار «Hello Compose!‎» توسط عنصر نوشتاری Compose نمایش داده می‌شود.

همچنین می‌توانید ComposeView را مستقیماً در قطعه‌ای اضافه کنید اگر تمام صفحه شما با Compose ساخته شده باشد، که به شما امکان می‌دهد از استفاده از فایل طرح‌بندی 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 در «ویرایشگر چیدمان»

همچنین می‌توانید composable را در «ویرایشگر چیدمان» برای چیدمان XML خود که حاوی ComposeView است پیش‌دید کنید. با انجام این کار می‌توانید ببینید که composable شما در چیدمان ترکیبی Views و Compose چگونه به‌نظر می‌رسد.

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

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

برای نمایش این composable، از مشخصه ابزارهای tools:composableName استفاده کنید و مقدار آن را روی نام کاملاً واجد شرایط 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>

«ترکیب‌پذیر» در ویرایشگر چیدمان نمایش داده می‌شود