Search code examples
c#windowsuwpwin-universal-appuwp-xaml

Animate thumb of UWP Slider


I am using the Slider XAML control in my UWP app. Whenever we tap on the slider and change its value, I want the slider thumb to simply show a translation animation while moving from the old position to the new position. How can this be achieved?


Solution

  • You can use a property to get the last value and play an animation to set the value from the last vale to current value.

    Adding a Slider in xaml

        <Slider x:Name="Slider" Value="{x:Bind Value,Mode=TwoWay}"/>
    

    Adding a DependencyProperty in MainPage.

        public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
            "Value", typeof(double), typeof(MainPage), new PropertyMetadata(default(double), (s
                , e) =>
            {
                ((MainPage) s)._lastValue = (double) e.OldValue;
            }));
    
        public double Value
        {
            get => (double) GetValue(ValueProperty);
            set => SetValue(ValueProperty, value);
        }
    
        private double _lastValue;
    

    The Value can set the _lastValue that can begin the Storyboard

    Adding PointerPressedEvent and PointerReleasedEvent in MainPage code for the Slider will handle it.

        public MainPage()
        {
            InitializeComponent();
            Slider.AddHandler(PointerPressedEvent, new PointerEventHandler(Slider_OnPointerPressed), true);
            Slider.AddHandler(PointerReleasedEvent, new PointerEventHandler(Slider_OnPointerReleased), true);
        }
    

    I save the ClickPoint in Slider_OnPointerPressed and I compare the current point in Slider_OnPointerReleased. The user may click the Slider that should begin the animation and the user drag the thumb that should not begin the animation.

        private void Slider_OnPointerPressed(object sender, PointerRoutedEventArgs e)
        {
            var slider = (Slider) sender;
    
            ClickPoint = e.GetCurrentPoint(slider).Position;
        }
    
        private Point ClickPoint { set; get; }
    
        private void Slider_OnPointerReleased(object sender, PointerRoutedEventArgs e)
        {
            var slider = (Slider) sender;
    
            var point = e.GetCurrentPoint(slider).Position;
    
            var x = point.X - ClickPoint.X;
            var y = point.Y - ClickPoint.Y;
            var length = x * x + y * y;
            if (length < 10)
            {
                AnimationValue();
            }
        }
    

    The AnimationValue will begin the animation.

        private void AnimationValue()
        {
            var storyboard = new Storyboard();
    
            var animation = new DoubleAnimation
            {
                From = _lastValue,
                To = Value,
                Duration = TimeSpan.FromSeconds(2),
                EasingFunction = new CubicEase(),
                EnableDependentAnimation = true
            };
    
            Storyboard.SetTarget(animation, Slider);
            Storyboard.SetTargetProperty(animation, "Value");
    
            storyboard.BeginTime = TimeSpan.Zero;
            storyboard.Children.Add(animation);
    
            storyboard.Begin();
    
            _storyboard = storyboard;
        }
    

    You can custom the Duration and EasingFunction to change the time.

    All code in github

    If you can read Chinese, please read my blog because my English is very poor, I am worried that I can’t tell you exactly what I mean.