Lucien Guimaraes

    Lucien Guimaraes

    1 year ago
    I'm asking for help on this one again. I'm unable to create a smooth alpha transition like this video, using NestedScrollConnection or simply with animateColorAsState. For both the value isn't updated as often as the scroll is happening in the view
    t

    Thiago

    1 year ago
    Check the compose samples. There have samples using TopBar, Header image and swipe actions
    Lucien Guimaraes

    Lucien Guimaraes

    1 year ago
    I already did, but sadly they don't have such a fade animation on topAppBar
    Doris Liu

    Doris Liu

    1 year ago
    Can you post a code snippet on how you are updating the alpha now?
    Lucien Guimaraes

    Lucien Guimaraes

    1 year ago
    only the part with the animation update ? Or would you like the complete integration ?
    Here is a shorten snippet using only rememberScrollState and animateColorAsState
    BoxWithConstraints {
    
                val scrollState = rememberScrollState()
                val maxHeight = remember {
                    mutableStateOf(this@BoxWithConstraints.maxHeight.value / 3)  //We consider the image header is a third of the screen
                }
                val tobAppBarBackgroundColor = animateColorAsState(
                    when (scrollState.value) {
                        0f -> {
                            Color.White.copy(alpha = 0f)
                        }
                        in 0f..maxHeight.value -> {
                            val alpha = scrollState.value/maxHeight.value
                            Color.White.copy(alpha = alpha)
                        }
                        else -> {
                            Color.White.copy(alpha = 1f)
                        }
                    }
                )
    
                Column(modifier = Modifier
                    .fillMaxSize()
                    .verticalScroll(scrollState)) {
                    //content
                }
                TopAppBar(
                    backgroundColor = tobAppBarBackgroundColor.value,
                )
            }
    I added some logs, and When I'm scrolling the scrollState.value is called only a few times
    Doris Liu

    Doris Liu

    1 year ago
    I was just looking at the code snippet that you posted in an earlier thread. 🙂 I'm curious what are the values throughout scrolling that you see from
    when (scrollState.value) {
                        0f -> {
                            Color.White.copy(alpha = 0f)
                        }
                        in 0f..maxHeight.value -> {
                            val alpha = scrollState.value/maxHeight.value
                            Color.White.copy(alpha = alpha)
                        }
                        else -> {
                            Color.White.copy(alpha = 1f)
                        }
                    }
    Can you add a log after this block and do a quick scroll?
    Lucien Guimaraes

    Lucien Guimaraes

    1 year ago
    Here is a look on logcat when I'm scrolling until the end of the screen.
    D/debug: scrollState is 0.0
    D/debug: scrollState is 0.0
    D/debug: scrollState is 16.316895
    D/debug: scrollState is 76.4624
    D/debug: scrollState is 480.82385
    D/debug: scrollState is 674.97656
    D/debug: scrollState is 674.97656
    D/debug: scrollState is 674.97656
    D/debug: scrollState is 702.93726
    D/debug: scrollState is 758.1581
    D/debug: scrollState is 866.1438
    D/debug: scrollState is 978.0
    that's why I'm unable to have a correct computation on the color, the scrollState values should be updated more often. But I don't know if t's intended by the API or if I'm doing something wrong
    Colton Idle

    Colton Idle

    1 year ago
    Looking forward to seeing if you can resolve this. We have a very similar requirement because iOS team can do it easily apparently.
    Doris Liu

    Doris Liu

    1 year ago
    Seems like there's a jump in the scrolling value from 76 to 480. I was trying to figure out whether the animation is too fast, or the scrolling value change happens irregularly. Out of curiosity, what if you remove
    animateColorAsState
    and just use the interpolated alpha directly. what do you see there? Could you also include the timestamp for the scrollState.value logging so we can see whether there's any frame skipping?
    Lucien Guimaraes

    Lucien Guimaraes

    1 year ago
    Out of curiosity, what if you remove 
    animateColorAsState
     and just use the interpolated alpha directly. what do you see there?
    Wow just tried this and it's already much better
    I have way more scrolling value change
    Doris Liu

    Doris Liu

    1 year ago
    🙂 Can you share the logging with the more frequent scrolling value change? Does it happen every frame?
    Lucien Guimaraes

    Lucien Guimaraes

    1 year ago
    Does it happen every frame ?
    Yes, it seems so. Here is the logging without
    animateColorAsState
    2021-02-25 19:49:19.449 D/debug: scrollState is 0.0
    2021-02-25 19:49:19.715 D/debug: scrollState is 0.0
    2021-02-25 19:49:22.178 D/debug: scrollState is 8.751709
    2021-02-25 19:49:22.225 D/debug: scrollState is 36.629395
    2021-02-25 19:49:22.278 D/debug: scrollState is 66.92615
    2021-02-25 19:49:22.291 D/debug: scrollState is 68.18396
    2021-02-25 19:49:22.302 D/debug: scrollState is 76.79932
    2021-02-25 19:49:22.343 D/debug: scrollState is 93.759766
    2021-02-25 19:49:22.402 D/debug: scrollState is 126.45117
    2021-02-25 19:49:22.422 D/debug: scrollState is 134.1903
    2021-02-25 19:49:22.439 D/debug: scrollState is 140.88184
    2021-02-25 19:49:22.492 D/debug: scrollState is 157.72766
    2021-02-25 19:49:22.538 D/debug: scrollState is 168.83215
    2021-02-25 19:49:22.553 D/debug: scrollState is 177.0935
    2021-02-25 19:49:22.613 D/debug: scrollState is 209.2351
    2021-02-25 19:49:22.632 D/debug: scrollState is 215.45056
    2021-02-25 19:49:22.651 D/debug: scrollState is 227.0415
    2021-02-25 19:49:22.750 D/debug: scrollState is 271.698
    2021-02-25 19:49:22.768 D/debug: scrollState is 274.1543
    2021-02-25 19:49:22.814 D/debug: scrollState is 297.47107
    2021-02-25 19:49:22.865 D/debug: scrollState is 319.48877
    2021-02-25 19:49:22.924 D/debug: scrollState is 339.22827
    2021-02-25 19:49:22.939 D/debug: scrollState is 348.00037
    2021-02-25 19:49:23.001 D/debug: scrollState is 372.81177
    2021-02-25 19:49:23.047 D/debug: scrollState is 384.83008
    2021-02-25 19:49:23.092 D/debug: scrollState is 400.29297
    2021-02-25 19:49:23.171 D/debug: scrollState is 419.08154
    2021-02-25 19:49:23.224 D/debug: scrollState is 429.19495
    2021-02-25 19:49:23.284 D/debug: scrollState is 447.0946
    2021-02-25 19:49:23.336 D/debug: scrollState is 465.09326
    2021-02-25 19:49:23.379 D/debug: scrollState is 476.05554
    2021-02-25 19:49:23.391 D/debug: scrollState is 481.49835
    2021-02-25 19:49:23.455 D/debug: scrollState is 489.9375
    2021-02-25 19:49:23.511 D/debug: scrollState is 494.52356
    2021-02-25 19:49:23.557 D/debug: scrollState is 508.80078
    2021-02-25 19:49:23.567 D/debug: scrollState is 513.7958
    2021-02-25 19:49:23.612 D/debug: scrollState is 524.1341
    2021-02-25 19:49:23.637 D/debug: scrollState is 534.9395
    2021-02-25 19:49:23.697 D/debug: scrollState is 553.46844
    2021-02-25 19:49:23.754 D/debug: scrollState is 579.5058
    2021-02-25 19:49:23.782 D/debug: scrollState is 590.0153
    2021-02-25 19:49:23.795 D/debug: scrollState is 596.7677
    2021-02-25 19:49:23.818 D/debug: scrollState is 605.4359
    2021-02-25 19:49:23.836 D/debug: scrollState is 613.4224
    2021-02-25 19:49:23.891 D/debug: scrollState is 630.97266
    2021-02-25 19:49:23.955 D/debug: scrollState is 659.7693
    2021-02-25 19:49:23.974 D/debug: scrollState is 666.88965
    2021-02-25 19:49:23.988 D/debug: scrollState is 672.5115
    2021-02-25 19:49:24.003 D/debug: scrollState is 679.4973
    2021-02-25 19:49:24.073 D/debug: scrollState is 705.7602
    2021-02-25 19:49:24.128 D/debug: scrollState is 726.7422
    2021-02-25 19:49:24.214 D/debug: scrollState is 755.17145
    2021-02-25 19:49:24.278 D/debug: scrollState is 775.1311
    2021-02-25 19:49:24.347 D/debug: scrollState is 802.93066
    2021-02-25 19:49:24.400 D/debug: scrollState is 818.94055
    2021-02-25 19:49:24.460 D/debug: scrollState is 829.8714
    2021-02-25 19:49:24.521 D/debug: scrollState is 845.0254
    2021-02-25 19:49:24.541 D/debug: scrollState is 852.99146
    2021-02-25 19:49:24.594 D/debug: scrollState is 870.84784
    2021-02-25 19:49:24.641 D/debug: scrollState is 892.7049
    2021-02-25 19:49:24.686 D/debug: scrollState is 917.4961
    2021-02-25 19:49:24.774 D/debug: scrollState is 959.5512
    2021-02-25 19:49:24.831 D/debug: scrollState is 978.0
    Doris Liu

    Doris Liu

    1 year ago
    There's still some irregularities even in the last logging, sometimes subsequent value changes are 50-100ms apart, which indicates a low frame rate.
    This is alpha 12 or beta01?
    Lucien Guimaraes

    Lucien Guimaraes

    1 year ago
    This is alpha12
    I haven't migrated to beta01 yet, is there any performance improvement in the beta01 release ?
    Doris Liu

    Doris Liu

    1 year ago
    It'd be helpful if you could try this on beta01 and file a bug if you still see the same issue. We have made some changes in pointer input and Scrollable since alpha12. @matvei would be able to tell you more about that. BTW, is this on an emulator or an actual device?
    Lucien Guimaraes

    Lucien Guimaraes

    1 year ago
    Ok, I'm going to do the migration and check if there is any performance improvement 👍 And it's from an emulator. But the issue was also on my Pixel 3 (when using
    animateColorAsState
    , I haven't try without it on my device yet)
    Doris Liu

    Doris Liu

    1 year ago
    I don't expect
    animateColorAsState
    to have an impact on frame rate since it's fairly lightweight, if it does on beta01 please file a bug. I'd be curious to see what's going on. 🙂
    t

    Thiago

    1 year ago
    Doris, just a doubt, migrating this Lucien sample to use animation with
    withNanoFrames
    you think that should solve frame drops? As the
    TargetBasedAnimation
    sample on official docs: https://developer.android.com/jetpack/compose/animation#targetbasedanimation
    Lucien Guimaraes

    Lucien Guimaraes

    1 year ago
    migration done on beta01, I still have some value changes that are 50-100ms apart while using the interpolated alpha directly. And using
    animateColorAsState
    it's the same issue as it was in alpha12. Both were tested on emulator
    Doris Liu

    Doris Liu

    1 year ago
    Doris, just a doubt, migrating this Lucien sample to use animation with 
    withNanoFrames
     you think that should solve frame drops?
    I doubt that would fix the frame drop. If you scroll up to the diagram here: https://developer.android.com/jetpack/compose/animation#low-level-apis , you'll see that
    animate*AsState
    uses
    TargetBasedAnimation
    under the hood. 🙂
    migration done on beta01, I still have some value changes that are 50-100ms apart while using the interpolated alpha directly. And using 
    animateColorAsState
     it's the same issue as it was in alpha12. Both were tested on emulator
    Please file a bug and include the snippet. We'll investigate. Thank you
    Lucien Guimaraes

    Lucien Guimaraes

    1 year ago
    I will, thanks for helping!
    Timo Drick

    Timo Drick

    1 year ago
    As a workaround until the bug is fixed for me animateColorAsState(value, animationSpec = tween(1000)) makes it smooth. Of course it is not exactly what you want.
    Doris Liu

    Doris Liu

    1 year ago
    if you had to work around the imperfect input target values to the animation, I'd recommend a low stiffness
    spring
    over a
    tween
    , at least
    spring
    keeps the velocity continuous. 🙂
    Timo Drick

    Timo Drick

    1 year ago
    Using lazyColumnListState.firstVisibleItemScrollOffset works for me fine (smooth animation) not sure but maybe LazyColumn works better?https://github.com/timo-drick/compose_dev_challenge_1/blob/main/app/src/main/java/com/example/androiddevchallenge/PuppyDetail.kt
    Doris Liu

    Doris Liu

    1 year ago
    Very nice animation! 👆😒miling_face_with_3_hearts: Thanks for the follow-up, @Timo Drick . Do you also use the
    firstVisibleItemScrollOffset
    in combination w/
    animate*AsState
    ?
    Nvm. The code linked above answered that question for me. 🙂
    Timo Drick

    Timo Drick

    1 year ago
    So it is not an animation. I just use the scrollOffset to calculate the bottom padding of the image.
    Lucien Guimaraes

    Lucien Guimaraes

    1 year ago
    I didn't follow up last days, but I was able to have something smooth (using the interpolated alpha directly)
    Colton Idle

    Colton Idle

    1 year ago
    Nice! Please share a gist if possible. Very curious about the end result.
    Lucien Guimaraes

    Lucien Guimaraes

    1 year ago
    Here is the computation for the color update:
    @Composable
    fun topAppBarBackgroundColor(
        scrollState: ScrollState,
        pictureHeight: Dp,
    ): Color {
        val topBarAnimationLimit = (scrollState.maxValue / HikeDetailScreen.HEADER_PART_SCREEN) + pictureHeight.value
        return when (scrollState.value) {
            0 -> {
                MaterialTheme.colors.surface.copy(alpha = 0f)
            }
            in 0..topBarAnimationLimit.roundToInt() -> {
                var alpha = scrollState.value / topBarAnimationLimit
                if (alpha > 1) //to be sure we never have an alpha float exceeding 1f
                    alpha = 1f
                MaterialTheme.colors.surface.copy(alpha = alpha)
            }
            else -> {
                MaterialTheme.colors.surface.copy(alpha = 1f)
            }
        }
    }
    the
    HEADER_PART_SCREEN
    is just an Int ratio of the screen. In this case I want my picture to take a third of the bloc visible, so it's 3. But it could be whatever you want. And for the statusBar I just created a Box that take a modifier with the statusBarHeight (using Inset library) and with a background being the same as the topBar
    t

    Thiago

    1 year ago
    First: congrats for the animation. Very cool. I have one question: why your
    topAppBarBackgroundColor
    is annotaded with @Composable if that contains logic only? I think your code can be improved to:
    @Composable
    fun topAppBarBackgroundColor(
        scrollState: ScrollState,
        pictureHeight: Dp,
    ): Color {
        val topBarAnimationLimit = (scrollState.maxValue / HikeDetailScreen.HEADER_PART_SCREEN) + pictureHeight.value
        val alpha = (scrollState.value / topBarAnimationLimit).coercIn(0f, 1f)
        return MaterialTheme.colors.surface.copy(alpha = alpha)
    }
    Lucien Guimaraes

    Lucien Guimaraes

    1 year ago
    I have one question: why your 
    topAppBarBackgroundColor
     is annotaded with @Composable if that contains logic only
    MaterialTheme.colors.surface
    has to be called from a Composable so that's why! And yeah it can totally be improved to be cleaner 👍 from your example you can even just return the alpha, and you apply the
    MaterialTheme.colors.surface
    where the function is called. Which remove the Compose annotation from
    topAppBarBackgroundColor