效果圖
好久沒有寫wpf了。
最近看到飛書的點贊動畫非常有意思,決定試試,雖然不及飛書那樣的絢麗,但是練手還是可以的,希望自己的手藝還在!
那麼如何寫一個這樣的動畫呢?
首先需要刨析這個動畫的構成:
外圈圓
大拇指-1豎著
大拇指-2握著
顫動動畫
中心旋轉動畫
展開中心旋轉動畫
當我們分析這些東西剩下的就好辦了。
首先我們先辦了這個最難的東西大拇指。
這個東西的構成,我們使用Path 直接去寫。顯然我們就會得到這樣的程式碼
<Geometry x:Key="t1"> M 20 40 v 0 40 h 0 7 v 0 -40 z M 30 42 v 0 38 h 40 0 l 15 -35 l -10 -5 h -25 0 l 2 -20 <!--小褶皺--> q -10 -10, -20 22 z </Geometry>
當我們在path 100*100的大小的時候使用腦補進行繪製就就可以了。
至於這個小褶皺我曾經不想要,但是看到了自己的豬爪...還是決定加上了。
這程式碼的原理非常簡單,基本都是基本的直線繪製,最難的就是用了個貝塞爾來製造大拇指背部的弧度.
不管咋樣還是弄出來個簡單的贊。
剩下就是握著的狀態了
那麼我們只需要修改部分程式碼就可以達到了~
也就是
<Geometry x:Key="t2"> M 20 40 v 0 40 h 0 7 v 0 -40 z M 30 42 v 0 38 h 40 0 l 15 -35 l -10 -5 h -25 0 l 2 0 <!--小褶皺--> q -10 -10, -20 0 z </Geometry>
我們修改了最後兩行程式碼的 l 的y引數和q最後的end point引數的y的值都是降到0了 這樣會形成一個簡單的弧度
哈 這樣子 我們就是得到了兩個手掌的不同狀態了。
剩下的事情就是來組裝吧~~~~
首先是大拇指張開和大拇指握住的狀態轉換。
做到這事情最簡單的動畫就是使用eventtigger來做,我們使用簡單的滑鼠按下事件作為啟動,當然了 想要豐富過程也是可以使用滑鼠浮動事件作為啟動事件之一。
<Path.Triggers> <EventTrigger RoutedEvent="MouseLeftButtonDown"> <BeginStoryboard x:Name="Bs1"> <Storyboard> <ObjectAnimationUsingKeyFrames BeginTime="0:0:0" Storyboard.TargetProperty="Data"> <DiscreteObjectKeyFrame KeyTime="0:0:0.01"> <DiscreteObjectKeyFrame.Value> <StaticResource ResourceKey="t2"/> </DiscreteObjectKeyFrame.Value> </DiscreteObjectKeyFrame> </ObjectAnimationUsingKeyFrames> </Storyboard> </BeginStoryboard> </EventTrigger> </Path.Triggers>
為了做件事 ,我們把geometry作為window的資源 所以子啊寫動畫的時候 用離弦值就非常方便了。
觀察程式碼,我們僅僅只是在點下的時候讓path轉換為握住的data,因為我們需要在鬆開左鍵的時候才讓拇指豎起來。
所以還需要補上一個MouseLeftButtonUp的動畫
這最終的程式碼就是
<Path.Triggers> <EventTrigger RoutedEvent="MouseLeftButtonDown"> <BeginStoryboard x:Name="Bs1"> <Storyboard> <ObjectAnimationUsingKeyFrames BeginTime="0:0:0" Storyboard.TargetProperty="Data"> <DiscreteObjectKeyFrame KeyTime="0:0:0.01"> <DiscreteObjectKeyFrame.Value> <StaticResource ResourceKey="t2"/> </DiscreteObjectKeyFrame.Value> </DiscreteObjectKeyFrame> </ObjectAnimationUsingKeyFrames> </Storyboard> </BeginStoryboard> </EventTrigger> <EventTrigger RoutedEvent="MouseLeftButtonUp"> <RemoveStoryboard BeginStoryboardName="Bs1"/> </EventTrigger> </Path.Triggers>
效果圖
莫名的搞笑....
基礎的東西我們構建好了,剩下就是補全了。
不全顫抖啊,補全中心旋轉動畫,也就是手指握住後有一個向下的動畫。
首先這個顫動 我們可以簡單的理解為位移,一個快速的上下左右的位移
正好WPF有這種動畫 所以我們就可以得到如下的程式碼
<ThicknessAnimationUsingKeyFrames RepeatBehavior="Forever" Duration="0:0:0.4" Storyboard.TargetProperty="Margin" > <SplineThicknessKeyFrame KeyTime="0:0:0.0" Value="4,3,0,0"/> <SplineThicknessKeyFrame KeyTime="0:0:0.2" Value="3,4,0,0"/> <SplineThicknessKeyFrame KeyTime="0:0:0.3" Value="0,0,4,0"/> <SplineThicknessKeyFrame KeyTime="0:0:0.35" Value="0,0,4,3"/> <SplineThicknessKeyFrame KeyTime="0:0:0.4" Value="4,3,0,0"/> </ThicknessAnimationUsingKeyFrames>
我們可以直程式碼放到path的eventtriger中
看得出來 離散動畫的值就是簡單的marigin的位移,程式碼非常簡單。
就是在這裡顫抖...
雖然看上去不是很好看,但是我們結合下一個動畫,也就是手掌向下就會好很多了
這個動畫很明顯是一個旋轉動畫,所以我們需要提前準備一個roteate的transofrom
程式碼如下
<Path.RenderTransform> <RotateTransform x:Name="rote" Angle="0"/> </Path.RenderTransform>
動畫程式碼如下
<DoubleAnimation Duration="0:0:0.1" To="30" Storyboard.TargetName="rote" Storyboard.TargetProperty="Angle"> <DoubleAnimation.EasingFunction> <CubicEase/> </DoubleAnimation.EasingFunction> </DoubleAnimation>
我們簡單的使用了一個函數,提升一下效果的動感...
但是感覺沒啥用
效果圖就是這樣的了
雖然看上去已經非常不錯了,但是還有些不做,想想 我們的手都朝下了 鬆開之後為啥沒有一個向上的彈簧動作呢?
也就是
我們需要在擡起時加上一個角度的旋轉。
也就是
<EventTrigger RoutedEvent="MouseLeftButtonUp"> <BeginStoryboard x:Name="Bs2"> <Storyboard> <DoubleAnimation FillBehavior="Stop" Duration="0:0:0.5" To="-30" Storyboard.TargetName="rote" Storyboard.TargetProperty="Angle"> <DoubleAnimation.EasingFunction> <CubicEase EasingMode="EaseOut"/> </DoubleAnimation.EasingFunction> </DoubleAnimation> </Storyboard> </BeginStoryboard> <RemoveStoryboard BeginStoryboardName="Bs1"/> </EventTrigger>
程式碼可以說手掌向下的反向操作。
順便播放完把bs1動畫解除掉。
剩下的就是圈的構造和動畫。
圓圈呢,我們可以是直接的圓圈,也可以是broder,看個人喜歡了。
我就不羅嗦直接上程式碼
<Border BorderThickness="2" Background="Transparent" BorderBrush="Transparent" CornerRadius="100" Width="200" Height="{Binding RelativeSource={RelativeSource Mode=Self}, Path=Width}" Grid.Column="1" Grid.Row="1"> <Border x:Name="sor" Visibility="Hidden" BorderThickness="2" Background="Transparent" BorderBrush="Transparent" CornerRadius="100" Width="200" Height="{Binding RelativeSource={RelativeSource Mode=Self}, Path=Width}" Grid.Column="1" Grid.Row="1"/> </Border>
構造了兩個巢狀的borderr,寬度其實可以隨意,只是演示的時候放大的大小而已。
動畫則是放到了path的啟動動畫之中
也就是
<DoubleAnimation RepeatBehavior="Forever" SpeedRatio="1.2" Duration="0:0:1.5" To="0" Storyboard.TargetName="sor" Storyboard.TargetProperty="Width"> <DoubleAnimation.EasingFunction> <CubicEase/> </DoubleAnimation.EasingFunction> </DoubleAnimation> <ObjectAnimationUsingKeyFrames BeginTime="0:0:0" Storyboard.TargetName="sor" Storyboard.TargetProperty="Visibility"> <DiscreteObjectKeyFrame KeyTime="0:0:0.1"> <DiscreteObjectKeyFrame.Value> <Visibility> Visible </Visibility> </DiscreteObjectKeyFrame.Value> </DiscreteObjectKeyFrame> </ObjectAnimationUsingKeyFrames>
程式碼非常簡單,控制下內圈的大小,還有是否隱藏而已。
這樣子我們就最終得到了頭圖的效果了
總的過程還是比較簡單的。
下面是全部的程式碼
<Window.Resources> <Geometry x:Key="t1"> M 20 40 v 0 40 h 0 7 v 0 -40 z M 30 42 v 0 38 h 40 0 l 15 -35 l -10 -5 h -25 0 l 2 -20 <!--小褶皺--> q -10 -10, -20 22 z </Geometry> <Geometry x:Key="t2"> M 20 40 v 0 40 h 0 7 v 0 -40 z M 30 42 v 0 38 h 40 0 l 15 -35 l -10 -5 h -25 0 l 2 0 <!--小褶皺--> q -10 -10, -20 0 z </Geometry> <PathGeometry Figures=" M 20 40 l 2 -5 v 0 5 h -2 0 z" x:Key="roue"/> </Window.Resources> <Grid> <Border BorderThickness="2" Background="Transparent" BorderBrush="BlueViolet" CornerRadius="100" Width="200" Height="{Binding RelativeSource={RelativeSource Mode=Self}, Path=Width}" Grid.Column="1" Grid.Row="1"> <Border x:Name="sor" Visibility="Hidden" BorderThickness="2" Background="Transparent" BorderBrush="Salmon" CornerRadius="100" Width="200" Height="{Binding RelativeSource={RelativeSource Mode=Self}, Path=Width}" Grid.Column="1" Grid.Row="1"/> </Border> <Grid Width="300" Height="300" ShowGridLines="False"> <Grid.RowDefinitions> <RowDefinition/> <RowDefinition /> <RowDefinition/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition/> <ColumnDefinition/> </Grid.ColumnDefinitions> <Path StrokeThickness="2" Grid.Column="1" Grid.Row="1" VerticalAlignment="Bottom" Stretch="Uniform" Fill="Pink" Width="80" Height="80" Stroke="Blue" Data="{StaticResource t1}" RenderTransformOrigin="0.5,0.5"> <Path.RenderTransform> <RotateTransform x:Name="rote" Angle="0"/> </Path.RenderTransform> <Path.Triggers> <EventTrigger RoutedEvent="MouseLeftButtonDown"> <BeginStoryboard x:Name="Bs1"> <Storyboard> <ObjectAnimationUsingKeyFrames BeginTime="0:0:0" Storyboard.TargetProperty="Data"> <DiscreteObjectKeyFrame KeyTime="0:0:0.01"> <DiscreteObjectKeyFrame.Value> <StaticResource ResourceKey="t2"/> </DiscreteObjectKeyFrame.Value> </DiscreteObjectKeyFrame> </ObjectAnimationUsingKeyFrames> <ThicknessAnimationUsingKeyFrames RepeatBehavior="Forever" Duration="0:0:0.4" Storyboard.TargetProperty="Margin" > <SplineThicknessKeyFrame KeyTime="0:0:0.0" Value="4,3,0,0"/> <SplineThicknessKeyFrame KeyTime="0:0:0.2" Value="3,4,0,0"/> <SplineThicknessKeyFrame KeyTime="0:0:0.3" Value="0,0,4,0"/> <SplineThicknessKeyFrame KeyTime="0:0:0.35" Value="0,0,4,3"/> <SplineThicknessKeyFrame KeyTime="0:0:0.4" Value="4,3,0,0"/> </ThicknessAnimationUsingKeyFrames> <DoubleAnimation Duration="0:0:0.1" To="30" Storyboard.TargetName="rote" Storyboard.TargetProperty="Angle"> <DoubleAnimation.EasingFunction> <CubicEase/> </DoubleAnimation.EasingFunction> </DoubleAnimation> <DoubleAnimation RepeatBehavior="Forever" SpeedRatio="1.2" Duration="0:0:1.5" To="0" Storyboard.TargetName="sor" Storyboard.TargetProperty="Width"> <DoubleAnimation.EasingFunction> <CubicEase/> </DoubleAnimation.EasingFunction> </DoubleAnimation> <ObjectAnimationUsingKeyFrames BeginTime="0:0:0" Storyboard.TargetName="sor" Storyboard.TargetProperty="Visibility"> <DiscreteObjectKeyFrame KeyTime="0:0:0.1"> <DiscreteObjectKeyFrame.Value> <Visibility> Visible </Visibility> </DiscreteObjectKeyFrame.Value> </DiscreteObjectKeyFrame> </ObjectAnimationUsingKeyFrames> </Storyboard> </BeginStoryboard> </EventTrigger> <EventTrigger RoutedEvent="MouseLeftButtonUp"> <BeginStoryboard x:Name="Bs2"> <Storyboard> <DoubleAnimation FillBehavior="Stop" Duration="0:0:0.5" To="-30" Storyboard.TargetName="rote" Storyboard.TargetProperty="Angle"> <DoubleAnimation.EasingFunction> <CubicEase EasingMode="EaseOut"/> </DoubleAnimation.EasingFunction> </DoubleAnimation> </Storyboard> </BeginStoryboard> <RemoveStoryboard BeginStoryboardName="Bs1"/> </EventTrigger> </Path.Triggers> </Path> </Grid>