Browse Source

add Gestures sample page

Emmanuel Hansen 2 years ago
parent
commit
b9827c39ce

+ 3 - 0
samples/ControlCatalog/MainView.xaml

@@ -92,6 +92,9 @@
       <TabItem Header="Flyouts">
         <pages:FlyoutsPage />
       </TabItem>
+      <TabItem Header="Gestures">
+        <pages:GesturePage />
+      </TabItem>
       <TabItem Header="Image"
                ScrollViewer.HorizontalScrollBarVisibility="Disabled"
                ScrollViewer.VerticalScrollBarVisibility="Disabled">

+ 214 - 0
samples/ControlCatalog/Pages/GesturePage.cs

@@ -0,0 +1,214 @@
+using System;
+using System.Diagnostics;
+using System.Numerics;
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Input;
+using Avalonia.LogicalTree;
+using Avalonia.Markup.Xaml;
+using Avalonia.Rendering.Composition;
+using Avalonia.VisualTree;
+
+namespace ControlCatalog.Pages
+{
+    public class GesturePage : UserControl
+    {
+        private bool _isInit;
+        private float _currentScale;
+
+        public GesturePage()
+        {
+            this.InitializeComponent();
+        }
+
+        private void InitializeComponent()
+        {
+            AvaloniaXamlLoader.Load(this);
+        }
+
+        protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
+        {
+            base.OnAttachedToVisualTree(e);
+
+            if(_isInit)
+            {
+                return;
+            }
+
+            _isInit = true;
+
+            SetPullHandlers(this.Find<Border>("TopPullZone"), false);
+            SetPullHandlers(this.Find<Border>("BottomPullZone"), true);
+            SetPullHandlers(this.Find<Border>("RightPullZone"), true);
+            SetPullHandlers(this.Find<Border>("LeftPullZone"), false);
+
+            var image = this.Find<Image>("PinchImage");
+            SetPinchHandlers(image);
+
+            var reset = this.Find<Button>("ResetButton");
+
+            reset!.Click += (s, e) =>
+            {
+                var compositionVisual = ElementComposition.GetElementVisual(image);
+
+                if(compositionVisual!= null)
+                {
+                    _currentScale = 1;
+                    compositionVisual.Scale = new Vector3(1,1,1);
+                    image.InvalidateMeasure();
+                }
+            };
+                
+        }
+
+        private void SetPinchHandlers(Control? control)
+        {
+            if (control == null)
+            {
+                return;
+            }
+
+            _currentScale = 1;
+            Vector3 currentOffset = default;
+            bool isZooming = false;
+
+            CompositionVisual? compositionVisual = null;
+
+            void InitComposition(Control visual)
+            {
+                if (compositionVisual != null)
+                {
+                    return;
+                }
+
+                compositionVisual = ElementComposition.GetElementVisual(visual);
+            }
+
+            control.LayoutUpdated += (s, e) =>
+            {
+                InitComposition(control!);
+                if (compositionVisual != null)
+                {
+                    compositionVisual.Scale = new(_currentScale, _currentScale, 1);
+
+                    if(currentOffset == default)
+                    {
+                        currentOffset = compositionVisual.Offset;
+                    }
+                }
+            };
+
+            control.AddHandler(Gestures.PinchEvent, (s, e) =>
+            {
+                InitComposition(control!);
+
+                isZooming = true;
+
+                if(compositionVisual != null)
+                {
+                    var scale = _currentScale * (float)e.Scale;
+
+                    compositionVisual.Scale = new(scale, scale, 1);
+                }
+            });
+
+            control.AddHandler(Gestures.PinchEndedEvent, (s, e) =>
+            {
+                InitComposition(control!);
+
+                isZooming = false;
+
+                if (compositionVisual != null)
+                {
+                    _currentScale = compositionVisual.Scale.X;
+                }
+            });
+
+            control.AddHandler(Gestures.ScrollGestureEvent, (s, e) =>
+            {
+                InitComposition(control!);
+
+                if (compositionVisual != null && !isZooming)
+                {
+                    currentOffset -= new Vector3((float)e.Delta.X, (float)e.Delta.Y, 0);
+
+                    compositionVisual.Offset = currentOffset;
+                }
+            });
+        }
+
+        private void SetPullHandlers(Control? control, bool inverse)
+        {
+            if (control == null)
+            {
+                return;
+            }
+
+            var ball = control.FindLogicalDescendantOfType<Border>();
+
+            Vector3 defaultOffset = default;
+
+            CompositionVisual? ballCompositionVisual = null;
+
+            if (ball != null)
+            {
+                InitComposition(ball);
+            }
+            else
+            {
+                return;
+            }
+
+            control.LayoutUpdated += (s, e) =>
+            {
+                InitComposition(ball!);
+                if (ballCompositionVisual != null)
+                {
+                    defaultOffset = ballCompositionVisual.Offset;
+                }
+            };
+
+            control.AddHandler(Gestures.PullGestureEvent, (s, e) =>
+            {
+                Vector3 center = new((float)control.Bounds.Center.X, (float)control.Bounds.Center.Y, 0);
+                InitComposition(ball!);
+                if (ballCompositionVisual != null)
+                {
+                    ballCompositionVisual.Offset = defaultOffset + new System.Numerics.Vector3((float)e.Delta.X * 0.4f, (float)e.Delta.Y * 0.4f, 0) * (inverse ? -1 : 1);
+                }
+            });
+
+            control.AddHandler(Gestures.PullGestureEndedEvent, (s, e) =>
+            {
+                InitComposition(ball!);
+                if (ballCompositionVisual != null)
+                {
+                    ballCompositionVisual.Offset = defaultOffset;
+                }
+            });
+
+            void InitComposition(Control control)
+            {
+                if (ballCompositionVisual != null)
+                {
+                    return;
+                }
+
+                ballCompositionVisual = ElementComposition.GetElementVisual(ball);
+
+                if (ballCompositionVisual != null)
+                {
+                    var offsetAnimation = ballCompositionVisual.Compositor.CreateVector3KeyFrameAnimation();
+                    offsetAnimation.Target = "Offset";
+                    offsetAnimation.InsertExpressionKeyFrame(1.0f, "this.FinalValue");
+                    offsetAnimation.Duration = TimeSpan.FromMilliseconds(100);
+
+                    var implicitAnimations = ballCompositionVisual.Compositor.CreateImplicitAnimationCollection();
+                    implicitAnimations["Offset"] = offsetAnimation;
+
+                    ballCompositionVisual.ImplicitAnimations = implicitAnimations;
+                }
+            }
+        }
+    }
+}

+ 117 - 0
samples/ControlCatalog/Pages/GesturePage.xaml

@@ -0,0 +1,117 @@
+<UserControl xmlns="https://github.com/avaloniaui"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+             d:DesignHeight="800"
+             d:DesignWidth="400"
+             x:Class="ControlCatalog.Pages.GesturePage">
+  <StackPanel Orientation="Vertical"
+              Spacing="4">
+    <TextBlock FontWeight="Bold"
+               FontSize="18"
+               Margin="5">Pull Gexture (Touch / Pen)</TextBlock>
+    <TextBlock Margin="5">Pull from colored rectangles</TextBlock>
+    <Border>
+      <DockPanel HorizontalAlignment="Stretch"
+                 ClipToBounds="True"
+                 Margin="5"
+                 Height="200">
+        <Border DockPanel.Dock="Top"
+                Margin="2"
+                Name="TopPullZone"
+                Background="Transparent"
+                BorderBrush="Red"
+                HorizontalAlignment="Stretch"
+                Height="50"
+                BorderThickness="1">
+          <Border.GestureRecognizers>
+            <PullGestureRecognizer PullDirection="TopToBottom"/>
+          </Border.GestureRecognizers>
+          <Border Width="10"
+                  Height="10"
+                  HorizontalAlignment="Center"
+                  VerticalAlignment="Center"
+                  CornerRadius="5"
+                  Name="TopBall"
+                  Background="Green"/>
+        </Border>
+        <Border DockPanel.Dock="Bottom"
+                BorderBrush="Green"
+                Margin="2"
+                Background="Transparent"
+                Name="BottomPullZone"
+                HorizontalAlignment="Stretch"
+                Height="50"
+                BorderThickness="1">
+          <Border.GestureRecognizers>
+            <PullGestureRecognizer PullDirection="BottomToTop"/>
+          </Border.GestureRecognizers>
+          <Border Width="10"
+                  Name="BottomBall"
+                  HorizontalAlignment="Center"
+                  VerticalAlignment="Center"
+                  Height="10"
+                  CornerRadius="5"
+                  Background="Green"/>
+        </Border>
+        <Border DockPanel.Dock="Right"
+                Margin="2"
+                Background="Transparent"
+                Name="RightPullZone"
+                BorderBrush="Blue"
+                HorizontalAlignment="Right"
+                VerticalAlignment="Stretch"
+                Width="50"
+                BorderThickness="1">
+          <Border.GestureRecognizers>
+            <PullGestureRecognizer PullDirection="RightToLeft"/>
+          </Border.GestureRecognizers>
+          <Border Width="10"
+                  Height="10"
+                  Name="RightBall"
+                  HorizontalAlignment="Center"
+                  VerticalAlignment="Center"
+                  CornerRadius="5"
+                  Background="Green"/>
+
+        </Border>
+        <Border DockPanel.Dock="Left"
+                Margin="2"
+                Background="Transparent"
+                Name="LeftPullZone"
+                BorderBrush="Orange"
+                HorizontalAlignment="Left"
+                VerticalAlignment="Stretch"
+                Width="50"
+                BorderThickness="1">
+          <Border.GestureRecognizers>
+            <PullGestureRecognizer PullDirection="LeftToRight"/>
+          </Border.GestureRecognizers>
+          <Border Width="10"
+                  Height="10"
+                  Name="LeftBall"
+                  HorizontalAlignment="Center"
+                  VerticalAlignment="Center"
+                  CornerRadius="5"
+                  Background="Green"/>
+
+        </Border>
+      </DockPanel>
+    </Border>
+
+    <TextBlock FontWeight="Bold"
+               FontSize="18"
+               Margin="5">Pinch/Zoom Gexture (Multi Touch)</TextBlock>
+    <Border ClipToBounds="True">
+      <Image Stretch="UniformToFill"
+             Margin="5"
+             Name="PinchImage"
+             Source="/Assets/delicate-arch-896885_640.jpg">
+        <Image.GestureRecognizers>
+          <PinchGestureRecognizer/>
+          <ScrollGestureRecognizer CanHorizontallyScroll="True" CanVerticallyScroll="True"/>
+        </Image.GestureRecognizers>
+      </Image>
+    </Border>
+    <Button HorizontalAlignment="Center" Name="ResetButton">Reset</Button>
+  </StackPanel>
+</UserControl>