简体   繁体   中英

Android Jetpack Compose complex animate performance issue

i just started the compose animation and now I'm confused I Have a login screen and ı want to with animation but ı noticed to performance issues on my code. When ı click the box on first time coming lagyly and ı dont wanna that what can do for this is there any other solution or it just like that? How can I solve this?

enum class ViewState { WELCOME, SIGNING, SIGNUP }

@ExperimentalAnimationApi
@Composable
fun OnBoardView(deviceHeight: Dp, deviceWidth: Dp,activity: Activity) {

    val baseState = remember { mutableStateOf(ViewState.WELCOME) }
    val signUpTransition = updateTransition(targetState = baseState, "1")
    val signInTransition = updateTransition(targetState = baseState, label = "2")
    val focusManager = LocalFocusManager.current
    val visible by remember { baseState }
    val density = LocalDensity.current
    val isRunning = !signUpTransition.isRunning || !signInTransition.isRunning

    //SIGN UP
    val signUpSize = sizeAnimate(
        targetState = ViewState.SIGNUP,
        deviceWidth = deviceWidth,
        label = "3",
        transition = signUpTransition,
    )
    val signUpOffset = offsetAnimate(
        targetState = ViewState.SIGNUP,
        label = "4",
        transition = signUpTransition,
        deviceWidth = deviceWidth
    )
    //SIGN IN
    val signInSize = sizeAnimate(
        targetState = ViewState.SIGNING,
        deviceWidth = deviceWidth,
        label = "5",
        transition = signInTransition,
    )
    val signInOffset = offsetAnimate(
        targetState = ViewState.SIGNING,
        label = "6",
        transition = signInTransition,
        deviceWidth = deviceWidth
    )

    @Composable
    fun TextView(label: String, targetState: ViewState, icon: ImageVector, color: Color) {
        AnimatedVisibility(
            visible = visible == targetState,
            enter = slideInHorizontally(
                animationSpec = tween(900),
                initialOffsetX = {
                    with(density) {
                        when (targetState) {
                            ViewState.SIGNUP -> -deviceWidth.roundToPx()
                            ViewState.SIGNING -> deviceWidth.roundToPx()
                            else -> {
                                0
                            }
                        }
                    }
                }
            ),
            exit = slideOutHorizontally(
                animationSpec = tween(900),
                targetOffsetX = {
                    with(density) {
                        when (targetState) {
                            ViewState.SIGNUP -> -deviceWidth.roundToPx()
                            ViewState.SIGNING -> deviceWidth.roundToPx()
                            else -> {
                                0
                            }

                        }
                    }
                }
            )
        ) {
            Column(
                modifier = Modifier
                    .fillMaxHeight(0.5F)
                    .fillMaxWidth(),
                verticalArrangement = Arrangement.SpaceBetween,
                horizontalAlignment = Alignment.CenterHorizontally
            ) {
                IconButton(
                    enabled = isRunning && !this@AnimatedVisibility.transition.isRunning,
                    onClick = {
                        baseState.value = ViewState.WELCOME
                    },
                    modifier = Modifier
                        .size(50.dp)
                        .clip(shape = CircleShape)
                        .background(color)
                ) {
                    Icon(
                        icon,
                        contentDescription = null,
                        tint = Color.White
                    )
                }
                Text(text = label, fontSize = 25.sp)
            }

        }
    }

    @Composable
    fun MainBoxView(
        offset: Offset,
        deviceWidth: Dp,
        backgroundColor: Color,
        selectedState: ViewState,
        content: @Composable () -> Unit
    ) {
        Box(
            modifier = Modifier
                .size(
                    width = deviceWidth,
                    height = if (selectedState == ViewState.SIGNUP) deviceHeight / 1.5F else deviceHeight / 2.3F
                )
                .offset(offset.x.dp, offset.y.dp)
                .clip(shapes.medium)
                .background(backgroundColor)
                .noRippleClickable(isEnabled = isRunning) {
                    baseState.value = selectedState
                    focusManager.clearFocus()
                },
            contentAlignment = Alignment.TopCenter
        ) {
            Column(
                modifier = Modifier.fillMaxSize(),
                horizontalAlignment = Alignment.CenterHorizontally,
            ) {
                content()
            }
        }
    }


    @Composable
    fun BoxColumnView(
        targetState: ViewState,
        content: @Composable () -> Unit,
    ) {
        AnimatedVisibility(
            visible = visible == targetState,
            enter = slideInHorizontally(
                animationSpec = tween(800),
                initialOffsetX = { with(density) { if (targetState == ViewState.SIGNUP) (-deviceWidth / 2).roundToPx() else (deviceWidth / 2).roundToPx() } }
            ),
            exit = slideOutHorizontally(
                animationSpec = tween(800),
                targetOffsetX = { with(density) { if (targetState == ViewState.SIGNUP) (-deviceWidth / 2).roundToPx() else (deviceWidth / 2).roundToPx() } }
            )
        ) {
            content()
        }
    }

    @Composable
    fun BoxPreTextView(label: String, targetState: ViewState) {
        AnimatedVisibility(
            visible = visible == ViewState.WELCOME,
            enter = when (visible) {
                ViewState.SIGNUP -> {
                    slideInHorizontally(
                        animationSpec = tween(800),
                        initialOffsetX = { with(density) { deviceWidth.roundToPx() } }
                    )
                }
                ViewState.WELCOME -> {
                    slideInHorizontally(
                        animationSpec = tween(800),
                        initialOffsetX = { with(density) { if (targetState == ViewState.SIGNUP) deviceWidth.roundToPx() else -deviceWidth.roundToPx() } }
                    )
                }
                else -> {
                    slideInHorizontally(
                        animationSpec = tween(800),
                        initialOffsetX = { with(density) { deviceWidth.roundToPx() } }
                    )
                }
            },
            exit = when (visible) {
                ViewState.SIGNUP -> {
                    slideOutHorizontally(
                        animationSpec = tween(800),
                        targetOffsetX = { with(density) { deviceWidth.roundToPx() } }
                    )
                }
                ViewState.WELCOME -> {
                    slideOutHorizontally(
                        animationSpec = tween(800),
                        targetOffsetX = { with(density) { if (targetState == ViewState.SIGNUP) -deviceWidth.roundToPx() else deviceWidth.roundToPx() } }
                    )
                }
                else -> {
                    slideOutHorizontally(
                        animationSpec = tween(800),
                        targetOffsetX = { with(density) { -deviceWidth.roundToPx() } }
                    )
                }
            }
        ) {
            Text(
                text = label,
                color = Color.White,
            )
        }
    }

    @Composable
    fun MainTextView(label: String, targetState: ViewState) {
        AnimatedVisibility(
            visible = visible == targetState || visible == ViewState.WELCOME,
            enter = slideInHorizontally(
                animationSpec = tween(800),
                initialOffsetX = {
                    with(density) {
                        if (targetState == ViewState.SIGNUP) {
                            (-deviceWidth / 3).roundToPx()
                        } else {
                            (deviceWidth / 3).roundToPx()
                        }
                    }
                }
            ),
            exit = slideOutHorizontally(
                animationSpec = tween(1200),
                targetOffsetX = {
                    with(density) {
                        if (targetState == ViewState.SIGNUP) {
                            (-deviceWidth / 3).roundToPx()
                        } else {
                            (deviceWidth / 3).roundToPx()
                        }
                    }
                })
        ) {
            Text(
                text = label,
                color = Color.White,
                fontSize = 24.sp,
            )
        }
    }

    Column(
        modifier = Modifier
            .fillMaxSize()
            .noRippleClickable {
                focusManager.clearFocus()
            },
    ) {
        Box(
            modifier = Modifier
                .weight(1.5F)
                .fillMaxSize(),
            contentAlignment = Alignment.Center
        ) {
            TextView(
                icon = Icons.Default.ArrowForward,
                label = "WELCOME!",
                targetState = ViewState.SIGNUP,
                color = DarkBlue
            )
            TextView(
                icon = Icons.Default.ArrowBack,
                label = "WELCOME BACK!",
                targetState = ViewState.SIGNING,
                color = LightBlue
            )
        }
        Row(
            modifier = Modifier
                .weight(3F)
                .fillMaxSize()
                .noRippleClickable {
                    focusManager.clearFocus()
                },
            //horizontalArrangement = Arrangement.SpaceBetween,
            verticalAlignment = Alignment.Top,
        ) {
            //SIGN UP
            MainBoxView(
                offset = signUpOffset,
                deviceWidth = signUpSize,
                backgroundColor = DarkBlue,
                selectedState = ViewState.SIGNUP
            ) {
                Box(
                    modifier = Modifier.weight(1F),
                    contentAlignment = Alignment.Center
                ) {
                    MainTextView(
                        label = "SIGN UP",
                        targetState = ViewState.SIGNUP,
                    )
                }
                Box(
                    modifier = Modifier.weight(6F),
                    contentAlignment = Alignment.TopCenter
                ) {
                    /*
                    BoxPreTextView(
                        label = "New here? come on, what are you waiting for, sign up and open up to new worlds",
                        targetState = ViewState.SIGNUP
                    )

                     */
                    BoxColumnView(
                        targetState = ViewState.SIGNUP,
                    ) {

                    }
                }
            }
            //SIGN IN
            MainBoxView(
                offset = signInOffset,
                deviceWidth = signInSize,
                backgroundColor = LightBlue,
                selectedState = ViewState.SIGNING
            ) {
                Box(
                    modifier = Modifier.weight(1F),
                    contentAlignment = Alignment.Center
                ) {
                    MainTextView(
                        label = "SIGN IN",
                        targetState = ViewState.SIGNING,
                    )
                }
                Box(
                    modifier = Modifier.weight(4F),
                    contentAlignment = Alignment.TopCenter
                ) {
                    /*
                    BoxPreTextView(
                        label = "Returning? Just Sign in to resume what you were doing",
                        targetState = ViewState.SIGNING
                    )
                     */
                    BoxColumnView(
                        targetState = ViewState.SIGNING,
                    ) {
                        LoginView(activity)
                    }
                }
            }
        }
        Box(
            modifier = Modifier
                .weight(1F)
                .fillMaxSize(),
            contentAlignment = Alignment.Center
        ) {
            Row(
                modifier = Modifier.fillMaxSize(0.5F),
                horizontalArrangement = Arrangement.SpaceAround,
                verticalAlignment = Alignment.CenterVertically,
            ) {
                IconButton(
                    onClick = { },
                    modifier = Modifier
                        .size(50.dp)
                        .clip(shape = CircleShape)
                        .background(Color.Blue)
                ) {
                    Icon(
                        painterResource(id = R.mipmap.facebook_foreground),
                        contentDescription = null,
                        tint = Color.White
                    )
                }
                IconButton(
                    onClick = { },
                    modifier = Modifier
                        .size(50.dp)
                        .clip(shape = CircleShape)
                        .background(GoogleRed)
                ) {
                    Icon(
                        painterResource(id = R.mipmap.google_foreground),
                        contentDescription = null,
                        tint = Color.White
                    )
                }
                IconButton(
                    onClick = { },
                    modifier = Modifier
                        .size(50.dp)
                        .clip(shape = CircleShape)
                        .background(LightBlue)
                ) {
                    Icon(
                        painterResource(id = R.mipmap.twitter_foreground),
                        contentDescription = null,
                        tint = Color.White
                    )
                }
            }
        }
    }
}


