سفارشی‌سازی انتقال عنصر هم‌رسانی‌شده

برای سفارشی‌سازی نحوه اجرای پویانمایی گذار عنصر هم‌رسانی‌شده، چند پارامتر وجود دارد که می‌توان از آن‌ها برای تغییر نحوه گذار عناصر هم‌رسانی‌شده استفاده کرد.

مشخصات پویانمایی

برای تغییر دادن مشخصات پویانمایی مورداستفاده برای حرکت اندازه و موقعیت، می‌توانید پارامتر boundsTransform متفاوتی را در Modifier.sharedElement() مشخص کنید. این کار موقعیت اولیه Rect و موقعیت هدف Rect را ارائه می‌دهد.

برای مثال، برای اینکه نوشتار در مثال قبلی با حرکت قوسی حرکت کند، پارامتر boundsTransform را برای استفاده از مشخصات keyframes مشخص کنید:

val textBoundsTransform = BoundsTransform { initialBounds, targetBounds ->
    keyframes {
        durationMillis = boundsAnimationDurationMillis
        initialBounds at 0 using ArcMode.ArcBelow using FastOutSlowInEasing
        targetBounds at boundsAnimationDurationMillis
    }
}
Text(
    "Cupcake", fontSize = 28.sp,
    modifier = Modifier.sharedBounds(
        rememberSharedContentState(key = "title"),
        animatedVisibilityScope = animatedVisibilityScope,
        boundsTransform = textBoundsTransform
    )
)

می‌توانید از هر AnimationSpec استفاده کنید. این نمونه از مشخصات keyframes استفاده می‌کند.

شکل ۱. نمونه‌ای که پارامترهای boundsTransform مختلف را نشان می‌دهد

حالت تغییر اندازه

هنگام پویانمایی بین دو مرز مشترک، می‌توانید پارامتر resizeMode را روی RemeasureToBounds یا ScaleToBounds تنظیم کنید. این پارامتر تعیین می‌کند که عنصر هم‌رسانی‌شده چگونه بین دو حالت گذار می‌کند. ScaleToBounds ابتدا چیدمان فرزند را با محدودیت‌های پیش‌نگری (یا هدف) اندازه‌گیری می‌کند. سپس، چیدمان پایدار فرزند مقیاس‌بندی می‌شود تا در مرزهای هم‌رسانی‌شده قرار گیرد. ScaleToBounds را می‌توان به‌عنوان «مقیاس گرافیکی» بین حالت‌ها درنظر گرفت.

درمقابل، RemeasureToBounds طرح‌بندی فرزند sharedBounds را با محدودیت‌های ثابت پویانمایی‌شده براساس اندازه هدف دوباره اندازه‌گیری و طرح‌بندی می‌کند. بازسنجش با تغییر اندازه مرزها راه‌اندازی می‌شود که می‌تواند به‌طور بالقوه در هر فریم اتفاق بیفتد.

برای ترکیب‌پذیرهای Text، ScaleToBounds توصیه می‌شود، زیرا از بازچیدمان و بازجاری شدن نوشتار در خطوط مختلف جلوگیری می‌کند. RemeasureToBounds برای مرزهایی با نسبت‌های ابعادی متفاوت توصیه می‌شود، و اگر می‌خواهید تداوم سیال بین دو عنصر مشترک داشته باشید.

تفاوت بین دو حالت تغییر اندازه را می‌توان در مثال‌های زیر مشاهده کرد:

ScaleToBounds

RemeasureToBounds

فعال و غیرفعال کردن عناصر هم‌رسانی‌شده به‌صورت پویا

به‌طور پیش‌فرض، sharedElement() و sharedBounds() به‌گونه‌ای پیکربندی شده‌اند که هرگاه کلید منطبقی در وضعیت هدف پیدا شود، تغییرات چیدمان را پویانمایی کنند. بااین‌حال، ممکن است بخواهید این پویانمایی را به‌طور پویا براساس شرایط خاصی، مانند جهت پیمایش یا وضعیت فعلی واسط کاربر، غیرفعال کنید.

