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

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

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

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

کلیپ و روکش

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

این عنصر در بالای سایر عناصر 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

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