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

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

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

برای تغییر مشخصات پویانمایی استفاده‌شده برای حرکت اندازه و موقعیت، می‌توانید پارامتر 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 لغو کنید تا به‌صورت نادرست برگردد.

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

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

مثال زیر نشان می‌دهد که نوشتار شرح «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 باید روی عنصر هم‌رسانی‌شده قرار گیرد تا زمانی که صفحه قابل‌مشاهده نباشد. افزودن اصلاح‌کننده به عنصر ترکیبی آن را در سطح بالا نگه می‌دارد.

بدون Modifier.renderInSharedTransitionScopeOverlay()

ازطریق Modifier.renderInSharedTransitionScopeOverlay()

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

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

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