برای کنترل اینکه آیا انتقال عنصر مشترک رخ می‌دهد یا نه، می‌توانید SharedContentConfig ارسال‌شده به rememberSharedContentState() را سفارشی‌سازی کنید. خصوصیت isEnabled تعیین می‌کند که عنصر هم‌رسانی‌شده فعال است یا نه.

مثال زیر نشان می‌دهد که چگونه پیکربندی‌ای را تعریف کنید که فقط هنگام پیمایش بین صفحه‌های خاص (مثلاً فقط از A به B) انتقال مشترک را فعال کند و آن را برای سایر صفحه‌ها غیرفعال کند.

SharedTransitionLayout {
    val transition = updateTransition(currentState)
    transition.AnimatedContent { targetState ->
        // Create the configuration that depends on state changing.
        fun animationConfig() : SharedTransitionScope.SharedContentConfig {
            return object : SharedTransitionScope.SharedContentConfig {
                override val SharedTransitionScope.SharedContentState.isEnabled: Boolean
                    // For this example, we only enable the transition in one direction
                    // from A -> B and not the other way around.
                    get() =
                        transition.currentState == "A" && transition.targetState == "B"
            }
        }
        when (targetState) {
            "A" -> Box(
                modifier = Modifier
                    .sharedElement(
                        rememberSharedContentState(
                            key = "shared_box",
                            config = animationConfig()
                        ),
                        animatedVisibilityScope = this
                    )
                    // ...
            ) {
                // Your content
            }
            "B" -> {
                Box(
                    modifier = Modifier
                        .sharedElement(
                            rememberSharedContentState(
                                key = "shared_box",
                                config = animationConfig()
                            ),
                            animatedVisibilityScope = this
                        )
                        // ...
                ) {
                    // Your content
                }
            }
        }
    }
}

به‌طور پیش‌فرض، اگر یک عنصر مشترک درطول یک پویانمایی درحال اجرا غیرفعال شود، همچنان پویانمایی فعلی درحال اجرا را تکمیل می‌کند تا از حذف تصادفی پویانمایی‌های درحال اجرا جلوگیری شود. اگر لازم است عنصر را درحین اجرای پویانمایی بردارید، می‌توانید shouldKeepEnabledForOngoingAnimation را در میانای SharedContentConfig لغو کنید تا مقدار false برگردانده شود.

رد شدن به چیدمان نهایی

به‌طور پیش‌فرض، هنگام گذر بین دو چیدمان، اندازه چیدمان بین حالت شروع و پایان آن پویانمایی می‌شود. این ممکن است رفتار نامطلوبی هنگام پویانمایی محتوایی مانند نوشتار باشد.

مثال زیر نشان می‌دهد که نوشتار شرح «Lorem Ipsum» به دو روش مختلف وارد صفحه می‌شود. در مثال اول، نوشتار با ورود به محفظه و افزایش اندازه آن، بازآرایی می‌شود. در مثال دوم، نوشتار با بزرگ شدن بازآرایی نمی‌شود. افزودن Modifier.skipToLookaheadSize() از بازجاری با رشد آن جلوگیری می‌کند.

بدون Modifier.skipToLookaheadSize() - به جریان مجدد نوشتار «Lorem Ipsum» توجه کنید

Modifier.skipToLookaheadSize() - توجه کنید که نوشتار «Lorem Ipsum» حالت نهایی خود را در شروع پویانمایی حفظ می‌کند

کلیپ و رونهادها

برای اینکه عناصر هم‌رسانی‌شده بین ترکیب‌پذیرهای مختلف هم‌رسانی شوند، پرداخت ترکیب‌پذیر به یک هم‌پوشانی لایه ارتقا می‌یابد وقتی که انتقال به مطابقت آن در مقصد شروع می‌شود. تأثیر این کار این است که از مرزهای والد و تبدیل‌های لایه آن (برای مثال، آلفا و مقیاس) فرار می‌کند.

این نشانگر روی دیگر عناصر واسط کاربر هم‌رسانی‌نشده رندر می‌شود. وقتی انتقال تمام شد، عنصر از هم‌پوشانی به DrawScope خودش منتقل می‌شود.

