├── .gitattributes
├── .github
└── workflows
│ └── dotnetcore.yml
├── AvaloniaRipple.sln
├── AvaloniaRipple
├── App.xaml
├── App.xaml.cs
├── AvaloniaRipple.csproj
├── MainWindow.xaml
├── MainWindow.xaml.cs
├── Program.cs
└── nuget.config
├── README.md
└── Ripple
├── Ripple.csproj
└── RippleEffect
├── RippleEffect.cs
└── RippleEffect.xaml
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/.github/workflows/dotnetcore.yml:
--------------------------------------------------------------------------------
1 | name: .NET Core
2 |
3 | on: [push]
4 |
5 | jobs:
6 | build:
7 |
8 | runs-on: ubuntu-latest
9 |
10 | steps:
11 | - uses: actions/checkout@v1
12 | - name: Setup .NET Core
13 | uses: actions/setup-dotnet@v1
14 | with:
15 | dotnet-version: 3.0
16 | - name: Build with dotnet
17 | run: dotnet build --configuration Release
18 |
--------------------------------------------------------------------------------
/AvaloniaRipple.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.29409.12
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AvaloniaRipple", "AvaloniaRipple\AvaloniaRipple.csproj", "{ECB440AE-658B-4602-87CD-BE7FE8285362}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ripple", "Ripple\Ripple.csproj", "{ECBAA8F5-8837-4F09-A33E-9157EF1C3FE2}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Release|Any CPU = Release|Any CPU
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {ECB440AE-658B-4602-87CD-BE7FE8285362}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17 | {ECB440AE-658B-4602-87CD-BE7FE8285362}.Debug|Any CPU.Build.0 = Debug|Any CPU
18 | {ECB440AE-658B-4602-87CD-BE7FE8285362}.Release|Any CPU.ActiveCfg = Release|Any CPU
19 | {ECB440AE-658B-4602-87CD-BE7FE8285362}.Release|Any CPU.Build.0 = Release|Any CPU
20 | {ECBAA8F5-8837-4F09-A33E-9157EF1C3FE2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {ECBAA8F5-8837-4F09-A33E-9157EF1C3FE2}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {ECBAA8F5-8837-4F09-A33E-9157EF1C3FE2}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {ECBAA8F5-8837-4F09-A33E-9157EF1C3FE2}.Release|Any CPU.Build.0 = Release|Any CPU
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | GlobalSection(ExtensibilityGlobals) = postSolution
29 | SolutionGuid = {CF585909-D4B7-4ABC-B2B5-EF4699EF6943}
30 | EndGlobalSection
31 | EndGlobal
32 |
--------------------------------------------------------------------------------
/AvaloniaRipple/App.xaml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/AvaloniaRipple/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using Avalonia;
2 | using Avalonia.Markup.Xaml;
3 |
4 | namespace AvaloniaRipple
5 | {
6 | public class App : Application
7 | {
8 | public override void Initialize()
9 | {
10 | AvaloniaXamlLoader.Load(this);
11 | }
12 | }
13 | }
--------------------------------------------------------------------------------
/AvaloniaRipple/AvaloniaRipple.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | winExe
4 | netcoreapp3.0
5 |
6 |
7 |
8 | %(Filename)
9 |
10 |
11 | Designer
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/AvaloniaRipple/MainWindow.xaml:
--------------------------------------------------------------------------------
1 |
12 |
15 |
17 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/AvaloniaRipple/MainWindow.xaml.cs:
--------------------------------------------------------------------------------
1 | using Avalonia;
2 | using Avalonia.Controls;
3 | using Avalonia.Markup.Xaml;
4 |
5 | namespace AvaloniaRipple
6 | {
7 | public class MainWindow : Window
8 | {
9 | public MainWindow()
10 | {
11 | InitializeComponent();
12 | #if DEBUG
13 | this.AttachDevTools();
14 | #endif
15 | }
16 |
17 | private void InitializeComponent()
18 | {
19 | AvaloniaXamlLoader.Load(this);
20 | }
21 | }
22 | }
--------------------------------------------------------------------------------
/AvaloniaRipple/Program.cs:
--------------------------------------------------------------------------------
1 | using Avalonia;
2 | using Avalonia.Controls;
3 | using Avalonia.Logging.Serilog;
4 |
5 | namespace AvaloniaRipple
6 | {
7 | internal class Program
8 | {
9 | // Initialization code. Don't use any Avalonia, third-party APIs or any
10 | // SynchronizationContext-reliant code before AppMain is called: things aren't initialized
11 | // yet and stuff might break.
12 | public static void Main(string[] args) => BuildAvaloniaApp().Start(AppMain, args);
13 |
14 | // Avalonia configuration, don't remove; also used by visual designer.
15 | public static AppBuilder BuildAvaloniaApp()
16 | => AppBuilder.Configure()
17 | .UsePlatformDetect()
18 | .LogToDebug();
19 |
20 | // Your application's entry point. Here you can initialize your MVVM framework, DI
21 | // container, etc.
22 | private static void AppMain(Application app, string[] args)
23 | {
24 | app.Run(new MainWindow());
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/AvaloniaRipple/nuget.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Avalonia Ripple Effect
2 |
3 | [](https://i.imgur.com/SJo17KT.gif)
4 |
5 | Sample of ripple effect using Avalonia.
6 | All things which wrapped in RippleEffect will be effected
7 |
8 | ```sh
9 |
13 |
15 |
20 |
21 |
22 | ```
23 |
--------------------------------------------------------------------------------
/Ripple/Ripple.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.0
5 |
6 |
7 |
8 |
9 | Designer
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/Ripple/RippleEffect/RippleEffect.cs:
--------------------------------------------------------------------------------
1 | using Avalonia;
2 | using Avalonia.Animation;
3 | using Avalonia.Controls;
4 | using Avalonia.Controls.Primitives;
5 | using Avalonia.Controls.Shapes;
6 | using Avalonia.Media;
7 | using Avalonia.Styling;
8 | using System;
9 |
10 | namespace Ripple
11 | {
12 | public class RippleEffect : ContentControl
13 | {
14 | #region Styled properties
15 |
16 | public static readonly StyledProperty RippleFillProperty =
17 | AvaloniaProperty.Register(nameof(RippleFill));
18 |
19 | public Brush RippleFill
20 | {
21 | get { return GetValue(RippleFillProperty); }
22 | set { SetValue(RippleFillProperty, value); }
23 | }
24 |
25 | public static readonly StyledProperty RippleOpacityProperty =
26 | AvaloniaProperty.Register(nameof(RippleOpacity));
27 |
28 | public double RippleOpacity
29 | {
30 | get { return GetValue(RippleOpacityProperty); }
31 | set { SetValue(RippleOpacityProperty, value); }
32 | }
33 |
34 | #endregion Styled properties
35 |
36 | private Ellipse _circle;
37 | private Animation _ripple;
38 | private Point _pointer;
39 | private IAnimationSetter _toWidth;
40 | private IAnimationSetter _fromMargin;
41 | private IAnimationSetter _toMargin;
42 | private bool _isRunning;
43 |
44 | public RippleEffect()
45 | {
46 | this.AddHandler(PointerPressedEvent, async (s, e) =>
47 | {
48 | if (_isRunning)
49 | {
50 | return;
51 | }
52 | _pointer = e.GetPosition(this);
53 | _isRunning = true;
54 | var maxWidth = Math.Max(Bounds.Width, Bounds.Height) * 2.2D;
55 | _toWidth.Value = maxWidth;
56 | _fromMargin.Value = _circle.Margin = new Thickness(_pointer.X, _pointer.Y, 0, 0);
57 | _toMargin.Value = new Thickness(_pointer.X - maxWidth / 2, _pointer.Y - maxWidth / 2, 0, 0);
58 |
59 | await _ripple.RunAsync(_circle);
60 |
61 | _isRunning = false;
62 | });
63 | }
64 |
65 | protected override void OnTemplateApplied(TemplateAppliedEventArgs e)
66 | {
67 | base.OnTemplateApplied(e);
68 |
69 | _circle = e.NameScope.Find("Circle");
70 |
71 | var style = _circle.Styles[0] as Style;
72 | _ripple = style.Animations[0] as Animation;
73 | _toWidth = _ripple.Children[1].Setters[1];
74 | _fromMargin = _ripple.Children[0].Setters[0];
75 | _toMargin = _ripple.Children[1].Setters[0];
76 |
77 | style.Animations.Remove(_ripple);
78 | }
79 | }
80 | }
--------------------------------------------------------------------------------
/Ripple/RippleEffect/RippleEffect.xaml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------