亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何使用Shape做動畫

發布時間:2020-12-05 11:41:13 來源:億速云 閱讀:182 作者:小新 欄目:編程語言

這篇文章主要介紹如何使用Shape做動畫,文中介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們一定要看完!

1. 使用StrokeDashOffset做等待提示動畫

圓形的等待提示動畫十分容易做,只要讓它旋轉就可以了:

如何使用Shape做動畫

但是圓形以外的形狀就不容易做了,例如三角形,總不能讓它單純地旋轉吧:

如何使用Shape做動畫

要解決這個問題可以使用StrokeDashOffset。StrokeDashOffset用于控制虛線邊框的第一個短線相對于Shape開始點的位移,使用動畫控制這個數值可以做出邊框滾動的效果:

如何使用Shape做動畫

<Page.Resources><Storyboard x:Name="ProgressStoryboard"><DoubleAnimationUsingKeyFrames EnableDependentAnimation="True"                                       
Storyboard.TargetProperty="(Shape.StrokeDashOffset)"                                       
Storyboard.TargetName="triangle"><EasingDoubleKeyFrame KeyTime="0:1:0"                                  
Value="-500" /></DoubleAnimationUsingKeyFrames></Storyboard></Page.Resources><Grid Background="#FFCCCCCC"><Grid Height="100"          
HorizontalAlignment="Center"><StackPanel Orientation="Horizontal"                    
VerticalAlignment="Center"><TextBlock Text="L"                       
FontSize="55"                       
Margin="0,0,5,4" /><local:Triangle x:Name="triangle"                            
Height="40"                            
Width="40"                            
StrokeThickness="2"                            
Stroke="RoyalBlue"                            
StrokeDashArray="4.045 4.045"                            
StrokeDashOffset="0.05"                            
StrokeDashCap="Round" /><TextBlock Text="ading..."                       
FontSize="55"                       
Margin="5,0,0,4" /></StackPanel></Grid></Grid>

需要注意的是Shape的邊長要正好能被StrokeDashArray中短線和缺口的和整除,即 滿足邊長 / StrokeThickness % Sum( StrokeDashArray ) = 0,這是因為在StrokeDashOffset=0的地方會截斷短線,如下圖所示:

如何使用Shape做動畫

另外注意的是邊長的計算,如Rectangle,邊長并不是(Height + Width) * 2,而是(Height - StrokeThickness) * 2 + (Width- StrokeThickness) * 2,如下圖所示,邊長應該從邊框正中間開始計算:

如何使用Shape做動畫

有一些Shape的邊長計算還會受到Stretch影響,如上一篇中自定義的Triangle:

如何使用Shape做動畫

<StackPanel Orientation="Horizontal" HorizontalAlignment="Center"><Grid Height="50"          
Width="50"><local:Triangle Stretch="Fill"                        
StrokeThickness="5"                        
Stroke="RoyalBlue" /></Grid><Grid Height="50"          
Width="50"          
Margin="10,0,0,0"><local:Triangle Stretch="None"                        
StrokeThickness="5"                        
Stroke="RoyalBlue" /></Grid></StackPanel>

2. 使用StrokeDashArray做進度提示動畫

StrokeDashArray用于將Shape的邊框變成虛線,StrokeDashArray的值是一個double類型的有序集合,里面的數值指定虛線中每一段以StrokeThickness為單位的長度。用StrokeDashArray做進度提示的基本做法就是將進度Progress通過Converter轉換為分成兩段的StrokeDashArray,第一段為實線,表示當前進度,第二段為空白。假設一個Shape的邊長是100,當前進度為50,則將StrokeDashArray設置成{50,double.MaxValue}兩段。

做成動畫如下圖所示:

如何使用Shape做動畫

<Page.Resources><Style TargetType="TextBlock"><Setter Property="FontSize"                
Value="12" /></Style><local:ProgressToStrokeDashArrayConverter x:Key="ProgressToStrokeDashArrayConverter"                                              
TargetPath="{Binding ElementName=Triangle}" /><local:ProgressToStrokeDashArrayConverter2 x:Key="ProgressToStrokeDashArrayConverter2"                                               
TargetPath="{Binding ElementName=Triangle}" />
<toolkit:StringFormatConverter x:Key="StringFormatConverter" /><local:ProgressWrapper x:Name="ProgressWrapper" /><Storyboard x:Name="Storyboard1"><DoubleAnimation Duration="0:0:5"                         
To="100"                         
Storyboard.TargetProperty="Progress"                         
Storyboard.TargetName="ProgressWrapper"                         
EnableDependentAnimation="True" /></Storyboard></Page.Resources><Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"><Viewbox Height="150"><StackPanel Orientation="Horizontal"><Grid><local:Triangle Height="40"                                
Width="40"                                
StrokeThickness="2"                                
Stroke="DarkGray" /><local:Triangle x:Name="Triangle"                                
Height="40"                                
Width="40"                                
StrokeThickness="2"                                
Stroke="RoyalBlue"                                
StrokeDashArray="{Binding Progress,Source={StaticResource ProgressWrapper},Converter={StaticResource ProgressToStrokeDashArrayConverter}}" /><TextBlock Text="{Binding Progress,Source={StaticResource ProgressWrapper},Converter={StaticResource StringFormatConverter},ConverterParameter='{}{0:0}'}"                           
HorizontalAlignment="Center"                           
VerticalAlignment="Center"                           
Margin="0,15,0,0" /></Grid><Grid Margin="20,0,0,0"><local:Triangle Height="40"                                
Width="40"                                
StrokeThickness="2"                                
Stroke="DarkGray" /><local:Triangle x:Name="Triangle2"                                
Height="40"                                
Width="40"                                
StrokeThickness="2"                                
Stroke="RoyalBlue"                               
StrokeDashArray="{Binding Progress,Source={StaticResource ProgressWrapper},Converter={StaticResource ProgressToStrokeDashArrayConverter2}}" /><TextBlock Text="{Binding Progress,Source={StaticResource ProgressWrapper},Converter={StaticResource StringFormatConverter},ConverterParameter='{}{0:0}'}"                           
HorizontalAlignment="Center"                           
VerticalAlignment="Center"                           
Margin="0,15,0,0" /></Grid></StackPanel></Viewbox></Grid>

其中ProgressToStrokeDashArrayConverter和ProgressToStrokeDashArrayConverter2的代碼如下:

public class ProgressToStrokeDashArrayConverter : DependencyObject, IValueConverter
{/// <summary>/// 獲取或設置TargetPath的值/// </summary>  public Path TargetPath
    {
    get { return (Path)GetValue(TargetPathProperty);
     }
    set {
     SetValue(TargetPathProperty, value); 
    }
    }/// <summary>/// 標識 TargetPath 依賴屬性。/// 
    </summary>public static readonly DependencyProperty TargetPathProperty =
        DependencyProperty.Register("TargetPath", typeof(Path), typeof(ProgressToStrokeDashArrayConverter), new PropertyMetadata(null));public virtual object Convert(object value, Type targetType, object parameter, string language)
    {
    if (value is double == false)return null;

        var progress = (double)value;if (TargetPath == null)return null;var totalLength = GetTotalLength();
        var firstSection = progress * totalLength / 100 / TargetPath.StrokeThickness;if (progress == 100)
            firstSection = Math.Ceiling(firstSection);var result = new DoubleCollection { 
            firstSection, double.MaxValue };return result;
    }public object ConvertBack(object value, Type targetType, object parameter, string language)
    {throw new NotImplementedException();
    }protected double GetTotalLength()
    {var geometry = TargetPath.Data as PathGeometry;
    if (geometry == null)
    return 0;
    if (geometry.Figures.Any() == false)return 0;
    var figure = geometry.Figures.FirstOrDefault();
    if (figure == null)
    return 0;
    var totalLength = 0d;
    var point = figure.StartPoint;
    foreach (var item in figure.Segments)
        {
        var segment = item as LineSegment;
        if (segment == null)
        return 0;

            totalLength += Math.Sqrt(Math.Pow(point.X - segment.Point.X, 2) + Math.Pow(point.Y - segment.Point.Y, 2));
            point = segment.Point;
        }

        totalLength += Math.Sqrt(Math.Pow(point.X - figure.StartPoint.X, 2) + Math.Pow(point.Y - figure.StartPoint.Y, 2));
        return totalLength;
    }
}
public class ProgressToStrokeDashArrayConverter2 : ProgressToStrokeDashArrayConverter
{
public override object Convert(object value, Type targetType, object parameter, string language)
    {
    if (value is double == false)return null;

        var progress = (double)value;
        if (TargetPath == null)
        return null;
        var totalLength = GetTotalLength();
        totalLength = totalLength / TargetPath.StrokeThickness;
        var thirdSection = progress * totalLength / 100;
        if (progress == 100)
            thirdSection = Math.Ceiling(thirdSection);

        var secondSection = (totalLength - thirdSection) / 2;
        var result = new DoubleCollection { 0, secondSection, thirdSection, double.MaxValue };
        return result;
    }
}

由于代碼只是用于演示,protected double GetTotalLength()寫得比較將就。可以看到這兩個Converter繼承自DependencyObject,這是因為這里需要通過綁定為TargetPath賦值。

這里還有另一個類ProgressWrapper:

public class ProgressWrapper : DependencyObject
{/// <summary>/// 獲取或設置Progress的值/// </summary>  public double Progress
    {get { return (double)GetValue(ProgressProperty); }set { SetValue(ProgressProperty, value); }
    }/// <summary>/// 標識 Progress 依賴屬性。/// 
    </summary>public static readonly DependencyProperty ProgressProperty =
        DependencyProperty.Register("Progress", typeof(double), typeof(ProgressWrapper), new PropertyMetadata(0d));
}

因為這里沒有可供Storyboard操作的double屬性,所以用這個類充當Storyboard和StrokeDashArray的橋梁。UWPCommunityToolkit中也有一個差不多用法的類BindableValueHolder,這個類通用性比較強,可以參考它的用法。

3. 使用Behavior改進進度提示動畫代碼

只是做個動畫而已,又是Converter,又是Wrapper,又是Binding,看起來十分復雜,如果Shape上面有Progress屬性就方便多了。這時候首先會考慮附加屬性,在XAML用法如下:

<UserControl.Resources>
  <Storyboard x:Name="Storyboard1"><DoubleAnimation Duration="0:0:5"                     
  To="100"                     
  Storyboard.TargetProperty="(local:PathExtention.Progress)"                     
  Storyboard.TargetName="Triangle" />
  </Storyboard></UserControl.Resources><Grid x:Name="LayoutRoot"      
  Background="White"><local:Triangle x:Name="Triangle"                    
  Height="40"                    
  local:PathExtention.Progress="0"                    
  Width="40"                    
  StrokeThickness="2"                    
  Stroke="RoyalBlue" ></local:Triangle></Grid>

但其實這是行不通的,XAML有一個存在了很久的限制:However, an existing limitation of the Windows Runtime XAML implementation is that you cannot animate a custom attached property.。這個限制決定了XAML不能對自定義附加屬性做動畫。不過,這個限制只限制了不能對自定義附加屬性本身做動畫,但對附加屬性中的類的屬性則可以,例如以下這種寫法應該是行得通的:

<UserControl.Resources>
  <Storyboard x:Name="Storyboard1"><DoubleAnimation Duration="0:0:5"                     
  To="100"                     
  Storyboard.TargetProperty="(local:PathExtention.Progress)"                     
  Storyboard.TargetName="TrianglePathExtention" />
  </Storyboard></UserControl.Resources><Grid x:Name="LayoutRoot"      
  Background="White"><local:Triangle x:Name="Triangle"                    
  Height="40"                    
  Width="40"                    
  StrokeThickness="2"                    
  Stroke="RoyalBlue" >  <local:PathHelper><local:PathExtention x:Name="TrianglePathExtention"                             
  Progress="0" />  </local:PathHelper></local:Triangle></Grid>

更優雅的寫法是利用XamlBehaviors,這篇文章很好地解釋了XamlBehaviors的作用:

XAML Behaviors非常重要,因為它們提供了一種方法,讓開發人員能夠以一種簡潔、可重復的方式輕松地向UI對象添加功能。
他們無需創建控件的子類或重復編寫邏輯代碼,只要簡單地增加一個XAML代碼片段。

要使用Behavior改進現有代碼,只需實現一個PathProgressBehavior:

public class PathProgressBehavior : Behavior<UIElement>
{protected override void OnAttached()
    {base.OnAttached();UpdateStrokeDashArray();
    }/// <summary>/// 獲取或設置Progress的值/// </summary>  public double Progress
    {get { return (double)GetValue(ProgressProperty); }set { SetValue(ProgressProperty, value); }
    }/*Progress DependencyProperty*/protected virtual void OnProgressChanged(double oldValue, double newValue)
    {UpdateStrokeDashArray();
    }protected virtual double GetTotalLength(Path path)
    {/*some code*/}private void UpdateStrokeDashArray()
    {
    var target = AssociatedObject as Path;if (target == null)return;double progress = Progress;
    //if (target.ActualHeight == 0 || target.ActualWidth == 0)//    
    return;
    if (target.StrokeThickness == 0)
    return;
    var totalLength = GetTotalLength(target);
    var firstSection = progress * totalLength / 100 / target.StrokeThickness;
    if (progress == 100)
            firstSection = Math.Ceiling(firstSection);
            var result = new DoubleCollection {
             firstSection, double.MaxValue 
             };
        target.StrokeDashArray = result;
    }
}

XAML中如下使用:

<UserControl.Resources>
  <Storyboard x:Name="Storyboard1"><DoubleAnimation Duration="0:0:5"                     
  To="100"                     
  Storyboard.TargetProperty="Progress"                     
  Storyboard.TargetName="PathProgressBehavior"                     
  EnableDependentAnimation="True"/>
  </Storyboard></UserControl.Resources><Grid x:Name="LayoutRoot"      
  Background="White">
  <local:Triangle x:Name="Triangle"                  
  Height="40"                  
  local:PathExtention.Progress="0"                  
  Width="40"                  
  StrokeThickness="2"                  
  Stroke="RoyalBlue" ><interactivity:Interaction.Behaviors>  
  <local:PathProgressBehavior x:Name="PathProgressBehavior" /></interactivity:Interaction.Behaviors>
  </local:Triangle></Grid>

這樣看起來就清爽多了。

4. 模仿背景填充動畫

先看看效果:

如何使用Shape做動畫

其實這篇文章里并不會討論填充動畫,不過首先聲明做填充動畫會更方便快捷,這一段只是深入學習過程中的產物,實用價值不高。
上圖三角形的填充的效果只需要疊加兩個同樣大小的Shape,前面那個設置Stretch="Uniform",再通過DoubleAnimation改變它的高度就可以了。文字也是相同的原理,疊加兩個相同的TextBlock,將前面那個放在一個無邊框的ScrollViewer里再去改變ScrollViewer的高度。

<Page.Resources><Style TargetType="TextBlock"><Setter Property="FontSize"               
Value="12" /></Style><local:ProgressToHeightConverter x:Key="ProgressToHeightConverter"                                     
TargetContentControl="{Binding ElementName=ContentControl}" /><local:ReverseProgressToHeightConverter x:Key="ReverseProgressToHeightConverter"                                           
TargetContentControl="{Binding ElementName=ContentControl2}" /><toolkit:StringFormatConverter x:Key="StringFormatConverter" /><local:ProgressWrapper x:Name="ProgressWrapper" /><Storyboard x:Name="Storyboard1"><DoubleAnimation Duration="0:0:5"                         
To="100"                         
Storyboard.TargetProperty="Progress"                         
Storyboard.TargetName="ProgressWrapper"                         
EnableDependentAnimation="True" /></Storyboard></Page.Resources><Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"><Grid><local:Triangle Height="40"                        
Width="40"                        
StrokeThickness="2"                        
Fill="LightGray" /><local:Triangle  Height="40"                         
Width="40"                         
Stretch="Fill"                         
StrokeThickness="2"                         
Stroke="RoyalBlue" /><ContentControl x:Name="ContentControl"                       
 VerticalAlignment="Bottom"                       
 HorizontalAlignment="Center"                        
 Height="{Binding Progress,Source={StaticResource ProgressWrapper},Converter={StaticResource ProgressToHeightConverter}}"><local:Triangle x:Name="Triangle3"                            Height="40"                            
 Width="40"                            
 StrokeThickness="2"                            
 Fill="RoyalBlue"                            
 Stretch="Uniform"                            
 VerticalAlignment="Bottom" /></ContentControl><TextBlock Text="{Binding Progress,Source={StaticResource ProgressWrapper},Converter={StaticResource StringFormatConverter},ConverterParameter='{}{0:0}'}"                   
 HorizontalAlignment="Center"                   
 VerticalAlignment="Center"                   
 Margin="0,12,0,0"                   
 Foreground="White" /><ContentControl x:Name="ContentControl2"                        
 Height="{Binding Progress,Source={StaticResource ProgressWrapper},Converter={StaticResource ReverseProgressToHeightConverter}}"                        
 VerticalAlignment="Top"                        
 HorizontalAlignment="Center"><ScrollViewer BorderThickness="0"                          
 Padding="0,0,0,0"                          
 VerticalScrollBarVisibility="Disabled"                          
 HorizontalScrollBarVisibility="Disabled"                          
 VerticalAlignment="Top"                          
 Height="40"><Grid  Height="40"><TextBlock Text="{Binding Progress,Source={StaticResource ProgressWrapper},Converter={StaticResource StringFormatConverter},ConverterParameter='{}{0:0}'}"                               
 HorizontalAlignment="Center"                               
 VerticalAlignment="Center"                               
 Margin="0,12,0,0" /></Grid></ScrollViewer></ContentControl></Grid></Grid>

ProgressToHeightConverter和ReverseProgressToHeightConverter的代碼如下:

public class ProgressToHeightConverter : DependencyObject, IValueConverter
{/// <summary>/// 獲取或設置TargetContentControl的值/// </summary>  public ContentControl TargetContentControl
    {
    get { 
    return (ContentControl)GetValue(TargetContentControlProperty); 
    }
    set { 
    SetValue(TargetContentControlProperty, value); 
    }
    }/// <summary>/// 標識 TargetContentControl 依賴屬性。///
     </summary>public static readonly DependencyProperty TargetContentControlProperty =
        DependencyProperty.Register("TargetContentControl", typeof(ContentControl), typeof(ProgressToHeightConverter), new PropertyMetadata(null));
        public object Convert(object value, Type targetType, object parameter, string language)
    {
    if (value is double == false)
    return 0d;

        var progress = (double)value;
        if (TargetContentControl == null)
        return 0d;
        var element = TargetContentControl.Content as FrameworkElement;
        if (element == null)
        return 0d;return element.Height * progress / 100;
    }public object ConvertBack(object value, Type targetType, object parameter, string language)
    {throw new NotImplementedException();
    }

      
}public class ReverseProgressToHeightConverter : DependencyObject, IValueConverter
{/// <summary>/// 獲取或設置TargetContentControl的值/// </summary>  
public ContentControl TargetContentControl
    {
    get { 
    return (ContentControl)GetValue(TargetContentControlProperty);
     }
    set { 
    SetValue(TargetContentControlProperty, value); 
    }
    }/// <summary>/// 標識 TargetContentControl 依賴屬性。/// 
    </summary>public static readonly DependencyProperty TargetContentControlProperty =
        DependencyProperty.Register("TargetContentControl", typeof(ContentControl), typeof(ReverseProgressToHeightConverter), new PropertyMetadata(null));
        public object Convert(object value, Type targetType, object parameter, string language)
    {
    if (value is double == false)
    return double.NaN;

        var progress = (double)value;if (TargetContentControl == null)return double.NaN;
        var element = TargetContentControl.Content as FrameworkElement;
        if (element == null)return double.NaN;
        return element.Height * (100 - progress) / 100;
    }
    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
    throw new NotImplementedException();
    }
}

再提醒一次,實際上老老實實做填充動畫好像更方便些。

5. 將動畫應用到Button的ControlTemplate

同樣的技術,配合ControlTemplate可以制作很有趣的按鈕:

如何使用Shape做動畫

PointerEntered時,按鈕的邊框從進入點向反方向延伸。PointerExited時,邊框從反方向向移出點消退。要做到這點需要在PointerEntered時改變邊框的方向,使用了ChangeAngleToEnterPointerBehavior:

public class ChangeAngleToEnterPointerBehavior : Behavior<Ellipse>
{protected override void OnAttached()
    {base.OnAttached();
        AssociatedObject.PointerEntered += OnAssociatedObjectPointerEntered;
        AssociatedObject.PointerExited += OnAssociatedObjectPointerExited;
    }protected override void OnDetaching()
    {base.OnDetaching();
        AssociatedObject.PointerEntered -= OnAssociatedObjectPointerEntered;
        AssociatedObject.PointerExited -= OnAssociatedObjectPointerExited;
    }private void OnAssociatedObjectPointerExited(object sender, PointerRoutedEventArgs e)
    {UpdateAngle(e);
    }private void OnAssociatedObjectPointerEntered(object sender, PointerRoutedEventArgs e)
    {UpdateAngle(e);
    }private void UpdateAngle(PointerRoutedEventArgs e)
    {if (AssociatedObject == null || AssociatedObject.StrokeThickness == 0)return;

        AssociatedObject.RenderTransformOrigin = new Point(0.5, 0.5);var rotateTransform = AssociatedObject.RenderTransform as RotateTransform;if (rotateTransform == null)
        {
            rotateTransform = new RotateTransform();
            AssociatedObject.RenderTransform = rotateTransform;
        }var point = e.GetCurrentPoint(AssociatedObject.Parent as UIElement).Position;var centerPoint = new Point(AssociatedObject.ActualWidth / 2, AssociatedObject.ActualHeight / 2);var angleOfLine = Math.Atan2(point.Y - centerPoint.Y, point.X - centerPoint.X) * 180 / Math.PI;
        rotateTransform.Angle = angleOfLine + 180;
    }
}

這個類命名不是很好,不過將就一下吧。

為了做出邊框延伸的效果,另外需要一個類EllipseProgressBehavior:

public class EllipseProgressBehavior : Behavior<Ellipse>
{/// <summary>/// 獲取或設置Progress的值/// </summary>  
public double Progress
    {
    get { 
    return (double)GetValue(ProgressProperty); 
    }
    set { 
    SetValue(ProgressProperty, value); 
    }
    }/// <summary>/// 標識 Progress 依賴屬性。/// </summary>
    public static readonly DependencyProperty ProgressProperty =
        DependencyProperty.Register("Progress", typeof(double), typeof(EllipseProgressBehavior), new PropertyMetadata(0d, OnProgressChanged));
        private static void OnProgressChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
    {
    var target = obj as EllipseProgressBehavior;
    double oldValue = (double)args.OldValue;
    double newValue = (double)args.NewValue;if (oldValue != newValue)
            target.OnProgressChanged(oldValue, newValue);
    }
    protected virtual void OnProgressChanged(double oldValue, double newValue)
    {UpdateStrokeDashArray();
    }protected virtual double GetTotalLength()
    {if (AssociatedObject == null)return 0;
    return (AssociatedObject.ActualHeight - AssociatedObject.StrokeThickness) * Math.PI;
    }private void UpdateStrokeDashArray()
    {if (AssociatedObject == null || AssociatedObject.StrokeThickness == 0)
    return;
    //if (target.ActualHeight == 0 || target.ActualWidth == 0)//    
    return;var totalLength = GetTotalLength();
        totalLength = totalLength / AssociatedObject.StrokeThickness;
        var thirdSection = Progress * totalLength / 100;
        var secondSection = (totalLength - thirdSection) / 2;
        var result = new DoubleCollection { 0, secondSection, thirdSection, double.MaxValue };
        AssociatedObject.StrokeDashArray = result;
    }

}

套用到ControlTemplate如下:

<ControlTemplate TargetType="Button"><Grid x:Name="RootGrid"><VisualStateManager.VisualStateGroups><VisualStateGroup x:Name="CommonStates"><VisualStateGroup.Transitions><VisualTransition GeneratedDuration="0:0:1"                                      
To="Normal"><Storyboard><DoubleAnimationUsingKeyFrames EnableDependentAnimation="True"                                                           
Storyboard.TargetProperty="(local:EllipseProgressBehavior.Progress)"                                                           
Storyboard.TargetName="EllipseProgressBehavior"><EasingDoubleKeyFrame KeyTime="0:0:1"                                                      
Value="0"><EasingDoubleKeyFrame.EasingFunction><QuinticEase EasingMode="EaseOut" /></EasingDoubleKeyFrame.EasingFunction></EasingDoubleKeyFrame></DoubleAnimationUsingKeyFrames></Storyboard></VisualTransition><VisualTransition GeneratedDuration="0:0:1"                                     
To="PointerOver"><Storyboard><DoubleAnimationUsingKeyFrames EnableDependentAnimation="True"                                                           
Storyboard.TargetProperty="(local:EllipseProgressBehavior.Progress)"                                                           
Storyboard.TargetName="EllipseProgressBehavior"><EasingDoubleKeyFrame KeyTime="0:0:1"                                                      
Value="100"><EasingDoubleKeyFrame.EasingFunction><QuinticEase EasingMode="EaseOut" /></EasingDoubleKeyFrame.EasingFunction></EasingDoubleKeyFrame></DoubleAnimationUsingKeyFrames></Storyboard></VisualTransition></VisualStateGroup.Transitions><VisualState x:Name="Normal"><Storyboard><PointerUpThemeAnimation Storyboard.TargetName="RootGrid" /></Storyboard></VisualState><VisualState x:Name="PointerOver"><Storyboard><PointerUpThemeAnimation Storyboard.TargetName="RootGrid" /></Storyboard><VisualState.Setters><Setter Target="EllipseProgressBehavior.(local:EllipseProgressBehavior.Progress)"                               
 Value="100" /></VisualState.Setters></VisualState><VisualState x:Name="Pressed"><Storyboard><PointerDownThemeAnimation Storyboard.TargetName="RootGrid" /></Storyboard></VisualState><VisualState x:Name="Disabled" /></VisualStateGroup></VisualStateManager.VisualStateGroups><ContentPresenter x:Name="ContentPresenter"                          
AutomationProperties.AccessibilityView="Raw"                          
ContentTemplate="{TemplateBinding ContentTemplate}"                          
ContentTransitions="{TemplateBinding ContentTransitions}"                          
Content="{TemplateBinding Content}"                          
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"                          
Padding="{TemplateBinding Padding}"                         
 VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" /><Ellipse Fill="Transparent"                 Stroke="{TemplateBinding BorderBrush}"                 StrokeThickness="2"><interactivity:Interaction.Behaviors><local:ChangeAngleToEnterPointerBehavior /><local:EllipseProgressBehavior x:Name="EllipseProgressBehavior" /></interactivity:Interaction.Behaviors></Ellipse></Grid></ControlTemplate>
注意:我沒有鼓勵任何人自定義按鈕外觀的意思,能用系統自帶的動畫或樣式就盡量用系統自帶的,沒有設計師的情況下
又想UI做得與眾不同通常會做得很難看。想要UI好看,合理的布局、合理的顏色、合理的圖片就足夠了。

6. 結語

在學習Shape的過程中覺得好玩就做了很多嘗試,因為以前工作中做過不少等待、進度的動畫,所以這次就試著做出本文的動畫。
XAML的傳統動畫并沒有提供太多功能,主要是ColorAnimation、DoubleAnimation、PointAnimation三種,不過靠Binding和Converter可以彌補這方面的不足,實現很多需要的功能。
本文的一些動畫效果參考了SVG的動畫。話說回來,Windows 10 1703新增了SvgImageSource,不過看起來只是簡單地將SVG翻譯成對應的Shape,然后用Shape呈現,不少高級特性都不支持(如下圖陰影的濾鏡),用法如下:

<Image><Image.Source><SvgImageSource UriSource="feoffset_1.svg" /></Image.Source></Image>

SvgImageSource:
如何使用Shape做動畫

原本的Svg:
如何使用Shape做動畫

以上是“如何使用Shape做動畫”這篇文章的所有內容,感謝各位的閱讀!希望分享的內容對大家有幫助,更多相關知識,歡迎關注億速云行業資訊頻道!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

德兴市| 迭部县| 金川县| 余庆县| 龙陵县| 楚雄市| 宁德市| 静海县| 罗平县| 利辛县| 凤山市| 岳阳县| 峨边| 石城县| 阿克苏市| 扬州市| 钟祥市| 西贡区| 深州市| 清徐县| 云梦县| 界首市| 盘锦市| 建湖县| 辽宁省| 北宁市| 军事| 靖边县| 平塘县| 湄潭县| 耒阳市| 鹤峰县| 柳林县| 普兰县| 阳谷县| 敖汉旗| 仁寿县| 霍邱县| 龙陵县| 武乡县| 阳东县|