Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[All] Ripple effect is not working or badly working #627

Closed
4 of 5 tasks
vincentcastagna opened this issue Sep 15, 2021 · 4 comments · Fixed by #632
Closed
4 of 5 tasks

[All] Ripple effect is not working or badly working #627

vincentcastagna opened this issue Sep 15, 2021 · 4 comments · Fixed by #632
Assignees
Labels
kind/bug Something isn't working

Comments

@vincentcastagna
Copy link
Contributor

Current behavior

  • Clicking on any control that is supposed to have Ripple, such as Button, Card , have some visual issues with ripple.
    The ripple doesn't seem like a Ripple but more like a selected state. This is more likely due to speed/size on the ripple.

Expected behavior

  • Ripple should be clearly visible and same as what's provided natively by platform (such as button command bar)

How to reproduce it (as minimally and precisely as possible)

  • Run the Uno.Themes sample, notice ripple is not working well (almost not visible ?)
  • Run the Uno.Gallery samples (QA/DEV)

Environment

Latest version

Nuget Package:

Package Version(s):

Affected platform(s):

  • iOS
  • Android
  • WebAssembly
  • UWP
  • MacOS

Anything else we need to know?

@vincentcastagna vincentcastagna added the kind/bug Something isn't working label Sep 15, 2021
@MaximeDion-Work
Copy link
Contributor

Any news on this issue?

@Xiaoy312
Copy link
Contributor

notes
timelines:
    00 0    0   1 // every column = .075ms = ~1/13.3s
    .. .    .   .
    00 2    6   0
    07 2    0   0
    05 5    0   0
    <|      >>>>|  [uno] Opacity: 
                        [0, .075] (EaseIn) 0 -> 1
                        [.6, 1] (undefined=Linear?) 1 -> 0
    <|------>>>>|  [uwp] Opacity:
                        <EasingDoubleKeyFrame KeyTime="0" Value="0">        EasingMode="EaseIn"
                        <EasingDoubleKeyFrame KeyTime="0:0:0.075" Value="1">EasingMode="EaseIn"
                        <EasingDoubleKeyFrame KeyTime="0:0:0.6" Value="1">  EasingMode="EaseIn"
                        <EasingDoubleKeyFrame KeyTime="0:0:1" Value="0">    EasingMode="EaseIn"
    <<<|           [any] ScaleXY: [0, .225] (EaseInOut) 0 -> Multiplier

ease func:
    > https://docs.microsoft.com/en-us/dotnet/api/system.windows.media.animation.cubicease?view=net-5.0
    > graph: https://docs.microsoft.com/en-us/dotnet/media/cubicease-graph.png?view=net-5.0
    > f(t) = Math.Pow(t, 3);
    ease-in: most happen in 2nd half
    ease-out: most happen in 1st half
    ease-in-out: most happen in the middle 1/3

RippleSizeMultiplier: DP default value = 8
RippleSize: max of control height/width (updates on SizeChanged)

template:
    <Canvas>
        <Ellipse Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=RippleSize}"
                Height="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=RippleSize}"
                Canvas.Left="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=RippleX}"
                Canvas.Top="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=RippleY}"
                RenderTransformOrigin=".5,.5">
            <Ellipse.RenderTransform>
                <ScaleTransform x:Name="ScaleTransform" ScaleX="0" ScaleY="0" />
    ^ we are placing the ellipse at offset (-RippleSize/2,-RippleSize/2), so its center aligns to the click
        by default the size of the ellipse would be just enough to cover the entire control (on the longest? edge)
    ^ HOWEVER, the multiplier is 8x:
        <DoubleAnimation Storyboard.TargetName="ScaleTransform" Storyboard.TargetProperty="ScaleX"
            From="0" To="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=RippleSizeMultiplier}"
            Duration="0:0:0.225">
            <DoubleAnimation.EasingFunction>
                <CubicEase EasingMode="EaseInOut" />
    ^ meaning that the ellipse will expand extremely quickly
        and, taking no time to fill the control area in: 0.225 / 8 = 28ms, or 9.375ms if considering the ease