برای برش دادن عنصر هم‌رسانی‌شده به یک شکل، از تابع استاندارد Modifier.clip() استفاده کنید. آن را بعداز sharedElement() قرار دهید:

Image(
    painter = painterResource(id = R.drawable.cupcake),
    contentDescription = "Cupcake",
    modifier = Modifier
        .size(100.dp)
        .sharedElement(
            rememberSharedContentState(key = "image"),
            animatedVisibilityScope = this@AnimatedContent
        )
        .clip(RoundedCornerShape(16.dp)),
    contentScale = ContentScale.Crop
)

اگر لازم است مطمئن شوید که عنصر هم‌رسانی‌شده هرگز خارج از محفظه اصلی ارائه نمی‌شود، می‌توانید clipInOverlayDuringTransition را روی sharedElement() تنظیم کنید. به‌طور پیش‌فرض، برای مرزهای هم‌رسانی‌شده تودرتو، clipInOverlayDuringTransition از مسیر برش از sharedBounds() والد استفاده می‌کند.

برای پشتیبانی از نگه داشتن عناصر خاص میانای کاربر، مانند نوار پایین یا دکمه کنش شناور، همیشه در بالا درطول گذار عنصر مشترک، از Modifier.renderInSharedTransitionScopeOverlay() استفاده کنید. به‌طور پیش‌فرض، این اصلاح‌کننده محتوا را درطول زمانی که انتقال هم‌رسانی‌شده فعال است در هم‌پوشانی نگه می‌دارد.

برای مثال، در Jetsnack،‏ BottomAppBar باید در بالای عنصر مشترک قرار داده شود تا زمانی که صفحه قابل‌مشاهده نباشد. افزودن اصلاح‌کننده به composable آن را در حالت بالا نگه می‌دارد.

بدون Modifier.renderInSharedTransitionScopeOverlay()

ازطریق Modifier.renderInSharedTransitionScopeOverlay()

شاید بخواهید ترکیب‌پذیر غیرهم‌رسانی‌شده‌تان پویانمایی شود و همچنین قبل‌از انتقال، روی ترکیب‌پذیرهای دیگر باقی بماند. در چنین مواردی، از renderInSharedTransitionScopeOverlay().animateEnterExit() برای پویانمایی composable out هنگام اجرای انتقال عنصر مشترک استفاده کنید:

JetsnackBottomBar(
    modifier = Modifier
        .renderInSharedTransitionScopeOverlay(
            zIndexInOverlay = 1f,
        )
        .animateEnterExit(
            enter = fadeIn() + slideInVertically {
                it
            },
            exit = fadeOut() + slideOutVertically {
                it
            }
        )
)

شکل ۲. نوار برنامه پایین صفحه با انتقال پویانمایی به داخل و خارج می‌لغزد.

در موارد نادری که می‌خواهید عنصر هم‌رسانی‌شده شما در هم‌پوشانی رندر نشود، می‌توانید renderInOverlayDuringTransition را در sharedElement() روی false تنظیم کنید.

اطلاع‌رسانی به چیدمان‌های هم‌نیا درباره تغییرات اندازه عنصر هم‌رسانی‌شده

به‌طور پیش‌فرض، sharedBounds() و sharedElement() به محفظه اصلی هیچ‌گونه تغییر اندازه را درطول انتقال چیدمان اطلاع نمی‌دهند.

برای انتشار تغییرات اندازه به محفظه اصلی درحین انتقال، پارامتر placeholderSize را به PlaceholderSize.AnimatedSize تغییر دهید. با این کار، اندازه مورد بزرگ‌تر یا کوچک‌تر می‌شود. همه موارد دیگر در چیدمان به این تغییر واکنش نشان می‌دهند.

‫PlaceholderSize.ContentSize (پیش‌فرض)

PlaceholderSize.AnimatedSize

(توجه کنید که چگونه موارد دیگر در فهرست در پاسخ به رشد یک مورد به پایین حرکت می‌کنند)