Jetpack Compose A to Z 리허설 전 full 자료 (70분)
Jetpack Compose A to Z✨ࢿ࠼
View Slide
👋ࢿ࠼🏠TVOHCJO🏰TVOHCJOMBOE🐙HJUIVCDPNKJTVOHCJO
-PPLBIFBE-BZPVU "OJNBUJPO *OUFSOBM4ZTUFN $PNQJMFS%FCVHHJOH #FTU1SBDUJDF 8SBQVQ📖ݾର
↟ BMQIBӝળ↟ ٘ࣁࠗࢎ೦ࢤۚ📝दೞӝী
1. LookaheadLayout
startfinishanimation frame
$PMVNO3PX🙅 #PY#PY8JUI$POTUSBJOUT🙅 -B[Z-JTU🙅 $POTUSBJOU-BZPVU🙅 -BZPVU🙅 -PPLBIFBE-BZPVU🥳BOJNBUJPOGSBNFਸ୶ೞӝਤೠۨইਓ
startfinish1st intermediate layout2nd intermediate layout3rd intermediate layoutLookahead1. Modifier.onPlaced2. Modifier.intermediateLayout
/*** ۨইਓਸ Ѿೞӝ ਤ೧ measure ܳ ܻ ೞҊ ୶റ placement ױ҅ܳ प೯ೞח ۨইਓੑפ. => measure ܳ ܻ ೞח ױ҅: lookahead ױ҅* lookahead ױ҅о աݶ ୶റ [LookaheadLayoutScope.intermediateLayout] ਸ ా೧* lookahead Ѿҗܳ ӝ߈ਵ۽ ۨইਓ measure ߂ placement ܳ ઑೡ ࣻ ח ژ ܲ measure ߂ placement ױ҅о दؾפ. => intermediate layout** ܳ ਊೞৈ ۨইਓ ܻ measure ػ intermediate layout ਸ ೱ೧ ӝ৬ ਤܳ ରਵ۽ ߸҃ೡ ࣻ णפ.*/@ExperimentalComposeUiApi@UiComposable@Composablefun LookaheadLayout(content: @Composable @UiComposable LookaheadLayoutScope.() -> Unit,modifier: Modifier = Modifier,measurePolicy: MeasurePolicy)
/*** [LookaheadLayout] ݽٚ( ߂ р) ೞਤ ۨইਓী ೠ receiver ߧਤܳ ઁҕפ.* lookahead ױ҅ীࢲ ҅ػ ۨইਓ measurement ߂ placement ח* [LookaheadLayoutScope] ীࢲ пп [Modifier.intermediateLayout] ߂ [Modifier.onPlaced] ܳ ా೧ observe ೡ ࣻ णפ.*/@ExperimentalComposeUiApiinterface LookaheadLayoutScope {fun Modifier.onPlaced(onPlaced: (lookaheadScopeCoordinates: LookaheadLayoutCoordinates,layoutCoordinates: LookaheadLayoutCoordinates) -> Unit): Modifierfun Modifier.intermediateLayout(measure: MeasureScope.(measurable: Measurable,constraints: Constraints,lookaheadSize: IntSize) -> MeasureResult): Modifier}
@ExperimentalComposeUiApiinterface LookaheadLayoutScope {/*** intermediate layout ߓؼ ਤо ҅ػ റ ഐؾפ.** [LookaheadLayoutCoordinates] о যݶ ҅ػ intermediate layout য়ࣇҗ അ ߓظ ח ஹನ࠶ য়ࣇਸ* [LookaheadLayoutCoordinates.localLookaheadPositionOf] ৬ [LookaheadLayoutCoordinates.localPositionOf] ܳ ࢎਊೞৈ ਸ ࣻ णפ.* ܳ ా೧ ҅ػ intermediate layout য়ࣇਸ ӝ߈ਵ۽ ஹನ࠶ ߓܳ ઑೡ ࣻ णפ.** [onPlaced ۈ ੋ]** @param lookaheadScopeCoordinates [LookaheadLayout] ࢎਊೞח [LookaheadLayoutCoordinates]* @param layoutCoordinates modifier ஹನ࠶ ࢎਊೞח [LookaheadLayoutCoordinates]*/fun Modifier.onPlaced(onPlaced: (lookaheadScopeCoordinates: LookaheadLayoutCoordinates,layoutCoordinates: LookaheadLayoutCoordinates) -> Unit): Modifierfun Modifier.intermediateLayout(measure: MeasureScope.(measurable: Measurable,constraints: Constraints,lookaheadSize: IntSize
startfinishLookahead1st intermediate layout2nd intermediate layoutwill be 3rd intermediate layoutOEJOUFSNFEJBUFMBZPVUীࢲप೯غח࢚ടJOUFSNFEJBUFMBZPVUߓؼਤܳ҅ೣറ೧ਤܳModifier.onPlaced۽ࠁն
/*** ۨইਓী ೧ measure ػ bounds ഓ؊ੑפ.*/@JvmDefaultWithCompatibilityinterface LayoutCoordinates {// … ࢤۚ/*** [sourceCoordinates] ҕр [relativeToSource] ܳ ۽ஸ coordinate ۽ ߸ജפ.* [sourceCoordinates] ח زੌೠ ۨইਓ ҅கী ࣘೞח ݽٚ [LayoutCoordinates] ੌ ࣻ णפ.** @param sourceCoordinates ߸ജೡ [Offset] ח [LayoutCoordinates]* @param relativeToSource ߸ഝೡ [Offset]** @return ۽ஸ coordinate ۽ ߸ജػ [Offset]*/fun localPositionOf(sourceCoordinates: LayoutCoordinates, relativeToSource: Offset): Offset}
/*** lookhead ױ҅ ೯ җ റ ۨইਓ ݽف [LayoutCoordinates] ܳ ࠁਬפ.*/@ExperimentalComposeUiApisealed interface LookaheadLayoutCoordinates : LayoutCoordinates {/*** [sourceCoordinates] ҕр [relativeToSource] ܳ ۽ஸ coordinate ۽ ߸ജפ.* [sourceCoordinates] ח زੌೠ ۨইਓ ҅கী ࣘೞח ݽٚ [LookaheadLayoutCoordinates] ੌ ࣻ णפ.** [localPositionOf] ৬ ׳ܻ [localLookaheadPositionOf] ח coordinate ҅ਸ ਤ೧ lookahead ਤܳ ࢎਊפ.** @param sourceCoordinates ߸ജೡ [Offset] ח [LookaheadLayoutCoordinates]* @param relativeToSource ߸ഝೡ [Offset]** @return ۽ஸ coordinate ۽ ߸ജػ [Offset]*/fun localLookaheadPositionOf(sourceCoordinates: LookaheadLayoutCoordinates,relativeToSource: Offset = Offset.Zero): Offset}
// interface LookaheadLayoutScope/*** lookahead ױ҅ীࢲ ҅ػ ࠁܳ ӝ߈ਵ۽ intermediate layout ܳ ߓפ.* intermediate layout ӝо ઁҕغח ۈੋ [measure] ੋܳ ా೧ intermediate layout ܳ morph ೡ ࣻ णפ.** morph: അ ݽনਸ ܲ ݽনਵ۽ ߄Բח Ѫ** [measure ۈ ੋ]** @param measurable intermediate layout measurable* @param constraints intermediate layout constraints* @param lookaheadSize intermediate layout ӝ*/fun Modifier.intermediateLayout(measure: MeasureScope.(measurable: Measurable,constraints: Constraints,lookaheadSize: IntSize) -> MeasureResult): Modifier}
startfinishLookahead1st intermediate layout2nd intermediate layoutwill be 3rd intermediate layoutOEJOUFSNFEJBUFMBZPVUীࢲप೯غח࢚ടModifier.intermediateLayoutਵ۽ߓೡҔLookaheadLayoutCoordinates.localLookaheadPositionOfয়ࣇLookaheadLayoutCoordinates.localPositionOfয়ࣇ
startfinishLookaheadӝয়ࣇ
ӝઑ.PEJGJFSJNUFSNFEJBUF-BZPVU/*** lookahead ױ҅ীࢲ ҅ػ ࠁܳ ӝ߈ਵ۽ intermediate layout ܳ ߓפ.* intermediate layout ӝо ઁҕغח ۈੋ [measure] ੋܳ ా೧ intermediate layout ܳ morph ೡ ࣻ णפ.*/fun Modifier.intermediateLayout(measure: MeasureScope.(measurable: Measurable,constraints: Constraints,lookaheadSize: IntSize) -> MeasureResult): Modifier
য়ࣇઑ.PEJGJFSPO1MBDFE/*** [LookaheadLayoutCoordinates] о যݶ ҅ػ intermediate layout য়ࣇҗ അ ߓظ ח ஹನ࠶ য়ࣇਸ* [LookaheadLayoutCoordinates.localLookaheadPositionOf] ৬ [LookaheadLayoutCoordinates.localPositionOf] ܳ ࢎਊೞৈ ਸ ࣻ णפ.* ܳ ా೧ ҅ػ intermediate layout য়ࣇਸ ӝ߈ਵ۽ ஹನ࠶ ߓܳ ઑೡ ࣻ णפ.*/fun Modifier.onPlaced(onPlaced: (lookaheadScopeCoordinates: LookaheadLayoutCoordinates,layoutCoordinates: LookaheadLayoutCoordinates) -> Unit): Modifier
fun Modifier.movement(lookaheadScope: LookaheadLayoutScope) = composed {var targetOffset: IntOffset? by remember { mutableStateOf(null) } // ߓೡ য়ࣇvar placementOffset by remember { mutableStateOf(IntOffset.Zero) } // അ য়ࣇwith(lookaheadScope) {this@composed.onPlaced { lookaheadScopeCoordinates, layoutCoordinates ->// LookaheadLayout ۽ஸ coordinates ীࢲ modifier lookahead ਤܳ ߈ജtargetOffset = lookaheadScopeCoordinates.localLookaheadPositionOf(sourceCoordinates = layoutCoordinates).round() // о оө IntOffset чਵ۽ য়ࣇ ߈ৢܿ// LookaheadLayout ۽ஸ coordinates ীࢲ modifier അ ਤܳ ߈ജplacementOffset = lookaheadScopeCoordinates.localPositionOf(sourceCoordinates = layoutCoordinates,relativeToSource = Offset.Zero).round()}.intermediateLayout { measurable, constraints, _ ->val placeable = measurable.measure(constraints)layout(width = placeable.width, height = placeable.height) {// زೠ য়ࣇী ߓ
targetOffset = lookaheadScopeCoordinates.localLookaheadPositionOf(sourceCoordinates = layoutCoordinates).round() // о оө IntOffset чਵ۽ য়ࣇ ߈ৢܿ// LookaheadLayout ۽ஸ coordinate ীࢲ modifier അ ਤܳ ߈ജplacementOffset = lookaheadScopeCoordinates.localPositionOf(sourceCoordinates = layoutCoordinates,relativeToSource = Offset.Zero).round()}.intermediateLayout { measurable, constraints, _ ->val placeable = measurable.measure(constraints)layout(width = placeable.width, height = placeable.height) {// زೠ য়ࣇী ߓval (x, y) = targetOffset!! - placementOffsetplaceable.place(x = x, y = y)}}}}
fun Modifier.transformation(lookaheadScope: LookaheadLayoutScope) = with(lookaheadScope) {intermediateLayout { measurable, _, lookaheadSize ->val (width, height) = lookaheadSize // lookahead ӝ۽ width, height Ѿval animatedConstraints = Constraints.fixed(width = width.coerceAtLeast(0), // ୭ࣗ 0 ਵ۽ ࢸheight = height.coerceAtLeast(0))val placeable = measurable.measure(animatedConstraints)layout(width = placeable.width, height = placeable.height) { // lookahead ӝী ݏѱ ߓplaceable.place(x = 0, y = 0)}}}
LookaheadLayout(modifier = modifier.fillMaxSize().navigationBarsPadding().padding(16.dp),content = {Fab(modifier = Modifier.size(size = FabDefaults.size(isExpanded = isExpanded,maxWidthDp = screenMaxWidth.dp)).movement(lookaheadScope = this).transformation(lookaheadScope = this).noRippleClickable { isExpanded = !isExpanded },isExpanded = isExpanded)},measurePolicy = DefaultMeasurePolicy)
startfinishLookaheadӝয়ࣇগפݫ࣌9
2. Animation
#FGPSF😣"GUFS🪄
ఫझ࢚࢝গפݫ࣌ ߓ҃ਤزগפݫ࣌ GBEFJOPVU TMJEFJOPVUGBEFJOPVU"GUFS🪄
ఫझ࢚࢝গפݫ࣌➡️BOJNBUF$PMPS"T4UBUF ߣبزੌ ߓ҃ਤزগפݫ࣌➡️ߓ࢚҃࢝গפݫ࣌ਵ۽द GBEFJOPVU➡️"OJNBUFE$POUFOU TMJEFJOPVUGBEFJOPVU➡️"OJNBUFE$POUFOU"GUFS🪄
Column(modifier = Modifier.fillMaxSize().background(color = Color.BackgroundWhite),verticalArrangement = Arrangement.SpaceBetween) {TabContainer {TabDefaults.Items.forEach { tab ->TabItem(title = tab.shortname,backgroundColor = tabBackgroundColor(selectedTab = selectedTabState, nowTab = tab),textColor = tabTextColor(selectedTab = selectedTabState, nowTab = tab),onTabClick = { selectedTabState = tab })}}MovieContainer {MovieName(fullname = selectedTabState.fullname)MoviePoster(posterDrawable = selectedTabState.poster)}}
@Stableprivate fun tabBackgroundColor(selectedTab: Int,nowTab: Int): Color = when (selectedTab == nowTab) {true -> TabDefaults.Color.selectedBackgroundfalse -> TabDefaults.Color.defaultBackground}@Stableprivate fun tabTextColor(selectedTab: Int,nowTab: Int): Color = when (selectedTab == nowTab) {true -> TabDefaults.Color.selectedTextfalse -> TabDefaults.Color.defaultText}@Composableprivate fun tabBackgroundColorWithAnimation(selectedTab: Tab,nowTab: Tab): Color = animateColorAsState(targetValue = when (selectedTab == nowTab) {true -> TabDefaults.Color.selectedBackgroundfalse -> TabDefaults.Color.defaultBackground}).value@Composableprivate fun tabTextColorWithAnimation(selectedTab: Tab,nowTab: Tab): Color = animateColorAsState(targetValue = when (selectedTab == nowTab) {true -> TabDefaults.Color.selectedTextfalse -> TabDefaults.Color.defaultText}).value
/*** [Color] ী ೠ Fire-and-Forget গפݫ࣌ ӝמਸ ઁҕפ.* animate*AsState ח [Float], [Color], [Dp], [Size], [Offset], [Rect], [Int], [IntOffset] ӒܻҊ [IntSize] ী ࢎ ظ णפ.* ઁҕػ [targetValue] о ߸҃غݶ গפݫ࣌ زਵ۽ प೯ؾפ.* [targetValue] о ߸҃ؼ ٸ ೯ ੋ গפݫ࣌ ח ҃ ೯ ੋ গפݫ࣌ ࢜۽ [targetValue] ܳ ೱ೧ গפݫ࣌غب۾ झܳ ઑפ.** animate*AsState ח গפݫ࣌ ਊغҊ ח [State] ܳ ߈ജפ.** @param targetValue গפݫ࣌ ఋѶ* @param animationSpec दрী ٮۄ чਸ ߸҃ೞח ؘ ࢎਊೡ গפݫ࣌* @param finishedListener গפݫ࣌ ৮ܐؼ ٸ ঌܿਸ ߉ח ࢶఖ ܻझց*/@Composablefun animateColorAsState(targetValue: Color,animationSpec: AnimationSpec = colorDefaultSpring,finishedListener: ((Color) -> Unit)? = null): State
গפݫ࣌ࢎনਸݏࢸೞӝਤೠੋఠಕझ TQSJOH UXFFO LFZGSBNFT SFQFBUBCMFJOGJOJUF3FQFBUBCMF TOBQ"OJNBUJPO4QFD
/*** द чҗ ч ࢎী ޛܻ ӝ߈ গפݫ࣌ਸ ਊפ.** @param DampingRatio х࣭࠺ (ࢿ)* @param stiffness ъࢿ (ઙܐ чਵ۽ زೞח ࣘب)* @param visibleThreshold оदࢿ ҅ч* গפݫ࣌ ࢚ী ߈ৢܿೞӝী ࠙ दпਵ۽ оө Ѫਵ۽ рغযঠ ೞח दӝܳ פ.** @return য ২࣌ਸ ࢎਊೞח [SpringSpec]*/@Stablefun spring(dampingRatio: Float = Spring.DampingRatioNoBouncy,stiffness: Float = Spring.StiffnessMedium,visibilityThreshold: T? = null): SpringSpec = SpringSpec(dampingRatio = dampingRatio,stiffness = stiffness,visibilityThreshold = visibilityThreshold)
/*** ҋࢶਸ ࢎਊೞৈ ػ [durationMillis] زউ द чҗ ч рী গפݫ࣌ਸ ਊפ.** @param durationMillis গפݫ࣌ ࣘ दр (ܻୡ)* @param delayMillis গפݫ࣌ दغӝ ী ӝೞח दр (ܻୡ)* @param easing दҗ ࢎܳ ࠁрೞח ؘ ࢎਊغח ҋࢶ** @return য ২࣌ਸ ࢎਊೞח [TweenSpec]*/@Stablefun tween(durationMillis: Int = AnimationConstants.DefaultDurationMillis,delayMillis: Int = 0,easing: Easing = FastOutSlowInEasing): TweenSpec = TweenSpec(durationMillis = durationMillis,delay = delayMillis,easing = easing)
/*** গפݫ࣌ ࠙ࣻ(fraction)ܳ ઑೞח ߑߨੑפ.* ਸ ࢎਊೞݶ গפݫ࣌ ੌೠ ࣘب۽ ೯غח न ࣘبܳ ֫Ѣա ծ ࣻ णפ.** ࠙ࣻח গפݫ࣌ അ ਸ աఋղח 0 ীࢲ 1.0 ࢎ чੑפ. ৈӝࢲ 0 दਸ աఋղҊ 1.0 ਸ աఋշפ.*/@Stablefun interface Easing {fun transform(fraction: Float): Float}
// ࡅܰѱ ࣘبܳ ֫Ҋ ରਵ۽ ו۰פ.val FastOutSlowInEasing: Easing = CubicBezierEasing(0.4f, 0.0f, 0.2f, 1.0f)// ٜযয়ח ਃࣗח ઁੌ ࡅܲ ࣘبীࢲ ו۰פ.val LinearOutSlowInEasing: Easing = CubicBezierEasing(0.0f, 0.0f, 0.2f, 1.0f)// աоח ਃࣗח ઁੌ וܽ ࣘبীࢲ ࡈۄפ.val FastOutLinearInEasing: Easing = CubicBezierEasing(0.4f, 0.0f, 1.0f, 1.0f)// ࣻغ ঋ ࠙ࣻܳ ߈ജפ. ਃೞ݅ ࣻػ ਃೞ ঋ ҃ ӝࠄчਵ۽ ਬਊפ.val LinearEasing: Easing = Easing { fraction -> fraction }// 3ର ߬য ҋࢶਸ ҳഅפ.@Immutableclass CubicBezierEasing(private val a: Float,private val b: Float,private val c: Float,private val d: Float) : Easing
IUUQTFBTJOHTOFU
/*** গפݫ࣌ ӝрী ৈ۞ ఋझఙীࢲ ػ झշࢫ чਸ ӝ߈ਵ۽ গפݫ࣌ਸ ܻפ.* ઁա গפݫ࣌ ч ف ఃۨ ч ࢎী ࠁрؾפ.* ఃۨ݃ ࢎਊೡ [Easing] ਸ ೡ ࣻ णפ.*/@Stablefun keyframes(init: KeyframesSpec.KeyframesSpecConfig.() -> Unit): KeyframesSpec = KeyframesSpec(config = KeyframesSpec.KeyframesSpecConfig().apply(init))@Composablefun KeyframesExample(target: Int) {val value by animateIntAsState(targetValue = target, // 0 ~ 100animationSpec = keyframes {durationMillis = 1000 // 1000 ms زউ গפݫ࣌ ೯100 at 50 with LinearEasing // LinearEasing ਸ ࢎਊೞݴ 100 ms উী 50 ө গפݫ࣌500 at 80 with FastOutSlowInEasing // FastOutSlowInEasing ਸ ࢎਊೞݴ 500 ms উী 80 ө গפݫ࣌// റ 501 ~ 1000 ms زউ ӝઓী ࢸೠ ੋ FastOutSlowInEasing ܳ ҅ࣘ ࢎਊೞৈ 100 ө গפݫ࣌})}
/*** ػ ߈ࠂ പࣻী ب׳ೡ ٸө ӝр ӝ߈ গפݫ࣌(: [tween] ژח [keyframes])ਸ ߈ࠂਵ۽ प೯פ.** @param iterations ߈ࠂೡ പࣻ* @param animation ߈ࠂೡ গפݫ࣌* @param repeatMode ߈ࠂೡ ݽ٘ - [RepeatMode.Restart] ژח [RepeatMode.Reverse]* @param initialStartOffset গפݫ࣌ਸ दೡ য়ࣇ*/@Stablefun repeatable(iterations: Int,animation: DurationBasedAnimationSpec,repeatMode: RepeatMode = RepeatMode.Restart,initialStartOffset: StartOffset = StartOffset(0)): RepeatableSpec = RepeatableSpec(iterations = iterations,animation = animation,repeatMode = repeatMode,initialStartOffset = initialStartOffset)
/*** [repeatable] җ زੌೞҊ, ਬੌೠ ର ޖೠ ߈ࠂۄ iterations ੋо হणפ.*/@Stablefun infiniteRepeatable(animation: DurationBasedAnimationSpec,repeatMode: RepeatMode = RepeatMode.Restart,initialStartOffset: StartOffset = StartOffset(0)): InfiniteRepeatableSpec = InfiniteRepeatableSpec(animation = animation,repeatMode = repeatMode,initialStartOffset = initialStartOffset)
/*** snap чਸ द ઙܐ чਵ۽ ߸ജೞח ౠࣻ ݾ [AnimationSpec] ੑפ.** @param delayMillis গפݫ࣌ दਸ োೡ दр (ܻୡ)*/@Stablefun snap(delayMillis: Int = 0): SnapSpec = SnapSpec(delay = delayMillis)
@Composablefun animateColorAsState(targetValue: Color,animationSpec: AnimationSpec = colorDefaultSpring,finishedListener: ((Color) -> Unit)? = null): State
MovieContainer {MovieName(fullname = selectedTabState.fullname)MoviePoster(posterDrawable = selectedTabState.poster)}MovieContainer {AnimatedContent(modifier = Modifier.align(Alignment.CenterHorizontally).padding(horizontal = 30.dp),targetState = selectedTabState) { tab ->MovieName(fullname = tab.fullname)}AnimatedContent(modifier = Modifier.wrapContentSize(),targetState = selectedTabState) { tab ->MoviePoster(posterDrawable = tab.poster)}}
/*** [targetState] о ߸҃ؼ ٸ [content] ী زਵ۽ গפݫ࣌ਸ ਊೞח ஶపցੑפ.** @param targetState ߸҃ؼ ࢚క* @param modifier ਊೡ [Modifier]* @param transitionSpec ਊೡ গפݫ࣌* @param contentAlignment [content] о ߓؼ [Alignment]* @param content ߓೡ ஹನ࠶*/@ExperimentalAnimationApi@Composablefun AnimatedContent(targetState: S,modifier: Modifier = Modifier,transitionSpec: AnimatedContentScope.() -> ContentTransform = { /* … */ },contentAlignment: Alignment = Alignment.TopStart,content: @Composable AnimatedVisibilityScope.(targetState: S) -> Unit)
@ExperimentalAnimationApi@Composablefun AnimatedContent(targetState: S,modifier: Modifier = Modifier,transitionSpec: AnimatedContentScope.() -> ContentTransform = {fadeIn(animationSpec = tween(durationMillis = 220,delayMillis = 90)) + scaleIn(initialScale = 0.92f,animationSpec = tween(durationMillis = 220,delayMillis = 90)) with fadeOut(animationSpec = tween(durationMillis = 90))},contentAlignment: Alignment = Alignment.TopStart,content: @Composable AnimatedVisibilityScope.(targetState: S) -> Unit)
/*** ஹನ࠶ [AnimatedContent] ী ٜযоҊ աоח ߑߨਸ פ.** @param targetContentEnter ࢜۽ ஹನ࠶ ٜযয়ח গפݫ࣌* @param initialContentExit ӝઓ ஹನ࠶ աоח গפݫ࣌* @param targetContentZIndex ஹನ࠶ ٜযয়Ҋ աт ٸ ࢎਊೡ zIndex* @param sizeTransform ஹನ࠶ ٜযয়Ҋ աт ٸ ࢎૉо ߸ೡ ҃ ܳ ҙܻೞӝ ਤೠ ২࣌*/@ExperimentalAnimationApiclass ContentTransform(val targetContentEnter: EnterTransition,val initialContentExit: ExitTransition,targetContentZIndex: Float = 0f,sizeTransform: SizeTransform? = SizeTransform()) {var targetContentZIndex by mutableStateOf(targetContentZIndex)var sizeTransform: SizeTransform? = sizeTransforminternal set}
@ExperimentalAnimationApiclass ContentTransform(val targetContentEnter: EnterTransition,val initialContentExit: ExitTransition,targetContentZIndex: Float = 0f,sizeTransform: SizeTransform? = SizeTransform()) {/*** ஶపցী ٜযт ٸ ࢜۽ ࢚ ஹನ࠶ zIndex ܳ פ.* ӝࠄч 0f ੑפ. zIndex о ֫ ஹನ࠶ zIndex о ծ ஹನ࠶ ਤী Ӓ۰פ.* ੋؙझо э ஹನ࠶ ఋѶ ஹನ࠶ ݔ ਤী ߓؾפ.*/var targetContentZIndex by mutableStateOf(targetContentZIndex)/*** ࢜ ஹನ࠶ AnimatedContent ী ٜযоҊ ஹನ࠶ աт ٸ ӝо ߸҃غח ҃ ஶపց ഛ ߂ ୷ࣗܳ ҙܻפ.* ӝࠄਵ۽ [spring][SpringSpec] ݽٚ ӝ ߸҃ਸ গפݫ࣌ೞח ؘ ࢎਊغݴ [AnimatedContent] ח গפݫ࣌ػ ӝ۽ ੜ݀פ.* ࢎਊؼ [SizeTransform] ܳ ࢸೡ ࣻ णפ. ӝ গפݫ࣌ ਃೞ ঋਵݶ [sizeTransform] ਸ null ۽ ࢸೞࣁਃ.*/var sizeTransform: SizeTransform? = sizeTransforminternal set}
/*** ஹನ࠶ दؼ ٸ ೯غח গפݫ࣌ਸ פ.* ࢎਊೡ ࣻ ח [EnterTransition] 4о పҊܻח җ эणפ.** 1. fade: [fadeIn]* 2. scale: [scaleIn]* 3. slide: [slideIn], [slideInHorizontally], [slideInVertically]* 4. expand: [expandIn], [expandHorizontally], [expandVertically]*/@Immutablesealed class EnterTransition {internal abstract val data: TransitionData@Stableoperator fun plus(enter: EnterTransition): EnterTransition {// …}}
@Immutablesealed class EnterTransition {internal abstract val data: TransitionData // ղࠗীࢲ ࢎਊೞח ࠁܳ ࠁҙೣ/*** ܲ [EnterTransition] ਸ Ѿפ. [EnterTransition] ח زदী दغ۽ Ѿغח ࣽࢲח ਃೞ ঋणפ.* গפݫ࣌ਸ ਊೞח ࣽࢲח ঌ ߂ ߓਯਸ ݢ ઑೞҊ ୷ࣗ ژח ഛೠ ठۄ٘פ.** @param enter Ѿೡ ܲ [EnterTransition]** @return 2ѐ [EnterTransition] Ѿػ ࢜۽ [EnterTransition]*/@Stableoperator fun plus(enter: EnterTransition): EnterTransition {return EnterTransitionImpl(TransitionData(fade = data.fade ?: enter.data.fade,slide = data.slide ?: enter.data.slide,changeSize = data.changeSize ?: enter.data.changeSize,scale = data.scale ?: enter.data.scale))}}
/*** ஹನ࠶ ࢎۄ ٸ ೯غח গפݫ࣌ਸ פ.* ࢎਊೡ ࣻ ח [ExitTransition] 4о పҊܻח җ эणפ.** 1. fade: [fadeOut]* 2. scale: [scaleOut]* 3. slide: [slideOut], [slideOutHorizontally], [slideOutVertically]* 4. shrink: [shrinkOut], [shrinkHorizontally], [shrinkVertically]*/@Immutablesealed class ExitTransition {internal abstract val data: TransitionData@Stableoperator fun plus(exit: ExitTransition): ExitTransition {// …}}
@Immutablesealed class ExitTransition {internal abstract val data: TransitionData // ղࠗীࢲ ࢎਊೞח ࠁܳ ࠁҙೣ/*** ܲ [ExitTransition] ਸ Ѿפ. [ExitTransition] ח زदী दغ۽ Ѿغח ࣽࢲח ਃೞ ঋणפ.* গפݫ࣌ਸ ਊೞח ࣽࢲח ঌ ߂ ߓਯਸ ݢ ઑೞҊ ୷ࣗ ژח ഛೠ ठۄ٘פ.** @param exit Ѿೡ ܲ [ExitTransition]** @return 2ѐ [ExitTransition] Ѿػ ࢜۽ [ExitTransition]*/@Stableoperator fun plus(exit: ExitTransition): ExitTransition {return ExitTransitionImpl(TransitionData(fade = data.fade ?: exit.data.fade,slide = data.slide ?: exit.data.slide,changeSize = data.changeSize ?: exit.data.changeSize,scale = data.scale ?: exit.data.scale))}}
@ExperimentalAnimationApiclass ContentTransform(val targetContentEnter: EnterTransition,val initialContentExit: ExitTransition,targetContentZIndex: Float = 0f,sizeTransform: SizeTransform? = SizeTransform()) {var targetContentZIndex by mutableStateOf(targetContentZIndex)var sizeTransform: SizeTransform? = sizeTransforminternal set}
/*** ஹನ࠶ ӝо ߸҃ؼ ٸ ೠ ӝীࢲ ܲ ӝ۽ ߸ജೞח ߑߨਸ פ.*/@ExperimentalAnimationApiinterface SizeTransform {/*** ࢎૉ ઑ গפݫ࣌ীࢲ ஹನ࠶ ҃҅ী ݏѱ clip ೧ঠ ೞח ৈࠗੑפ.*/val clip: Boolean/*** গפݫ࣌ ਊ ࢎૉੋ [initialSize] ৬ গפݫ࣌ ਊ റ ࢎૉੋ [targetSize] ܳ ӝ߈ਵ۽ [AnimationSpec] ਸ ٜ݅ ࣻ णפ.*/fun createAnimationSpec(initialSize: IntSize, targetSize: IntSize): FiniteAnimationSpec}
/*** ઁҕػ [this][EnterTransition] ߂ [exit] ܳ ࢎਊೞৈ [ContentTransform] ਸ ࢤࢿೞݴ,* [EnterTransition] ߂ [ExitTransition] গפݫ࣌ زदী प೯ؾפ.** @param exit [this][EnterTransition] ৬ ச [ExitTransition]** @return [this][EnterTransition] ৬ [ExitTransition] [ContentTransform]*/@ExperimentalAnimationApiinfix fun EnterTransition.with(exit: ExitTransition) = ContentTransform(targetContentEnter = this,initialContentExit = exit)
@ExperimentalAnimationApi@Composablefun AnimatedContent(targetState: S,modifier: Modifier = Modifier,transitionSpec: AnimatedContentScope.() -> ContentTransform = { /* … */ },contentAlignment: Alignment = Alignment.TopStart,content: @Composable AnimatedVisibilityScope.(targetState: S) -> Unit)
/*** [AnimatedContent] ীࢲ݅ ಞܻೞѱ ਊೡ ࣻ ח ӝמਸ ઁҕפ.*/@ExperimentalAnimationApiclass AnimatedContentScope internal constructor(internal val transition: Transition,internal var contentAlignment: Alignment,internal var layoutDirection: LayoutDirection) : Transition.Segment {override val initialState: S get() = transition.segment.initialState // গפݫ࣌ दغӝ ୡӝ чoverride val targetState: S get() = transition.segment.targetState // গפݫ࣌ ਊؼ ч, গפݫ࣌ ઙܐ ч/*** അ [this][ContentTransform] [sizeTransform] ܳ ੋ۽ ߉ [sizeTransform] ۽ ࢸפ.** @param sizeTransform ࢜۽ ਊೡ [SizeTransform]** @return [sizeTransform] ਸ ࢜۽ ਊೠ [ContentTransform]*/@ExperimentalAnimationApiinfix fun ContentTransform.using(sizeTransform: SizeTransform?): ContentTransform = apply {this.sizeTransform = sizeTransform}// …
/*** ஶపց оܻীࢲ [AnimatedContent] ী ౠೠ ࣻಣ/ࣻ slide-in ਸ פ.* [slideInHorizontally] ߂ [slideInVertically] ৬ ׳ܻ द য়ࣇ [AnimatedContent] * അ ӝ৬ ۳ ২࣌ਸ ӝ߈ਵ۽ ز ҅ؾפ.** @param towards ठۄ٘ ߑೱ* ஹನ࠶ח [SlideDirection.Left], [SlideDirection.Right], [SlideDirection.Up] ߂ [SlideDirection.Down]* ߑೱਵ۽ ஶపցܳ ೱ೧ slide ೡ ࣻ णפ.* @param animationSpec ࢎਊೡ গפݫ࣌* @param initialOffset द য়ࣇ. زਵ۽ ҅غ݅ द ࣻزਵ۽ ೡ ࣻب णפ.*/fun slideIntoContainer(towards: AnimatedContentScope.SlideDirection,animationSpec: FiniteAnimationSpec = spring(visibilityThreshold = IntOffset.VisibilityThreshold),initialOffset: (offsetForFullSlide: Int) -> Int = { it }): EnterTransition// slideIntoContainer ৬ زੌ, ױ slide-in न slide-outfun slideOutOfContainer(towards: AnimatedContentScope.SlideDirection,animationSpec: FiniteAnimationSpec = spring(visibilityThreshold = IntOffset.VisibilityThreshold),targetOffset: (offsetForFullSlide: Int) -> Int = { it }): ExitTransition}
@Composableprivate fun tabBackgroundColorWithAnimation(selectedTab: Tab,nowTab: Tab): Color = animateColorAsState(targetValue = when (selectedTab == nowTab) {true -> TabDefaults.Color.selectedBackgroundfalse -> TabDefaults.Color.defaultBackground}).value@Composableprivate fun tabTextColorWithAnimation(selectedTab: Tab,nowTab: Tab): Color = animateColorAsState(targetValue = when (selectedTab == nowTab) {true -> TabDefaults.Color.selectedTextfalse -> TabDefaults.Color.defaultText}).valueMovieContainer {AnimatedContent(modifier = Modifier.align(Alignment.CenterHorizontally).padding(horizontal = 30.dp),targetState = selectedTabState) { tab ->MovieName(fullname = tab.fullname)}AnimatedContent(modifier = Modifier.wrapContentSize(),targetState = selectedTabState,contentAlignment = Alignment.Center) { tab ->MoviePoster(posterDrawable = tab.poster)}}
TMJEFJOPVUGBEFJOPVU DMJQ5P1BEEJOHGBMTF [*OEFYਃೠࣁࠗগפݫ࣌🖌️
MovieContainer {AnimatedContent(modifier = Modifier.align(Alignment.CenterHorizontally).padding(horizontal = 30.dp),targetState = selectedTabState) { tab ->MovieName(fullname = tab.fullname)}AnimatedContent(modifier = Modifier.wrapContentSize(),targetState = selectedTabState,contentAlignment = Alignment.Center) { tab ->MoviePoster(posterDrawable = tab.poster)}}MovieContainer {AnimatedContent(modifier = Modifier.align(Alignment.CenterHorizontally).padding(horizontal = 30.dp),targetState = selectedTabState,transitionSpec = {fadeIn() with fadeOut() using SizeTransform(clip = false)}) { tab ->MovieName(fullname = tab.fullname)}// …}
MovieContainer {// …AnimatedContent(modifier = Modifier.wrapContentSize(),targetState = selectedTabState,contentAlignment = Alignment.Center,transitionSpec = {val targetIndex = targetState.index // targetState == Tabval initialIndex = initialState.index // initialState == Tabif (targetIndex > initialIndex) { // చslideIntoContainer(towards = AnimatedContentScope.SlideDirection.Start) with fadeOut() using SizeTransform(clip = false)} else { // చfadeIn() with slideOutOfContainer(towards = AnimatedContentScope.SlideDirection.End) using SizeTransform(clip = false)}.apply {targetContentZIndex = targetIndex.toFloat()}}) { tab ->MoviePoster(posterDrawable = tab.poster)}}MovieContainer {AnimatedContent(modifier = Modifier.align(Alignment.CenterHorizontally).padding(horizontal = 30.dp),targetState = selectedTabState) { tab ->MovieName(fullname = tab.fullname)}AnimatedContent(modifier = Modifier.wrapContentSize(),targetState = selectedTabState,contentAlignment = Alignment.Center) { tab ->MoviePoster(posterDrawable = tab.poster)}}
🤔
/*** ࢚క ࣻળীࢲ ݽٚ গפݫ࣌ਸ ҙܻפ.* গפݫ࣌ [Transition.animateFloat], [Transition.animateColor], [Transition.animateValue] ١ਸ* ࢎਊೞৈ ࢶੋ ߑधਵ۽ ٜ݅ ࣻ णפ.** @param initialState গפݫ࣌ ୡӝ ч* @param label Android Studio Animation Inspector ীࢲ [Transition] ਸ ҳ߹ೞח ؘ ࢎਊೡ కӒ*/@Stableclass Transition @PublishedApi internal constructor(initialState: S,label: String?)
/*** [Transition] ਸ ࢤࢿೞҊ [targetState] чਵ۽ ୡӝ ࢚కܳ פ.* [targetState] о ߸҃غݶ [Transition] ࢜ [targetState] чਵ۽ ٜ݅য ݽٚ গפݫ࣌ਸ ઑפ.** @param targetState ߸҃ਸ хೡ ࢚* @param label Android Studio Animation Inspector ীࢲ [Transition] ਸ ҳ߹ೞח ؘ ࢎਊೡ కӒ** @return [targetState] чਵ۽ ୡӝ ࢚కо ػ [Transition]*/@Composablefun updateTransition(targetState: T,label: String? = null): Transition
/*** ػ [Transition] ী ࢝ӭ গפݫ࣌ਸ ୶оפ.* ח গפݫ࣌ ࢤݺ ӝо [Transition] ী ೧ ҙܻؽਸ פ.** @param transitionSpec ਊೡ গפݫ࣌* @param label Android Studio Animation Inspector ীࢲ [Transition] ਸ ҳ߹ೞח ؘ ࢎਊೡ కӒ* @param targetValueByState ػ [Transition] গפݫ࣌ दعਸ ٸ ઁҕೡ ч** @return গפݫ࣌ ਊػ [Color] [State]*/@Composableinline fun Transition.animateColor(noinline transitionSpec: @Composable Transition.Segment.() -> FiniteAnimationSpec = { spring() },label: String = "ColorAnimation",targetValueByState: @Composable (state: S) -> Color): State
/*** ࢚ਤ [Transition] ࢚క৬ ೞਤ ࢚క р ݒೝਸ ӝ߈ਵ۽ ೞਤ [Transition] ਸ ٟ݅פ.* ח җ э ਊب۽ ࢎਊؾפ:** 1. ೞਤ [Transition] ࢚కܳ ࢚ਤ [Transition] ਵ۽ ഐझ* ࢚ਤ [Transition] زੌೠ ࢚ ࢚క ߸҃ਵ۽ ੋ೧ ೯ ੋ গפݫ࣌ ח ৈࠗܳ ੋधפ.* ۧѱ ೞݶ ࢎী ೯؍ গפݫ࣌ ৮ܐغਸ ٸ ࣽରਵ۽ ܲ গפݫ࣌ਸ ࢸೡ ࣻ णפ.** 2. ҙबࢎ ܻ࠙* ࢚ਤ [Transition] ীࢲ ߉ ࢚కীࢲ ࢎਊೞח ࠁ݅ ఠ݂ೞৈ ೞਤ۽ ׳ೞҊ रਸ ٸ ਬਊೞѱ ॳੌ ࣻ णפ.** @param label Android Studio Animation Inspector ীࢲ [Transition] ਸ ҳ߹ೞח ؘ ࢎਊೡ కӒ* @param transformToChildState ࢚ਤ [Transition] ীࢲ чਸ ߉Ҋ ࢜۽ ݅ٚ ࢚క ч** @return ࢜۽ ࢚కܳ оח ೞਤ [Transition]*/@ExperimentalTransitionApi@Composableinline fun Transition.createChildTransition(label: String = "ChildTransition",transformToChildState: @Composable (parentState: S) -> T): Transition
var selectedTabState by remember { mutableStateOf(TabDefaults.Items.first()) }val selectedTabTypeTransition = updateTransition(targetState = selectedTabState.type,label = "selected tab")// …TabContainer {TabDefaults.Items.forEach { tab ->val backgroundColor by selectedTabTypeTransition.animateColor(transitionSpec = { defaultTween() },label = "background color") { movie ->when (movie == tab.type) {true -> TabDefaults.Color.selectedBackgroundfalse -> TabDefaults.Color.defaultBackground}}val textColor by selectedTabTypeTransition.animateColor(transitionSpec = { defaultTween() },label = "text color") { movie ->when (movie == tab.type) {true -> TabDefaults.Color.selectedText
) { movie ->when (movie == tab.type) {true -> TabDefaults.Color.selectedBackgroundfalse -> TabDefaults.Color.defaultBackground}}val textColor by selectedTabTypeTransition.animateColor(transitionSpec = { defaultTween() },label = "text color") { movie ->when (movie == tab.type) {true -> TabDefaults.Color.selectedTextfalse -> TabDefaults.Color.defaultText}}TabItem(title = tab.shortname,backgroundColor = backgroundColor,textColor = textColor,onTabClick = {selectedTabState = tab})}}
MovieContainer {AnimatedContent(modifier = Modifier.align(Alignment.CenterHorizontally).padding(horizontal = 30.dp),targetState = selectedTabState,// … ӝઓҗ زੌ) { tab ->MovieName(fullname = tab.fullname)}AnimatedContent(modifier = Modifier.wrapContentSize(),targetState = selectedTabState,// … ӝઓҗ زੌ) { tab ->MoviePoster(posterDrawable = tab.poster)}}
/*** [this][Transition] targetState о ߸҃ؼ ٸ زਵ۽ [content] ী গפݫ࣌ਸ ਊೞח ஶపցੑפ.** @param modifier ਊೡ [Modifier]* @param transitionSpec ਊೡ গפݫ࣌* @param contentAlignment [content] о ߓؼ [Alignment]* @param contentKey [Transition] targetState ী ೠ ః. زੌೠ ఃܳ ҕਬೞח ߸҃ੌ ҃ গפݫ࣌ ೯غ ঋणפ.* @param content ߓೡ ஹನ࠶*/@ExperimentalAnimationApi@Composablefun Transition.AnimatedContent(modifier: Modifier = Modifier,transitionSpec: AnimatedContentScope.() -> ContentTransform = {// ӝઓ AnimatedContent ৬ زੌ},contentAlignment: Alignment = Alignment.TopStart,contentKey: (targetState: S) -> Any? = { it },content: @Composable AnimatedVisibilityScope.(targetState: S) -> Unit)
MovieContainer {selectedTabTypeTransition.createChildTransition(label = "selected tab fullname") { movie ->movie.fullname}.AnimatedContent(/* ӝઓҗ زੌ */) { tabFullname ->MovieName(fullname = tabFullname)}selectedTabTypeTransition.AnimatedContent(/* ӝઓҗ زੌ */) { movie ->MoviePoster(posterDrawable = movie.poster)}}
ࢶఖߓ҃য়ࣇز ࢶఖߓ҃ݽন ۄ٬ਃೠࣁࠗগפݫ࣌🖌️
@Composableprivate fun MovieTab(selectedTabTypeTransition: Transition,updateSelectedTab: (tab: Tab) -> Unit) {BoxWithConstraints(modifier = Modifier.fillMaxWidth().wrapContentHeight().clip(RoundedCornerShape(bottomStartPercent = DefaultCornerUnit,bottomEndPercent = DefaultCornerUnit))) {val backgroundBoxWidth = remember { maxWidth / TabDefaults.Items.count() }val backgroundOffsetTransition by selectedTabTypeTransition.animateIntOffset(transitionSpec = { defaultTween() },label = "background offset") { movie ->IntOffset(x = with(LocalDensity.current) {(eachItemWidth * movie.index).toPx()}.toInt(),
)) {val eachItemWidth = remember { maxWidth / TabDefaults.Items.count() }val backgroundOffsetTransition by selectedTabTypeTransition.animateIntOffset(transitionSpec = { defaultTween() },label = "background offset") { movie ->IntOffset(x = with(LocalDensity.current) {(backgroundBoxWidth * movie.index).toPx() // dp -> float}.toInt(), // float -> inty = 0)}val backgroundShapeTransition by selectedTabTypeTransition.animateValue(transitionSpec = { defaultTween() },label = "background shape",typeConverter = TwoWayConverter(convertToVector = { corner ->AnimationVector4D(v1 = corner.topStart.toPercent(),v2 = corner.topEnd.toPercent(),v3 = corner.bottomStart.toPercent(),v4 = corner.bottomEnd.toPercent())},convertFromVector = { vector ->
/*** গפݫ࣌ী ࢎਊغח ݽٚ ؘఠ ਬഋ ରਗী ٮۄ* [AnimationVector1D], [AnimationVector2D], [AnimationVector3D] ژח [AnimationVector4D] ۽ ߸ജؾפ.* ٮۄࢲ ё ৈ۞ ҳࢿਃࣗܳ пп ࣘب ୶ ӝמਸ ࢎਊೞৈ ة݀ਵ۽ গפݫ࣌ ܻೡ ࣻ णפ.** ܳ ٜয [Color] ח A, R, G, B 4ѐ ҳࢿ ਃࣗ۽ ܖযઉ णפ.* ٮۄࢲ [AnimationVector4D] ܳ ࢎਊפ.*/sealed class AnimationVector {internal abstract fun reset()internal abstract fun newVector(): AnimationVectorinternal abstract operator fun get(index: Int): Floatinternal abstract operator fun set(index: Int, value: Float)internal abstract val size: Int}
/*** ఋੑ [T] ীࢲ [AnimationVector] ۽ ߸ജೞҊ [AnimationVector] ܳ द ఋੑ [T] ۽ ߸ജೞח ߑߨী ೠ о ನೣغয णפ.* ܳ ా೧ গפݫ࣌ਸ ݽٚ ఋੑ ѐীࢲ ҳഅೡ ࣻ णפ.*/interface TwoWayConverter {/*** ఋੑ [T] ਸ [AnimationVector] ఋੑਵ۽ ߸ജೞח ߑߨਸ פ.*/val convertToVector: (T) -> V/*** [AnimationVector] ఋੑਸ द ఋੑ [T] ۽ ߸ജೞח ߑߨਸ פ.*/val convertFromVector: (V) -> T}
)}val backgroundShapeTransition by selectedTabTypeTransition.animateValue(transitionSpec = { defaultTween() },label = "background shape",typeConverter = TwoWayConverter(convertToVector = { corner ->AnimationVector4D(v1 = corner.topStart.getPercent(),v2 = corner.topEnd.getPercent(),v3 = corner.bottomStart.getPercent(),v4 = corner.bottomEnd.getPercent())},convertFromVector = { vector ->RoundedCornerShape(topStartPercent = vector.v1.toInt(),topEndPercent = vector.v2.toInt(),bottomStartPercent = vector.v3.toInt(),bottomEndPercent = vector.v4.toInt())})) { movie ->when (movie) {Movie.Thor -> RoundedCornerShape(bottomStartPercent = 30)Movie.Spider -> RoundedCornerShape(percent = 0)
)) { movie ->when (movie) {Movie.Thor -> RoundedCornerShape(bottomStartPercent = 30) // ৽ଃ -> ৽ଃ ೞױ݅ ۄ٬Movie.Spider -> RoundedCornerShape(percent = 0) // оؘ -> ۄ٬ XMovie.Doctor -> RoundedCornerShape(bottomEndPercent = 30) // য়ܲଃ -> য়ܲଃ ೞױ݅ ۄ٬}}TabContainer {TabDefaults.Items.forEach { tab ->val textColor by selectedTabTypeTransition.animateColor(transitionSpec = { defaultTween() },label = "text color") { movie ->when (movie == tab.type) {true -> TabDefaults.Color.selectedTextfalse -> TabDefaults.Color.defaultText}}TabItem(title = tab.shortname,backgroundColor = TabDefaults.Color.defaultBackground,textColor = textColor,onTabClick = {
false -> TabDefaults.Color.defaultText}}TabItem(title = tab.shortname,backgroundColor = TabDefaults.Color.defaultBackground,textColor = textColor,onTabClick = {updateSelectedTab(tab)})}}Box(modifier = Modifier.width(backgroundBoxWidth).height(TabDefaults.Height).offset { backgroundOffsetTransition }.clip(backgroundShapeTransition).background(color = TabDefaults.Color.selectedBackground))}}
🤩🥳
\startfinishLookaheadӝয়ࣇগפݫ࣌9
fun Modifier.movement(lookaheadScope: LookaheadLayoutScope) = composed {var targetOffset: IntOffset? by remember { mutableStateOf(null) }var placementOffset by remember { mutableStateOf(IntOffset.Zero) }// 1. ӝࠄч হ: animateAsState X// 2. গפݫ࣌ чਵ۽ ೧ ч হ: Transition Xwith(lookaheadScope) {this@composed.onPlaced { lookaheadScopeCoordinates, layoutCoordinates ->targetOffset = lookaheadScopeCoordinates.localLookaheadPositionOf(sourceCoordinates = layoutCoordinates).round()placementOffset = lookaheadScopeCoordinates.localPositionOf(sourceCoordinates = layoutCoordinates,relativeToSource = Offset.Zero).round()}.intermediateLayout { measurable, constraints, _ ->val placeable = measurable.measure(constraints)layout(width = placeable.width, height = placeable.height) {val (x, y) = targetOffset!! - placementOffset
fun Modifier.transformation(lookaheadScope: LookaheadLayoutScope) = with(lookaheadScope) {intermediateLayout { measurable, _, lookaheadSize ->val (width, height) = lookaheadSize// 1. ӝࠄч হ: animateAsState X// 2. গפݫ࣌ чਵ۽ ೧ ч হ: Transition Xval animatedConstraints = Constraints.fixed(width = width.coerceAtLeast(0),height = height.coerceAtLeast(0))val placeable = measurable.measure(animatedConstraints)layout(width = placeable.width, height = placeable.height) {placeable.place(x = 0, y = 0)}}}
/*** [animateTo] ܳ ా೧ ч ߸҃ؼ ٸ زਵ۽ чী গפݫ࣌ਸ ਊೞח ч ഓ؊ੑפ.*/class Animatable(initialValue: T, // ୡӝ чval typeConverter: TwoWayConverter, // গפݫ࣌ ёী ࢎਊೡ AnimationVectorprivate val visibilityThreshold: T? = null // оदࢿ ҅ч) {// গפݫ࣌ അ чval value: T get() = internalState.value// അ গפݫ࣌ ࢚. গפݫ࣌ ױ হ աݶ ݾ чী ب׳פ.var taretValue: T by mutableStateOf(initialValue)private set// targetValue чਸ ೱ೧ গפݫ࣌ਸ दפ. block ੋח ݒ গפݫ࣌ ۨ ݃ ഐؾפ.suspend fun animateTo(targetValue: T,animationSpec: AnimationSpec = defaultSpringSpec,initialVelocity: T = velocity,block: (Animatable.() -> Unit)? = null): AnimationResult}
fun Modifier.animateMovement(lookaheadScope: LookaheadLayoutScope,animationSpec: AnimationSpec = defaultSpring()) = composed {var placementOffset by remember { mutableStateOf(IntOffset.Zero) }var targetOffset: IntOffset? by remember { mutableStateOf(null) }var targetOffsetAnimation: Animatable? by remember {mutableStateOf(null)}LaunchedEffect(Unit) {snapshotFlow { targetOffset }.collect { target ->if (target != null && target != targetOffsetAnimation?.targetValue) {targetOffsetAnimation?.run {launch {animateTo(targetValue = target,animationSpec = animationSpec)}} ?: Animatable(initialValue = target,typeConverter = IntOffset.VectorConverter).let { offsetAnimatable ->
animationSpec = animationSpec)}} ?: Animatable(initialValue = target,typeConverter = IntOffset.VectorConverter).let { offsetAnimatable ->targetOffsetAnimation = offsetAnimatable}}}}with(lookaheadScope) {this@composed.onPlaced { /* ӝઓҗ زੌ */ }.intermediateLayout { measurable, constraints, _ ->val placeable = measurable.measure(constraints)layout(width = placeable.width, height = placeable.height) {val (x, y) = (targetOffsetAnimation?.value ?: targetOffset!!) - placementOffsetplaceable.place(x = x, y = y)}}}}
fun Modifier.animateTransformation(lookaheadScope: LookaheadLayoutScope,animationSpec: AnimationSpec = defaultSpring()) = composed {var targetSize: IntSize? by remember { mutableStateOf(null) }var targetSizeAnimation: Animatable? by remember {mutableStateOf(null)}LaunchedEffect(Unit) {snapshotFlow { targetSize }.collect { target ->if (target != null && target != targetSizeAnimation?.targetValue) {targetSizeAnimation?.run {launch {animateTo(targetValue = target,animationSpec = animationSpec)}} ?: Animatable(initialValue = target,typeConverter = IntSize.VectorConverter).let { sizeAnimatable ->targetSizeAnimation = sizeAnimatable}
} ?: Animatable(initialValue = target,typeConverter = IntSize.VectorConverter).let { sizeAnimatable ->targetSizeAnimation = sizeAnimatable}}}}with(lookaheadScope) {[email protected] { measurable, _, lookaheadSize ->targetSize = lookaheadSizeval (width, height) = targetSizeAnimation?.value ?: lookaheadSizeval animatedConstraints = Constraints.fixed(width = width.coerceAtLeast(0),height = height.coerceAtLeast(0))val placeable = measurable.measure(animatedConstraints)layout(width = placeable.width, height = placeable.height) {placeable.place(x = 0, y = 0)}}}
ೞա"OJNBUJPO4QFD݅оמ ೞաগפݫ࣌݅оמ ೞաఋੑ݅оמ"OJNBUF<5>4UBUF4UBUF<5>"OJNBUF"T4UBUF"OJNBUJPO4QFDPCKFDU PCKFDU
ৈ۞ѐ"OJNBUJPO4QFDоמ ৈ۞ѐগפݫ࣌оמ ೞաఋੑ݅оמ"OJNBUBCMF<5>4UBUF<5>PCKFDU PCKFDUBOJNBUF5PBOJNBUF5P"OJNBUJPO4QFD"OJNBUJPO4QFD"OJNBUBCMF
ৈ۞ѐ"OJNBUJPO4QFDоמ ৈ۞ѐগפݫ࣌оמ ৈ۞ѐఋੑоמ উ٘۽٘झౚ٣য়JOTQFDUоמ5SBOTJUJPO <5>4UBUF<5>5SBOTJUJPOPCKFDU PCKFDUBOJNBUF<5>BOJNBUF<5>"OJNBUJPO4QFD"OJNBUJPO4QFD
3. Internal System↟-JWF-JUFSBM↟4UBCJMJUZ
fun earth() {print("Bye World")}
fun earth() {print(LiveLiterals$EarthKt.`getString$arg-0$call-print$fun-earth`())}object LiveLiterals$EarthKt {var `String$arg-0$call-print$fun-earth` = "Bye World"var `State$String$arg-0$call-print$fun-earth`: MutableState? = nullfun `getString$arg-0$call-print$fun-earth`(): String {val field = this.`String$arg-0$call-print$fun-earth`val state = if (field == null) {val tmp = liveLiteral("String$arg-0$call-print$fun-earth",this.`String$arg-0$call-print$fun-earth`)this.`String$arg-0$call-print$fun-earth` = tmptmp} else fieldreturn field.value}}
private val liveLiteralCache = HashMap>()@InternalComposeApi@ComposeCompilerApifun liveLiteral(key: String, value: T): State {return liveLiteralCache.getOrPut(key) {mutableStateOf(value)} as State}
@InternalComposeApifun updateLiveLiteralValue(key: String, value: Any?) {var needToUpdate = trueval stateObj = liveLiteralCache.getOrPut(key) {needToUpdate = falsemutableStateOf(value)}if (needToUpdate) {stateObj.value = value}}
private fun findEffectiveRecomposeScope(group: Int): RecomposeScopeImpl? {var current = groupwhile (current > 0) {for (data in DataIterator(this, current)) {if (data is RecomposeScopeImpl) {return data}}current = groups.parentAnchor(current)}return null}
// @Composable XXXfun earth() {print(LiveLiterals$EarthKt.`getString$arg-0$call-print$fun-earth`())}object LiveLiterals$EarthKt {var `String$arg-0$call-print$fun-earth` = "Bye World"var `State$String$arg-0$call-print$fun-earth`: MutableState? = nullfun `getString$arg-0$call-print$fun-earth`(): String {val field = this.`String$arg-0$call-print$fun-earth`val state = if (field == null) {val tmp = liveLiteral("String$arg-0$call-print$fun-earth",this.`String$arg-0$call-print$fun-earth`)this.`String$arg-0$call-print$fun-earth` = tmptmp} else fieldreturn field.value}}
/*** LiveLiteral ெઉ ח ҃ীب ਊغח ߧਤ ղীࢲ LiveLiteral ਸ ࢤࢿೞ ঋب۾* ஹನૉ ஹੌ۞ী दೞח ؘ ࢎਊؾפ.*/@Target(AnnotationTarget.PROPERTY,AnnotationTarget.FUNCTION,AnnotationTarget.CLASS,AnnotationTarget.FILE)@Retention(AnnotationRetention.SOURCE)annotation class NoLiveLiterals@NoLiveLiteralsfun earth() {print("Bye World")}
/*** উ ࢚కח ѱ 3о ઑѤਸ ٮܵפ.** - ч ߸҃عਸ ҃ ஹನ࠶ীѱ ঌ۰ઉঠ פ. (, [State] ۽ زظঠ ೣ)* - ੋझఢझ৬ അ ੋझఢझо زੌ೧ঠ פ.* - ݽٚ ҕѐ ٜ٘ب উ ࢚కৈঠ פ.** 3о ઑѤਸ ٮܲݶ ஹನૉח ೧ ٘о উੋ ࢚కۄҊ ঈೞҊ,* ೧ ٘ ч ߄Շ ঋওݶ ࢎਊػ ஹನ࠶ ܻஹನ࣌ਸ ࢤۚפ.** @see Immutable* @see Stable*/@Target(AnnotationTarget.ANNOTATION_CLASS, AnnotationTarget.CLASS)@Retention(AnnotationRetention.BINARY)annotation class StableMarker
/*** ࢤࢿػ റ۽ ݽٚ ҕѐੋ ٘о ߸ೞ ঋחח Ѫਸ աఋղݴ ېझী ਊؼ ࣻ णפ.** ࢤࢿ റ ч ߸҃غ ঋਵ۽ উ ߣ૩ ӏੋ* "ч ߸҃عਸ ҃ ஹನ࠶ীѱ ঌ۰ઉঠ פ." о ޖदؾפ.*/@Target(AnnotationTarget.CLASS)@Retention(AnnotationRetention.BINARY)@StableMarkerannotation class Immutablefun main() {val list = mutableListOf(1)list.add(2) // ੋझఢझח زੌೞ݅ ч ߄Չ ࣻ णפ.// @Immutable ۞ೠ ߸҃ب ೲਊೞ ঋणפ.}
/*** ч ߸҃ؼ ࣻ ח ࢚కݴ, ਊ ࢚ী ٮۄ ডрঀ ೡ ׳ۄפ.** ఋੑী ਊػݶ ୶о ೡ হ [StableMarker] ೡਸ Ӓ۽ оઉцפ.** ೣࣻա ۽ಌ౭ী ਊػݶ [StableMarker] ೡী ୶оغח ೡ ࢤӤפ.* э input ী যࢲח ೦࢚ زੌೠ output ਸ ٜ݅যղݴ(ࣽࣻ ೣࣻ), ೣࣻ ҃ ੋٜ द ݽف উੋ ࢚కۄח Ѫਸ ডࣘפ.* ݅ড input زੌೞݶ output ژೠ زੌೡ Ѫӝ ٸޙী ܻஹನ࣌ਸ झఈೞѱ ؾפ.*/@Target(AnnotationTarget.CLASS,AnnotationTarget.FUNCTION,AnnotationTarget.PROPERTY_GETTER,AnnotationTarget.PROPERTY)@Retention(AnnotationRetention.BINARY)@StableMarkerannotation class Stable
/*** ஹੌ दী ݽٚ ېझٜ উࢿਸ زਵ۽ ୶ۿפ.** @param parameters উࢿਸ ୶ۿೞחؘ ب ؼ ࣻ ѱ ੋٜ ࠺݃झܳ աఋշפ.*/@ComposeCompilerApi@Target(AnnotationTarget.CLASS)@Retention(AnnotationRetention.BINARY)annotation class StabilityInferred(val parameters: Int)// ਬੌೠ ٘ੋ value о উ ࢚కҊ ࠛ߸ೞӝ ٸޙী Name ېझח উ ࢚క۽ ౸ױؾפ.class Name(val value: String)// ਬੌೠ ٘ੋ value ఋੑ ઁ֎ܼۄ ఋੑਸ ౸ױೡ ࣻ হӝী ࢎী ࠺݃झఊػ чਸ ӝળਵ۽ উ ࢚కܳ ୶ۿפ.// ೞ݅ ٘о о߸ ࢚కӝ ٸޙী T ఋੑ উৈب NameWithGeneric ېझח ࠛউ ࢚క۽ ౸ױؾפ.class NameWithGeneric(var value: T)
@Composablefun TextWithImmutableList(texts: List) {Text(text = texts.joinToString())}
public interface MutableList : List, MutableCollection@Composablefun TextWithImmutableList(texts: List = mutableListOf()) {Text(text = texts.joinToString())}
@Immutableclass ImmutableListWrapper(val values: List)@Composablefun TextWithImmutableList(texts: ImmutableListWrapper) {Text(text = texts.values.joinToString())}
// https://github.com/Kotlin/kotlinx.collections.immutable@Composablefun TextWithImmutableList(texts: ImmutableList) {Text(text = texts.joinToString())}
4. Compiler Debugging↟CVJMENFUSJDT↟CVJMESFQPSUT
CVJMENFUSJDT// ஹੌ۞о хೠ ஹನ࠶ ೣٜࣻ ࠁܳ աఋշפ.kotlinOptions {freeCompilerArgs += ["-P","plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=" +"${rootProject.file(".").absolutePath}/report/compose-metrics"]}
<ݽٕݺ>@<࠽٘ఋੑ>NPEVMFKTPO{{"skippableComposables": 48, // skippable ࢚కੋ ஹನ࠶ ѐࣻ"restartableComposables": 67,"readonlyComposables": 0,"totalComposables": 67, // ஹನ࠶ ѐࣻ"restartGroups": 67,"totalGroups": 72,"staticArguments": 130,"certainArguments": 28,"knownStableArguments": 793, // উ ࢚క۽ ঌ۰ ੋ ѐࣻ"knownUnstableArguments": 30, // ࠛউ ࢚క۽ ঌ۰ ੋ ѐࣻ"unknownStableArguments": 8,"totalArguments": 831,"markedStableClasses": 0,"inferredStableClasses": 16, // উ ࢚క۽ ୶ۿػ ېझ ѐࣻ"inferredUnstableClasses": 2, // ࠛউ ࢚క۽ ୶ۿػ ېझ ѐࣻ"inferredUncertainClasses": 0,"effectivelyStableClasses": 16,"totalClasses": 18,"memoizedLambdas": 54,"singletonLambdas": 5,"singletonComposableLambdas": 8,"composableLambdas": 31,"totalLambdas": 89}
CVJMESFQPSUT// ஹੌ۞о хೠ ஹನ࠶ ೣٜࣻ ࢎਊੋ ېझ৬ ੋী ೠ উࢿ ࠁܳ աఋշפ.kotlinOptions {freeCompilerArgs += ["-P","plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=" +"${rootProject.file(".").absolutePath}/report/compose-reports"]}
<ݽٕݺ>@<࠽٘ఋੑ>DMBTTFTUYU/* ——— classes ——— */sealed class UiState {object Loading : UiState()object Done : UiState()data class Exception(val throwable: Throwable) : UiState()}/* ——— reports ——— */stable class Loading { = Stable}stable class Done { = Stable}unstable class Exception {unstable val throwable: Throwable = Unstable}
<ݽٕݺ>@<࠽٘ఋੑ>DPNQPTBCMFTDTW/* ——— composables ——— */@Composablefun DisplayText(text: String = "Hi") {Text(text = text)}@Composablefun DisplayTexts(texts: List) {Text(text = texts.joinToString())}/* ——— reports ——— */
<ݽٕݺ>@<࠽٘ఋੑ>DPNQPTBCMFTUYU/* ——— composables ——— */@Composablefun DisplayText(text: String = "Hi") {Text(text = text)}@Composablefun DisplayTexts(texts: List) {Text(text = texts.joinToString())}/* ——— reports ——— */restartable skippable scheme("[androidx.compose.ui.UiComposable]") fun DisplayText(stable text: String? = @dynamic LiveLiterals$MainActivityKt.String$param-text$fun-DisplayText())restartable /* skippable হ */ scheme("[androidx.compose.ui.UiComposable]") fun DisplayTexts(unstable texts: List)
<ݽٕݺ>@<࠽٘ఋੑ>DPNQPTBCMFTUYU/* ——— composables ——— */@Composablefun DisplayText(text: String = "Hi") {Text(text = text)}@Composablefun DisplayTexts(texts: List) {Text(text = texts.joinToString())}/* ——— reports ——— */restartable skippable scheme("[androidx.compose.ui.UiComposable]") fun DisplayText(stable text: String? = @dynamic LiveLiterals$MainActivityKt.String$param-text$fun-DisplayText())restartable scheme("[androidx.compose.ui.UiComposable]") fun DisplayTexts(unstable texts: List)
<ݽٕݺ>@<࠽٘ఋੑ>DPNQPTBCMFTUYU/* ——— composables ——— */@NoLiveLiterals // new@Composablefun DisplayText(text: String = "Hi") {Text(text = text)}@Composablefun DisplayTexts(texts: List) {Text(text = texts.joinToString())}/* ——— reports ——— */restartable skippable scheme("[androidx.compose.ui.UiComposable]") fun DisplayText(stable text: String? = @static "Hi")restartable scheme("[androidx.compose.ui.UiComposable]") fun DisplayTexts(unstable texts: List)
5. Best Practice↟ܻஹನ࣌ߧਤӝ↟ܻஹನ࣌হগӝ↟ࠛਃೠ࢚క୶ઁѢ↟"05ஹੌഝࢿച
EPOVUIPMFTLJQQJOHsetContent {var number by remember { mutableStateOf(0) }println("setContent recomposition")Text(modifier = Modifier.clickable { number++ },text = number.toString()).also { println("Text recomposition") }}/*ܻஹನ࣌ য٣ী ೯ؼөਃ?1, setContent content 2. Text3. setContent content + Text*/
EPOVUIPMFTLJQQJOHsetContent {var number by remember { mutableStateOf(0) }println("setContent recomposition")Text(modifier = Modifier.clickable { number++ },text = number.toString()).also { println("Text recomposition") }}/*[first-composition]setContent recompositionText recomposition[re-composition]setContent recompositionText recompositionറ زੌ ۽Ӓ ߈ࠂ*/
EPOVUIPMFTLJQQJOHsetContent {var number by remember { mutableStateOf(0) }println("setContent recomposition")Button(onClick = { number++ }) {Text(text = number.toString()).also { println("Text recomposition") }}.also { println("Button recomposition") }}/*[first-composition]setContent recompositionText recompositionButton recomposition[re-composition]Text recompositionറ زੌ ۽Ӓ ߈ࠂ*/
EPOVUIPMFTLJQQJOH// ஹੌ @Composablefun TextWrapper(text: String) {Text(text = text)}// ஹੌ റ (೨ब ࠗ࠙݅ द)@Composablefun TextWrapper(composer: Composer, text: String) {composer.startRestartGroup(-199242123) // ղࠗীࢲ addRecomposeScope() ۽ ܻஹನ࣌ झܳ ୶оೞҊ Text(text = text)composer.endRestartGroup()}
EPOVUIPMFTLJQQJOHsetContent {var number by remember { mutableStateOf(0) }println("setContent recomposition")Text(modifier = Modifier.clickable { number++ },text = number.toString()).also { println("Text recomposition") }}setContent {var number by remember { mutableStateOf(0) }println("setContent recomposition")Button(onClick = { number++ }) {Text(text = number.toString()).also { println("Text recomposition") }}.also { println("Button recomposition") }}Text RecomposeScope Text RecomposeScope
EPOVUIPMFTLJQQJOHsetContent {var number by remember { mutableStateOf(0) }println("setContent recomposition")Button(onClick = { number++ }) {Text(text = number.toString()).also { println("Text recomposition") }}.also { println("Button recomposition") }}Text RecomposeScope Button RecomposeScope
4UBCJMJUZ4ZTUFNsetContent {var number by remember { mutableStateOf(1) }TextWrapper(modifier = Modifier.clickable { number++ },text = number.toString())}@Composablefun TextWrapper(modifier: Modifier = Modifier,text: String) {Text(modifier = modifier, text = text)}
4UBCJMJUZ4ZTUFNsetContent {var number by remember { mutableStateOf(1) }TextWithLambda(modifier = Modifier.clickable { number++ },text = { number.toString() })}@Composablefun TextWithLambda(modifier: Modifier = Modifier,text: () -> String // Function0) {Text(modifier = modifier, text = text())}
NPWBCMF$POUFOU0Gval content = remember<@Composable () -> Unit> {{repeat(2) {Box(modifier = Modifier.size(100.dp).background(color = Color.Green))}}}Column {Button(onClick = { isRow = !isRow }) {Text(text = "Switch")}if (isRow) {Row { content() }} else {Column { content() }}}
NPWBCMF$POUFOU0Gval content = remember {movableContentOf { // movableContentWithReceiverOfrepeat(2) {Box(modifier = Modifier.size(100.dp).background(color = Color.Green))}}}Column {Button(onClick = { isRow = !isRow }) {Text(text = "Switch")}if (isRow) {Row { content() }} else {Column { content() }}}
!3FBE0OMZ$PNQPTBCMFobject MaterialTheme {val colors: Colors@Composable@ReadOnlyComposableget() = LocalColors.currentval typography: Typography@Composable@ReadOnlyComposableget() = LocalTypography.current// …}@Composable@ReadOnlyComposablefun stringResource(@StringRes id: Int): String {val resources = resources()return resources.getString(id)}
!/PO3FTUBSUBCMF$PNQPTBCMF@Composable@NonRestartableComposablefun DisposableEffect(key1: Any?, effect: DisposableEffectScope.() -> DisposableEffectResult) {remember(key1) { DisposableEffectImpl(effect) }}@Composable@NonRestartableComposablefun Image(modifier: Modifier = Modifier, colorFilter: ColorFilter? = null,imageVector: ImageVector, contentDescription: String?, alpha: Float = DefaultAlpha,alignment: Alignment = Alignment.Center, contentScale: ContentScale = ContentScale.Fit) {Image(modifier = modifier, alignment = alignment,contentScale = contentScale, alpha = alpha, colorFilter = colorFilter,painter = rememberVectorPainter(imageVector), contentDescription = contentDescription)}
TUBUJD$PNQPTJUJPO-PDBM0Gval LocalContext = staticCompositionLocalOf {noLocalProvidedFor("LocalContext")}val LocalClipboardManager = staticCompositionLocalOf {noLocalProvidedFor("LocalClipboardManager")}val LocalDensity = staticCompositionLocalOf {noLocalProvidedFor("LocalDensity")}val LocalFocusManager = staticCompositionLocalOf {noLocalProvidedFor("LocalFocusManager")}
!/P-JWF-JUFSBMT@file:NoLiveLiterals@NoLiveLiterals
#BTFMJOFQSPGJMFT#BTFMJOFQSPGJMFTݠन٘ীೠਃೠ҃۽ܳࢎஹੌೞӝਤ೧ ࢸী"OESPJE۠ఋ "35ীࢲࢎਊೞח"1,ীನೣػېझ߂ݫࢲ٘ݾ۾ੑפIUUQTEFWFMPQFSBOESPJEDPNUPQJDQFSGPSNBODFCBTFMJOFQSPGJMFT
#BTFMJOFQSPGJMFT.BDSPCFODINBSLݽٕࢸ
#BTFMJOFQSPGJMFT.BDSPCFODINBSLݽٕࢸ٘ࢿ CBTFMJOFQSPGJMFTࢤࢿ@ExperimentalBaselineProfilesApi@RunWith(AndroidJUnit4::class)class BaselineProfileGenerator {@get:Ruleval baselineProfileRule = BaselineProfileRule()@Testfun startup() = baselineProfileRule.collectBaselineProfile(packageName = AppPackageName) {pressHome()startActivityAndWait()}}
#BTFMJOFQSPGJMFT.BDSPCFODINBSLݽٕࢸ٘ࢿ CBTFMJOFQSPGJMFTਊറஏ@RunWith(AndroidJUnit4::class)class BaselineProfileBenchmark {@get:Ruleval benchmarkRule = MacrobenchmarkRule()// …private fun startup(compilationMode: CompilationMode) {benchmarkRule.measureRepeated(packageName = AppPackageName,metrics = listOf(StartupTimingMetric()),iterations = 10,startupMode = StartupMode.COLD,compilationMode = compilationMode) {pressHome()startActivityAndWait()}}}
#BTFMJOFQSPGJMFT.BDSPCFODINBSLݽٕࢸ٘ࢿ CBTFMJOFQSPGJMFTਊറஏ@RunWith(AndroidJUnit4::class)class BaselineProfileBenchmark {@get:Ruleval benchmarkRule = MacrobenchmarkRule()@Testfun startupNoCompilation() {startup(compilationMode = CompilationMode.None()) // JIT ஹੌ}@Testfun startupBaselineProfile() {startup(compilationMode = CompilationMode.Partial(baselineProfileMode = BaselineProfileMode.Require)) // AOT ஹੌ}// …}
#BTFMJOFQSPGJMFT.BDSPCFODINBSLݽٕࢸ٘ࢿ#VJME7BSJBOUTࢸ
#BTFMJOFQSPGJMFTܖӂೠഝࢿച
#BTFMJOFQSPGJMFTadb root
#BTFMJOFQSPGJMFTܖӂೠഝࢿച3VO
#BTFMJOFQSPGJMFTܖӂೠഝࢿച3VOadb pull
#BTFMJOFQSPGJMFTܖӂೠഝࢿച3VOadb pullCBTFMJOFQSPGUYUਵ۽ੌݺ߸҃റTSDNBJOਵ۽ز
#BTFMJOFQSPGJMFTܖӂೠഝࢿച3VOadb pullCBTFMJOFQSPGUYUਵ۽ੌݺ߸҃റTSDNBJOਵ۽زਊറ࠺Ү
#BTFMJOFQSPGJMFTܖӂೠഝࢿച3VOadb pullCBTFMJOFQSPGUYUਵ۽ੌݺ߸҃റTSDNBJOਵ۽زਊറ࠺Үਊೡݽٕীઓࢿ୶оdependencies {implementation("androidx.profileinstaller:profileinstaller:1.2.0-beta01")}
6. Wrap-up↟ة݀ߡҙܻ҅द
6. Wrap-up↟नӏ"1*DPMMFDU"T4UBUF8JUI-JGFDZDMF
хࢎפஹನૉ ղࠗ ٜ٘ cs.android.com ীࢲ оઉ৳णפ. ۨઃప࣌ীח షझীࢲ ઁҕೠ షझಕझо ਊغয णפ.QnA🙋