How to implement button click ripple in wpf project

114 views Asked by At

I would like to implement a button click ripple animation effect in a wpf project by Style enter image description here

1

There are 1 answers

0
MIHOW On

You could achieve RippleEffect using Canvas in ButtonTemplate.

<Canvas x:Name="Canvas"
        Width="{Binding ActualWidth, ElementName=OuterCanvas, Mode=OneWay}"
        Height="{Binding ActualHeight, ElementName=OuterCanvas, Mode=OneWay}"
        Background="Transparent"
        MouseLeftButtonDown="Canvas_MouseLeftButtonDown">

with Ellipse, also in the ButtonTemplate

<Ellipse x:Name="RippleEllipse"
         Width="10"
         Height="10"
         HorizontalAlignment="Center"
         VerticalAlignment="Center"
         Fill="Gray"
         Opacity="1"
         Visibility="Hidden"
         RenderTransformOrigin="0.5,0.5">
    <Ellipse.RenderTransform>
        <ScaleTransform ScaleX="1" ScaleY="1"/>
    </Ellipse.RenderTransform>
</Ellipse>

with Storyboard to animate that Ellipse for the Ripple effect.

<Storyboard x:Key="RippleEffect" Completed="Storyboard_Completed">
    <!-- Visibility -->
    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Ellipse.Visibility)" Duration="0:0:0.5">
        <DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{x:Static Visibility.Visible}"/>
        <DiscreteObjectKeyFrame KeyTime="0:0:0.5" Value="{x:Static Visibility.Hidden}"/>
    </ObjectAnimationUsingKeyFrames>

    <!-- Scale animation -->
    <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(Ellipse.RenderTransform).(ScaleTransform.ScaleX)" Duration="0:0:0.5">
        <LinearDoubleKeyFrame KeyTime="100%" Value="10"/>
    </DoubleAnimationUsingKeyFrames>
    <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(Ellipse.RenderTransform).(ScaleTransform.ScaleY)" Duration="0:0:0.5">
        <LinearDoubleKeyFrame KeyTime="100%" Value="10"/>
    </DoubleAnimationUsingKeyFrames>

    <!-- Opacity animation -->
    <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(Ellipse.Opacity)" Duration="0:0:0.5">
        <LinearDoubleKeyFrame KeyTime="0:0:0" Value="1"/>
        <LinearDoubleKeyFrame KeyTime="0:0:0.5" Value="0"/>
    </DoubleAnimationUsingKeyFrames>
</Storyboard>

now, it's necessary to move the Ellipse to point where the click was, and to start the Storyboard.

private Storyboard _storyboard;
private Point _mousePosition;
private Ellipse _ellipse;

public RippleButton()
{
    InitializeComponent();

    // Get storyboard from RippleButton
    _storyboard = (Storyboard)this.Resources["RippleEffect"];
}

private async void Canvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    Canvas _canvas = (Canvas)sender as Canvas;
    if (_canvas != null)
    {
        _mousePosition = e.GetPosition(_canvas);

        // Get the ellipse from the canvas
        _ellipse = _canvas.Children[1] as Ellipse;

        // Move the ellipse to the point where the mouse was clicked
        _ellipse.SetValue(Canvas.LeftProperty, _mousePosition.X - _ellipse.ActualWidth / 2);
        _ellipse.SetValue(Canvas.TopProperty, _mousePosition.Y - _ellipse.ActualHeight / 2);

        await Task.Delay(100);

        // Attach storyboard to the ellipse
        Storyboard.SetTarget(_storyboard, _ellipse);
        _storyboard.Begin();
    }
}

private void Storyboard_Completed(object sender, EventArgs e)
{
    _storyboard.Remove();
}

The result

Example

A few considerations:

  • Defined Storyboard animations has static values, so the Ripple effect would look different on different size of the Button.
  • The Ellipse fill is also static, could be changed by adding Dependency Property.
  • Buttons Border CornerRadius is also static, could be changed by adding Dependency Property.

With all that said, here's link to the repo and to the nuget.