on master help sign in
Implement smooth button animation with programmatic TransformOperations and Component state
commit96a28d479a4a85621746df3b4a3ab088399d8f83 authoriko <mail@iko.soy> dateMon 13 Apr 2026, 11:42 (6 months ago) parent550b6a9
1 file changed+26−28
client/Buttons.fs+26−28
client/Buttons.fs+26−28
@@ -7,28 +7,31 @@ open Fabulous.Avalonia
77open type Fabulous.Avalonia.View
88
99module Buttons =
10+ open Avalonia.Media.Transformation
11+ open System
1012
11− let button (text: string) (msg: 'msg) =
12− let shadowRef = ViewRef<Avalonia.Controls.Shapes.Rectangle>()
13−
14− let animate pressed =
15− match shadowRef.TryValue with
16− | None -> ()
17− | Some c ->
18− let offset = if pressed then 4. else 12.
19− match c.RenderTransform with
20− | :? TranslateTransform as t ->
21− t.X <- offset
22− t.Y <- offset
23− | _ ->
24− c.RenderTransform <- TranslateTransform(offset, offset)
13+ let private animationDuration: int64 = 60
14+
15+ let private translate x y =
16+ let b = TransformOperations.CreateBuilder 1
17+ b.AppendTranslate(x, y)
18+ b.Build() :> ITransform
2519
20+ let button (text: string) (msg: 'msg) =
2621 Component(text) {
27− Grid() {
22+ let! pressed = Context.State(false)
23+ let offset = if pressed.Current then 4. else 8.
24+
25+ (Grid() {
2826 Rectangle()
29− .reference(shadowRef)
3027 .fill(SolidColorBrush(Colors.Black))
31− .renderTransform (TranslateTransform(12., 12.))
28+ .renderTransform(translate offset offset)
29+ .transition (
30+ TransformOperationsTransition(
31+ Avalonia.Visual.RenderTransformProperty,
32+ TimeSpan.FromMilliseconds animationDuration
33+ )
34+ )
3235
3336 Rectangle().fill (SolidColorBrush(Constants.accentColor))
3437
@@ -39,15 +42,10 @@ module Buttons =
3942 .fontWeight(FontWeight.Bold)
4043 .center()
4144 .margin (8.)
42−
43− Button(msg, Rectangle().strokeThickness(4.).stroke(SolidColorBrush(Colors.Black)).margin (-3.))
44− .onPointerPressed(fun _ -> animate true)
45− .onPointerReleased(fun _ -> animate false)
46− .onPointerExited(fun _ -> animate false)
47− .background(Brushes.Transparent)
48− .borderThickness(0.)
49− .padding(0.)
50− .horizontalAlignment(Avalonia.Layout.HorizontalAlignment.Stretch)
51− .verticalAlignment (Avalonia.Layout.VerticalAlignment.Stretch)
52− }
45+ })
46+ .background(Brushes.Transparent)
47+ .onPointerPressed(fun _ -> pressed.Set true)
48+ .onPointerReleased(fun _ -> pressed.Set false)
49+ .onPointerExited(fun _ -> pressed.Set false)
50+ .onTapped (fun _ -> msg)
5351 }