animation duration references:
    https://material.angular.io/components/ripple/examples
        const Q = {
            enterDuration: 225,
            exitDuration: 150
    https://github.com/material-components/material-components-web/blob/master/packages/mdc-ripple/constants.ts#L44-L46
        export const numbers = {
            DEACTIVATION_TIMEOUT_MS: 225, // Corresponds to $mdc-ripple-translate-duration (i.e. activation animation duration)
            FG_DEACTIVATION_MS: 150, // Corresponds to $mdc-ripple-fade-out-duration (i.e. deactivation animation duration)
    
    ^ by looking at angular link's source, it is easy to see the full duration should be 225+150ms

    https://github.com/flutter/flutter/blob/a31bed7890e502278723074c8f82d402f9f8041f/packages/flutter/lib/src/material/ink_ripple.dart#L12-L16
        ^ @Steve based the timing on flutter which does have this 0.075 delay on opacity, within the first 225ms

fill-behavior:
    > A value that specifies how the timeline behaves after it reaches the end of its active period but its parent is inside its active or fill period. The default value is HoldEnd.
    > Set an animations FillBehavior property to HoldEnd when you want the animation to hold its value after it reaches the end of its active period. An animation that has reached the end of its active period that has a FillBehavior setting of HoldEnd is said to be in its fill period. **When you don't want an animation to hold its value after it reaches the end of its active period, set its FillBehavior property to Stop.**
    > -- https://docs.microsoft.com/en-us/dotnet/api/system.windows.media.animation.timeline.fillbehavior?view=net-5.0
    ^ the original code uses FillBehavior="Stop" for both ScaleTransform.Scale(X|Y)
        meaning that it reverts back as soon as we hit the 0.225s mark,
        when it is supposed to hold until the end of storyboard at 1s mark

android: !!! there is some massive lag on this platform on both emulator or real one
    ^ the visual tree is rather simple with about 500 elements in it on OverviewPage
    ^ it helps that we dont have VS attached
    ^ there is massive improvement when material (except for Button) and cupertino OverviewSampleViews are removed
        ^ the first click animation is still delayed but works nonetheless
    ^ when Navigated to ButtonSamplePage, the lag is back with VS attached
    ^ no idea if any of these is relevant?:
        === on navigate
        [Mono] GC_MINOR: (Nursery full) time 170.18ms, stw 177.30ms promoted 2226K major size: 29904K in use: 27599K los size: 2048K in use: 909K
        [Choreographer] Skipped 433 frames!  The application may be doing too much work on its main thread.
        [View] requestLayout() improperly called by Windows.UI.Xaml.Controls.Canvas during layout: running second layout pass
        [View] requestLayout() improperly called by Windows.UI.Xaml.Controls.Grid during layout: running second layout pass
        [View] requestLayout() improperly called by Windows.UI.Xaml.Shapes.Ellipse during layout: running second layout pass
        /* repeat last 3 lines per Ripple used */
        [OpenGLRenderer] Davey! duration=1859ms; Flags=0, IntendedVsync=155424938419441, Vsync=155426238419389, OldestInputEvent=9223372036854775807, NewestInputEvent=0, HandleInputStart=155426252590200, AnimationStart=155426252620000, PerformTraversalsStart=155426255267200, DrawStart=155426759670700, SyncQueued=155426777589600, SyncStart=155426778164900, IssueDrawCommandsStart=155426794059800, SwapBuffers=155426797801800, FrameCompleted=155426798904300, DequeueBufferDuration=320600, QueueBufferDuration=558100, GpuCompleted=155217673094300, 

        === on click (after a certain delay)
        [atform.materia] Explicit concurrent copying GC freed 10981(535KB) AllocSpace objects, 0(0B) LOS objects, 49% free, 5052KB/10104KB, paused 342us total 12.976ms
        [Mono] GC_TAR_BRIDGE bridges 2914 objects 401552 opaque 276998 colors 2914 colors-bridged 2914 colors-visible 2914 xref 0 cache-hit 0 cache-semihit 0 cache-miss 0 setup 0.21ms tarjan 221.42ms scc-setup 1.10ms gather-xref 0.16ms xref-setup 0.02ms cleanup 21.46ms
        [Mono] GC_BRIDGE: Complete, was running for 60.27ms
        [Mono] GC_MINOR: (Nursery full) time 271.15ms, stw 272.63ms promoted 1722K major size: 49536K in use: 46866K los size: 2048K in use: 1205K
        [OpenGLRenderer] Davey! duration=850ms; Flags=0, IntendedVsync=155489588340051, Vsync=155490021673367, OldestInputEvent=9223372036854775807, NewestInputEvent=0, HandleInputStart=155490030606500, AnimationStart=155490030626300, PerformTraversalsStart=155490031381200, DrawStart=155490386701700, SyncQueued=155490434410200, SyncStart=155490434738400, IssueDrawCommandsStart=155490436189600, SwapBuffers=155490438355300, FrameCompleted=155490439141900, DequeueBufferDuration=159400, QueueBufferDuration=285600, GpuCompleted=155454272485400, 
        [OpenGLRenderer] Davey! duration=862ms; Flags=0, IntendedVsync=155490038352347, Vsync=155490488352329, OldestInputEvent=9223372036854775807, NewestInputEvent=0, HandleInputStart=155490493270200, AnimationStart=155490493288700, PerformTraversalsStart=155490493915800, DrawStart=155490849196200, SyncQueued=155490896691700, SyncStart=155490897103500, IssueDrawCommandsStart=155490898551500, SwapBuffers=155490900625600, FrameCompleted=155490901366800, DequeueBufferDuration=87900, QueueBufferDuration=422000, GpuCompleted=155454289115500, 
    ^ there is also something weird with the buttons ButtonSamplePage:
        the first click (or the first click after changing mouse position)
            ^ note: on physical device, you need to click very carefully on the same spot or use `adb shell input tap`
        the animation pretty much just skip to the end, so you just see the expanded ripple
        without the expanding part...

droid animation/pointer/lag:
    it is worth noting that there is no issue with OnPressedPointer, it is hit consistently
    the visual-states are also applied nicely, which is confirmed with a textblock + setter

tl;dr:

  • RippleSizeMultiplier is 8, since the animation duration is fixed and we can only see the visible area, it also is a multiplier for how fast the ripple is travelling if we only consider the visible area, not what's outside.
  • The ScaleXY animation is using an EaseOut function, so the the bulk of it happens in the 1nd half of the duration while we are still animating the opacity.
  • The FillBehavior for ScaleXY is Stop, so the ellipse will immediately scale back to 0 after the expansion completes (at 225ms), instead of sticking for the full duration (225+150ms).

@dr1rrb
Copy link
Member

dr1rrb commented Sep 29, 2021

@Xiaoy312 For the perf of the ripple on Android, I would try to comment that line https://github.com/unoplatform/uno/blob/master/src/Uno.UI/UI/Xaml/Shapes/Shape.Android.cs#L88

GitHub
Build Mobile, Desktop and WebAssembly apps with C# and XAML. Today. Open source and professionally supported. - uno/Shape.Android.cs at master · unoplatform/uno

@Xiaoy312
Copy link
Contributor

Xiaoy312 commented Oct 1, 2021

It appears to have no effect, between having that line commented out or not.
What I did noticed however is that by upgrading Uno.UI from 3.10.0-dev.156 to 3.11.0-dev.248 greatly improved the performance. With the exception of sometimes first click still not showing the rippling effect (the expansion was skipped). The rest worked nice and smoothly.

edit: It seem to have fixed itself. Might be some issues with my environment&/emulator at the time..?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants