locked
How can I make label to smoothly increase height ? RRS feed

  • Question

  • User388510 posted

    I want to make label or any other element to smoothly increase height or width. But I can't find any examples how to make something like this. Can you advice me how to make this? I'm thinking about changing absolute coordinates of label in cycle in async thread,but I can't manage how to access label from another thread(none of solutions with invoke from this forum worked for me)

    Thursday, August 22, 2019 4:14 PM

Answers

  • User335020 posted

    Try this

    public static class AnimationExtensions
    {
        public static bool AnimationsEnabled { get; set; } = true;
    
        public static async Task<bool> AnimateDoublePropertyTo(this IAnimatable self, Action<double> setter, double fromValue, double newValue, uint length = 250,
                Easing easing = null, bool delayIfAnimationDisabled = false)
            {
                bool ret = false;
    
                if (self.AnimationIsRunning(nameof(AnimateDoublePropertyTo)))
                {
                    self.AbortAnimation(nameof(AnimateDoublePropertyTo));
                }
    
                if (!AnimationsEnabled)
                {
                    setter(newValue);
                    if (delayIfAnimationDisabled)
                    {
                        await Task.Delay((int)length);
                    }
                    return ret;
                }
    
                try
                {
                    double Transform(double t) => TransformDoubleValue(fromValue, newValue, t);
    
                    ret = await TransmuteDoublePropertyAnimation(self, setter, nameof(AnimateDoublePropertyTo), Transform, length, easing);
                }
                catch
                {
                    setter(fromValue);
                }
    
                return ret;
            }
    
            private static Task<bool> TransmuteDoublePropertyAnimation(IAnimatable element, Action<double> setter, string name, Func<double, double> transform, uint length = 250U, Easing easing = null)
            {
                easing = easing ?? Easing.Linear;
                var taskCompletionSource = new TaskCompletionSource<bool>();
    
                element.Animate(name, transform, setter, 16, length, easing, (v, c) => taskCompletionSource.SetResult(c));
    
                return taskCompletionSource.Task;
            }
    
            private static double TransformDoubleValue(double fromValue, double newValue, double t)
            {
                var result = fromValue + t * (newValue - fromValue);
    
                return result;
            }
    }
    

    and than for example:

    label.AnimateDoublePropertyTo((v) => label.HeightRequest = v, label.Height, label.Height+100);

    • Marked as answer by Anonymous Thursday, June 3, 2021 12:00 AM
    Friday, August 23, 2019 7:37 AM

All replies

  • User89714 posted

    @Zoom said: I want to make label or any other element to smoothly increase height or width. But I can't find any examples how to make something like this. Can you advice me how to make this? I'm thinking about changing absolute coordinates of label in cycle in async thread,but I can't manage how to access label from another thread(none of solutions with invoke from this forum worked for me)

    Use ScaleTo. See https://docs.microsoft.com/en-us/dotnet/api/xamarin.forms.viewextensions.scaleto?view=xamarin-forms

    Do not attempt to do animation from a non-UI thread.

    Thursday, August 22, 2019 4:54 PM
  • User388510 posted

    @JohnHardman said:

    @Zoom said: I want to make label or any other element to smoothly increase height or width. But I can't find any examples how to make something like this. Can you advice me how to make this? I'm thinking about changing absolute coordinates of label in cycle in async thread,but I can't manage how to access label from another thread(none of solutions with invoke from this forum worked for me)

    Use ScaleTo. See

    Do not attempt to do animation from a non-UI thread.

    But ScaleTo increases both X and Y, and I need only Y. And ScaleY doesn't have any animation. Am I missing something?

    Thursday, August 22, 2019 5:48 PM
  • User369979 posted

    You can use Timer to implement the animation by yourself:

    System.Timers.Timer timer = new System.Timers.Timer();
    timer.Interval = 250;
    timer.Elapsed += (s, args) =>
    {
        Device.BeginInvokeOnMainThread(() =>
        {
            MyLabel.HeightRequest += 1;
            if (MyLabel.HeightRequest == 100)
            {
                timer.Stop();
                timer.Dispose();
            }
        });
    };
    timer.Start();
    

    Adjust the interval and increasing constant as you want.

    Friday, August 23, 2019 6:39 AM
  • User388510 posted

    @LandLu said: You can use Timer to implement the animation by yourself:

    System.Timers.Timer timer = new System.Timers.Timer();
    timer.Interval = 250;
    timer.Elapsed += (s, args) =>
    {
        Device.BeginInvokeOnMainThread(() =>
        {
            MyLabel.HeightRequest += 1;
            if (MyLabel.HeightRequest == 100)
            {
                timer.Stop();
                timer.Dispose();
            }
        });
    };
    timer.Start();
    

    Adjust the interval and increasing constant as you want.

    Thanks for your help! Height increases correct, but without any animation. If I'm not mistaken, that's why

    HeightRequest does not immediately change the Bounds of a VisualElement, however setting the HeightRequest will change the result of calls to GetSizeRequest, which will in turn modify the final size the element receives during a layout cycle. Is there any way to manually refresh page after height change?

    Friday, August 23, 2019 7:21 AM
  • User369979 posted

    @Zoom Plase try my code. I placed the height request changed in a timer. It means every 0.25 second the height will increase 1. You can set a smaller value so that it will display an animation.

    Friday, August 23, 2019 7:26 AM
  • User335020 posted

    Try this

    public static class AnimationExtensions
    {
        public static bool AnimationsEnabled { get; set; } = true;
    
        public static async Task<bool> AnimateDoublePropertyTo(this IAnimatable self, Action<double> setter, double fromValue, double newValue, uint length = 250,
                Easing easing = null, bool delayIfAnimationDisabled = false)
            {
                bool ret = false;
    
                if (self.AnimationIsRunning(nameof(AnimateDoublePropertyTo)))
                {
                    self.AbortAnimation(nameof(AnimateDoublePropertyTo));
                }
    
                if (!AnimationsEnabled)
                {
                    setter(newValue);
                    if (delayIfAnimationDisabled)
                    {
                        await Task.Delay((int)length);
                    }
                    return ret;
                }
    
                try
                {
                    double Transform(double t) => TransformDoubleValue(fromValue, newValue, t);
    
                    ret = await TransmuteDoublePropertyAnimation(self, setter, nameof(AnimateDoublePropertyTo), Transform, length, easing);
                }
                catch
                {
                    setter(fromValue);
                }
    
                return ret;
            }
    
            private static Task<bool> TransmuteDoublePropertyAnimation(IAnimatable element, Action<double> setter, string name, Func<double, double> transform, uint length = 250U, Easing easing = null)
            {
                easing = easing ?? Easing.Linear;
                var taskCompletionSource = new TaskCompletionSource<bool>();
    
                element.Animate(name, transform, setter, 16, length, easing, (v, c) => taskCompletionSource.SetResult(c));
    
                return taskCompletionSource.Task;
            }
    
            private static double TransformDoubleValue(double fromValue, double newValue, double t)
            {
                var result = fromValue + t * (newValue - fromValue);
    
                return result;
            }
    }
    

    and than for example:

    label.AnimateDoublePropertyTo((v) => label.HeightRequest = v, label.Height, label.Height+100);

    • Marked as answer by Anonymous Thursday, June 3, 2021 12:00 AM
    Friday, August 23, 2019 7:37 AM
  • User89714 posted

    @Zoom said: But ScaleTo increases both X and Y, and I need only Y. And ScaleY doesn't have any animation. Am I missing something?

    If you look at the Xamarin.Forms source (it is open source and available from GitHub), you can find the source of ScaleTo in Xamarin.Forms.Core\ViewExtensions.cs

    ScaleTo looks like this:

        public static Task<bool> ScaleTo(this VisualElement view, double scale, uint length = 250, Easing easing = null)
        {
            if (view == null)
                throw new ArgumentNullException(nameof(view));
    
            return AnimateTo(view, view.Scale, scale, nameof(ScaleTo), (v, value) => v.Scale = value, length, easing);
        }
    

    Implementing a ScaleYTo should be little more than replacing each instance of Scale by ScaleY.

    Friday, August 23, 2019 10:09 AM