انتقال عنصر مشترک را سفارشی کنید

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

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

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

شکل 1. مثالی که boundsTransform مختلف را نشان می دهد

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

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

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

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

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

ScaleToBounds

RemeasureToBounds

به طرح نهایی بروید

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

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

بدون Modifier.skipToLookahead() - به جریان مجدد متن "Lorem Ipsum" توجه کنید

Modifier.skipToLookahead() - توجه کنید که متن "Lorem Ipsum" وضعیت نهایی خود را در شروع انیمیشن حفظ می کند.

کلیپ و روکش

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

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

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

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

بدون Modifier.renderInSharedTransitionScopeOverlay()

با Modifier.renderInSharedTransitionScopeOverlay()

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

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

شکل 2. نوار برنامه پایین که به هنگام انتقال انیمیشن به داخل و خارج می‌چرخد.

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

طرح بندی خواهر و برادر را از تغییرات اندازه عنصر مشترک مطلع کنید

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

به منظور انتشار تغییرات اندازه در ظرف والد در حین انتقال، پارامتر placeHolderSize را به PlaceHolderSize.animatedSize تغییر دهید. انجام این کار باعث رشد یا کوچک شدن آیتم می شود. همه موارد دیگر در طرح به تغییر پاسخ می دهند.

PlaceholderSize.contentSize (پیش فرض)

PlaceholderSize.animatedSize

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