@Composable
fun offsetAnimate(
    transition: Transition<MutableState<ViewState>>,
    targetState: ViewState,
    label: String,
    deviceWidth: Dp
): Offset {
    val offset by transition.animateOffset(
        label = label,
        transitionSpec = {
            if (this.targetState.value == targetState) {
                tween(900, 100)
            } else {
                tween(450)
            }

        },
    ) { animated ->
        fun width(value: Double) = (deviceWidth.value * value).toFloat()
        if (targetState == ViewState.SIGNUP) {
            when (animated.value) {
                ViewState.SIGNUP -> {
                    Offset(width(0.07), 0f)
                }
                ViewState.SIGNING -> {
                    Offset(-width(0.1), 0f)
                }
                else -> {
                    Offset(-width(0.06), 0f)
                }
            }
        } else {
            when (animated.value) {
                ViewState.SIGNUP -> {
                    Offset(width(0.2), 0f)
                }
                ViewState.SIGNING -> {
                    Offset(width(0.00), 0f)
                }
                else -> {
                    Offset(width(0.04), 0f)
                }
            }

        }

    }
    return offset
}

@Composable
fun sizeAnimate(
    transition: Transition<MutableState<ViewState>>,
    targetState: ViewState,
    label: String,
    deviceWidth: Dp
): Dp {
    val sizeAnimate by transition.animateDp(
        label = label,
        transitionSpec = {
            if (this.targetState.value == targetState)
                tween(450) else tween(900)
        },
    ) {
        if (targetState == ViewState.SIGNUP) {
            when (it.value) {
                ViewState.WELCOME -> deviceWidth / 2F
                ViewState.SIGNING -> deviceWidth / 16F
                ViewState.SIGNUP -> deviceWidth / 1.15F
            }
        } else {
            when (it.value) {
                ViewState.WELCOME -> deviceWidth / 2F
                ViewState.SIGNUP -> deviceWidth / 16F
                ViewState.SIGNING -> deviceWidth / 1.15F
            }
        }

    }
    return sizeAnimate
}

I've had similar performance issue not so long ago and managed to fix it by switching the build variant from debug to release.

  • Firstly from the bottom left corner of your project click on 'Build Variants' and select 'release' as the 'Active Build Variant'.

  • Now you need to set a signing config for the release variant. Press Ctrl+Alt+Shift+S and this shortcut should open the Project Structure. Then from 'Modules' select 'app' and click on 'Default Config'. Find 'Signing Config' and select '$signingConfigs.debug'.

  • Click Apply and wait for Gradle to fetch the build models. Then click OK and wait for Gradle to sync the project.

Rebuild the project and performance issue should be gone.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM