Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] AnimatedCornerRadius #240

Closed
AbdAlghaniAlbiek opened this issue Dec 7, 2021 · 7 comments
Closed

[Feature] AnimatedCornerRadius #240

AbdAlghaniAlbiek opened this issue Dec 7, 2021 · 7 comments

Comments

@AbdAlghaniAlbiek
Copy link

AbdAlghaniAlbiek commented Dec 7, 2021

Describe the problem this feature would solve

I have made a TemplatedControl that have 4 new properties (TopLeftCorner, TopRightCorner, BottomLeftCorner, BottomRightCorner) and each of them control in the radius of corner that associated with.
And the purpose of doing this that in WPF there type of animation called: "ThicknessAnimation" and this animation provide me the ability to animate the properties that are from thickness class like: (margin, padding, borderThickness ...) and because this animation isn't available in UWP the solutions simply was making a dependency property for each paramerter of the thickness and animate them all such as: (make four properties for the Margin => LeftMargin, TopMargin, RightMargin, BelowMawrgin, and animate all of them or some of them depending on your needs in one storyboard) and in my sample here I made animation for the corners of border

The generic xaml for this TemplatedControl :

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:CalculatorControlSample"
    xmlns:local2="using:CalculatorControlSample.Temp">

    <Style TargetType="local2:AnimatedCornerRadius">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="local2:AnimatedCornerRadius">
                    <Grid>
                        <Border
                        Width="{TemplateBinding Width}"
                        Height="{TemplateBinding Height}"
                        Opacity="{TemplateBinding Opacity}"
                        Background="{TemplateBinding Background}"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}"
                        CornerRadius="{TemplateBinding CornerRadius}"
                        HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
                        VerticalAlignment="{TemplateBinding VerticalAlignment}"/>

                        <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                          VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                                          Margin="{TemplateBinding Padding}"
                                          Content="{TemplateBinding Content}"/>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

And .cs file

public sealed class AnimatedCornerRadius : Control
 {
        public AnimatedCornerRadius()
        {
            this.DefaultStyleKey = typeof(AnimatedCornerRadius);
        }

        public object Content
        {
            get { return (object)GetValue(ContentProperty); }
            set { SetValue(ContentProperty, value); }
        }
        public static readonly DependencyProperty ContentProperty =
            DependencyProperty.Register(nameof(Content), typeof(object),typeof(AnimatedCornerRadius), new PropertyMetadata(null));

        public int TopLeftCorner
        {
            get { return (int)GetValue(TopLeftCornerProperty); }
            set { SetValue(TopLeftCornerProperty, value); }
        }
        public static readonly DependencyProperty TopLeftCornerProperty =
            DependencyProperty.Register(nameof(TopLeftCorner), typeof(int), typeof(AnimatedCornerRadius),
                new PropertyMetadata(0, (s, e) =>
                {
                    ((AnimatedCornerRadius)s).CornerRadius = new CornerRadius(
                        double.Parse(e.NewValue.ToString()),
                        ((AnimatedCornerRadius)s).CornerRadius.TopRight,
                        ((AnimatedCornerRadius)s).CornerRadius.BottomRight,
                        ((AnimatedCornerRadius)s).CornerRadius.BottomLeft);
                }));

        public int TopRightCorner
        {
            get { return (int)GetValue(TopRightCornerProperty); }
            set { SetValue(TopRightCornerProperty, value); }
        }
        public static readonly DependencyProperty TopRightCornerProperty =
            DependencyProperty.Register(nameof(TopRightCorner), typeof(int), typeof(AnimatedCornerRadius),
                new PropertyMetadata(0, (s, e) =>
                {
                    ((AnimatedCornerRadius)s).CornerRadius = new CornerRadius(
                        ((AnimatedCornerRadius)s).CornerRadius.TopLeft,
                        double.Parse(e.NewValue.ToString()),
                        ((AnimatedCornerRadius)s).CornerRadius.BottomRight,
                        ((AnimatedCornerRadius)s).CornerRadius.BottomLeft);
                }));

        public int BottomRightCorner
        {
            get { return (int)GetValue(BottomRightCornerProperty); }
            set { SetValue(BottomRightCornerProperty, value); }
        }
        public static readonly DependencyProperty BottomRightCornerProperty =
            DependencyProperty.Register(nameof(BottomRightCorner), typeof(int), typeof(AnimatedCornerRadius),
                new PropertyMetadata(0, (s, e) =>
                {
                    ((AnimatedCornerRadius)s).CornerRadius = new CornerRadius(
                        ((AnimatedCornerRadius)s).CornerRadius.TopLeft,
                        ((AnimatedCornerRadius)s).CornerRadius.TopRight,
                        double.Parse(e.NewValue.ToString()),
                        ((AnimatedCornerRadius)s).CornerRadius.BottomLeft);
                }));

        public int BottomLeftCorner
        {
            get { return (int)GetValue(BottomLeftCornerProperty); }
            set { SetValue(BottomLeftCornerProperty, value); }
        }
        public static readonly DependencyProperty BottomLeftCornerProperty =
            DependencyProperty.Register(nameof(BottomLeftCorner), typeof(int), typeof(AnimatedCornerRadius),
                new PropertyMetadata(0, (s, e) =>
                {
                    ((AnimatedCornerRadius)s).CornerRadius = new CornerRadius(
                        ((AnimatedCornerRadius)s).CornerRadius.TopLeft,
                        ((AnimatedCornerRadius)s).CornerRadius.TopRight,
                        ((AnimatedCornerRadius)s).CornerRadius.BottomRight,
                        double.Parse(e.NewValue.ToString()));
                }));
    }

and I define this control in MainPage and put the storyboard inside the same control and I made this storyboard ""Begin"" in code behind:

<controls:AnimatedCornerRadius

            x:Name="animatedBorder"
            Width="300"
            Height="300"
            Background="White"
            BorderBrush="Red"
            BorderThickness="8"
            CornerRadius="0"
            Tapped="animatedBorder_Tapped">
            <controls:AnimatedCornerRadius.Resources>
                <Storyboard x:Key="animatingCorners" AutoReverse="True">
                    <DoubleAnimation
                        EnableDependentAnimation="True"
                        Storyboard.TargetName="animatedBorder"
                        Storyboard.TargetProperty="TopLeftCorner"
                        From="0"
                        To="60"
                        Duration="0:0:1" />
                    <DoubleAnimation
                        EnableDependentAnimation="True"
                        Storyboard.TargetName="animatedBorder"
                        Storyboard.TargetProperty="TopRightCorner"
                        From="0"
                        To="60"
                        Duration="0:0:1" />
                    <DoubleAnimation
                        EnableDependentAnimation="True"
                        Storyboard.TargetName="animatedBorder"
                        Storyboard.TargetProperty="BottomRightCorner"
                        From="0"
                        To="60"
                        Duration="0:0:1" />
                    <DoubleAnimation
                        EnableDependentAnimation="True"
                        Storyboard.TargetName="animatedBorder"
                        Storyboard.TargetProperty="BottomLeftCorner"
                        From="0"
                        To="60"
                        Duration="0:0:1" />
                </Storyboard>
            </controls:AnimatedCornerRadius.Resources>
        </controls:AnimatedCornerRadius>

But then I think to make this properties as Attached properties to be possible to any one to implement it directly in any dependency object but then I figured out that It is impossible to animate attached properties, so I need your help to choice what is the better choice to deal with (making entirely new control to animate the corners OR there is some way else in behaviors and AnimationBuilder that can do it ????)

NOTE:
As you see, you can use these properties (TopLeftCorner, TopRightCorner, BottomRightCorner, BottomLeftCorner) as attached properties and adding it to VisualExtensions class too

Describe the solution

Making Animating CornerRadius possible using custom control

Describe alternatives you've considered

It's a good idea to add this type of animation (CornerRadiusAnimation or ThicknessAnimation) to AnimationBuilder if this possibole

Additional context & Screenshots

recordedVideo2021-12-07-232948.mp4
@ghost
Copy link

ghost commented Dec 7, 2021

Hello, 'AbdAlghaniAlbiek! Thanks for submitting a new feature request. I've automatically added a vote 👍 reaction to help get things started. Other community members can vote to help us prioritize this feature in the future!

@michael-hawker
Copy link
Member

Thanks for the example @AbdAlghaniAlbiek, did you have a scenario in mind where you were trying to animate the corners of an element?

@Sergio0694 thoughts on this? Can we not animate them in another method already?

@AbdAlghaniAlbiek
Copy link
Author

AbdAlghaniAlbiek commented Dec 9, 2021

@michael-hawker In Telegram when you swip an item from your contracts list, the corners of swiped item will be rounded like

Screenrecorder-2021-12-09-21-52-22-114.mp4

The problem is that there isn't a "DoubleAnimation" that can make animate each of corner of this control in AnimationBuilder

@Sergio0694
Copy link
Member

"And the purpose of doing this that in WPF there type of animation called: "ThicknessAnimation""

Yes, and it's not a coincidence that this animation type was removed on UWP: it's absolutely terrible for performance. It's even worse than regular double animations targeting properties such as eg. "Opacity". If we want to add a way to animate corner radiai, we should do that with a proper composition animation targeting the right property on the shadow visual, if there's one.

Also, side note: you can animate what you're describing with AnimationBuilder already, you're just not using the right APIs from it. You would need to use ExternalAnimation and pass your timeline there. I would not recommend using this here though, for performance reasons.

@AbdAlghaniAlbiek
Copy link
Author

hmm .. You mean the same reason that make you deleting light animation -> for performance reasons

If you don't have the desire to implement it in the toolkit, It's ok I'll close this issue .. you always know what is the best for this toolkit 👍👍

@Sergio0694
Copy link
Member

"You mean the same reason that make you deleting light animation -> for performance reasons"

Not really. All light effects are pretty fast as they run on the GPU. We also still have them in the new Microsoft Store 🙂
What I'm talking about here is that this proposed animation is running entirely on the CPU and causing a whole new layout update for every single animation frame, plus dependent animations are particularly heavy in general. We should always try to use the compositor instead, which is entirely GPU accellerated and not causing CPU load on the UI thread.

"If you don't have the desire to implement it in the toolkit, It's ok"

I didn't say we shouldn't add this. I just said if we want to add this, this is not the correct implementation for this.
It could be interesting to explore some new APIs to animate corner radiai using composition animations, sure 😊

@AbdAlghaniAlbiek
Copy link
Author

AbdAlghaniAlbiek commented Jul 7, 2022

Hi @Sergio0694 hope you have nice day. I'm sorry for bother you, but I was searching for a solution for this problem then I found this repo from the awesome @ratishphilip.
He was explaining how to make "Squircle" using composition and he animate its corners as you see 👇👇
Squircle_Gif

It'll be great way to animate the corners of any shape that made by the same way that "Squircle" is made of , and actually I think @ratishphilip made pull request for implementing his lib here
CommunityToolkit/WindowsCommunityToolkit#4115

@Arlodotexe Arlodotexe transferred this issue from CommunityToolkit/WindowsCommunityToolkit Jul 28, 2022
@CommunityToolkit CommunityToolkit locked and limited conversation to collaborators Jul 28, 2022
@Arlodotexe Arlodotexe converted this issue into discussion #241 Jul 28, 2022

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants