基于WPF繪制一個(gè)點(diǎn)贊大拇指動(dòng)畫
效果圖
好久沒有寫wpf了。
最近看到飛書的點(diǎn)贊動(dòng)畫非常有意思,決定試試,雖然不及飛書那樣的絢麗,但是練手還是可以的,希望自己的手藝還在!
實(shí)現(xiàn)思路
那么如何寫一個(gè)這樣的動(dòng)畫呢?
首先需要刨析這個(gè)動(dòng)畫的構(gòu)成:
- 外圈圓
- 大拇指-1豎著
- 大拇指-2握著
- 顫動(dòng)動(dòng)畫
- 中心旋轉(zhuǎn)動(dòng)畫
- 展開中心旋轉(zhuǎn)動(dòng)畫
當(dāng)我們分析這些東西剩下的就好辦了。
首先我們先辦了這個(gè)最難的東西大拇指。
這個(gè)東西的構(gòu)成,我們使用Path 直接去寫。顯然我們就會(huì)得到這樣的代碼
<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>
當(dāng)我們?cè)趐ath 100*100的大小的時(shí)候使用腦補(bǔ)進(jìn)行繪制就就可以了。
至于這個(gè)小褶皺我曾經(jīng)不想要,但是看到了自己的豬爪...還是決定加上了。
這代碼的原理非常簡(jiǎn)單,基本都是基本的直線繪制,最難的就是用了個(gè)貝塞爾來(lái)制造大拇指背部的弧度.
不管咋樣還是弄出來(lái)個(gè)簡(jiǎn)單的贊。
剩下就是握著的狀態(tài)了
那么我們只需要修改部分代碼就可以達(dá)到了~
也就是
<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參數(shù)和q最后的end point參數(shù)的y的值都是降到0了 這樣會(huì)形成一個(gè)簡(jiǎn)單的弧度
哈 這樣子 我們就是得到了兩個(gè)手掌的不同狀態(tài)了。
剩下的事情就是來(lái)組裝吧~~~~
首先是大拇指張開和大拇指握住的狀態(tài)轉(zhuǎn)換。
做到這事情最簡(jiǎn)單的動(dòng)畫就是使用eventtigger來(lái)做,我們使用簡(jiǎn)單的鼠標(biāo)按下事件作為啟動(dòng),當(dāng)然了 想要豐富過程也是可以使用鼠標(biāo)浮動(dòng)事件作為啟動(dòng)事件之一。
<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的資源 所以子啊寫動(dòng)畫的時(shí)候 用離弦值就非常方便了。
觀察代碼,我們僅僅只是在點(diǎn)下的時(shí)候讓path轉(zhuǎn)換為握住的data,因?yàn)槲覀冃枰谒砷_左鍵的時(shí)候才讓拇指豎起來(lái)。
所以還需要補(bǔ)上一個(gè)MouseLeftButtonUp的動(dòng)畫
這最終的代碼就是
<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>
效果圖
莫名的搞笑....
基礎(chǔ)的東西我們構(gòu)建好了,剩下就是補(bǔ)全了。
不全顫抖啊,補(bǔ)全中心旋轉(zhuǎn)動(dòng)畫,也就是手指握住后有一個(gè)向下的動(dòng)畫。
首先這個(gè)顫動(dòng) 我們可以簡(jiǎn)單的理解為位移,一個(gè)快速的上下左右的位移
正好WPF有這種動(dòng)畫 所以我們就可以得到如下的代碼
<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中
看得出來(lái) 離散動(dòng)畫的值就是簡(jiǎn)單的marigin的位移,代碼非常簡(jiǎn)單。
就是在這里顫抖...
雖然看上去不是很好看,但是我們結(jié)合下一個(gè)動(dòng)畫,也就是手掌向下就會(huì)好很多了
這個(gè)動(dòng)畫很明顯是一個(gè)旋轉(zhuǎn)動(dòng)畫,所以我們需要提前準(zhǔn)備一個(gè)roteate的transofrom
代碼如下
<Path.RenderTransform> <RotateTransform x:Name="rote" Angle="0"/> </Path.RenderTransform>
動(dòng)畫代碼如下
<DoubleAnimation Duration="0:0:0.1" To="30" Storyboard.TargetName="rote" Storyboard.TargetProperty="Angle"> <DoubleAnimation.EasingFunction> <CubicEase/> </DoubleAnimation.EasingFunction> </DoubleAnimation>
我們簡(jiǎn)單的使用了一個(gè)函數(shù),提升一下效果的動(dòng)感...
但是感覺沒啥用
效果圖就是這樣的了
雖然看上去已經(jīng)非常不錯(cuò)了,但是還有些不做,想想 我們的手都朝下了 松開之后為啥沒有一個(gè)向上的彈簧動(dòng)作呢?
也就是我們需要在抬起時(shí)加上一個(gè)角度的旋轉(zhuǎn)。
<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動(dòng)畫解除掉。
剩下的就是圈的構(gòu)造和動(dòng)畫。
圓圈呢,我們可以是直接的圓圈,也可以是broder,看個(gè)人喜歡了。
我就不羅嗦直接上代碼
<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>
構(gòu)造了兩個(gè)嵌套的borderr,寬度其實(shí)可以隨意,只是演示的時(shí)候放大的大小而已。
動(dòng)畫則是放到了path的啟動(dòng)動(dòng)畫之中
也就是
<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>
代碼非常簡(jiǎn)單,控制下內(nèi)圈的大小,還有是否隱藏而已。
這樣子我們就最終得到了頭圖的效果了
總的過程還是比較簡(jiǎn)單的。
完整代碼
下面是全部的代碼
<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>
以上就是基于WPF繪制一個(gè)點(diǎn)贊大拇指動(dòng)畫的詳細(xì)內(nèi)容,更多關(guān)于WPF繪制點(diǎn)贊動(dòng)畫的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
WPF+SkiaSharp實(shí)現(xiàn)自繪投籃小游戲
這篇文章主要介紹了如何利用WPF+SkiaSharp實(shí)現(xiàn)自繪投籃小游戲。此案例主要是針對(duì)光線投影法碰撞檢測(cè)功能的示例,順便做成了一個(gè)小游戲,很簡(jiǎn)單,但是,效果卻很不錯(cuò),感興趣的可以動(dòng)手嘗試一下2022-08-08WinForm實(shí)現(xiàn)頁(yè)面按鈕定時(shí)隱藏功能
這篇文章主要介紹了WinForm實(shí)現(xiàn)頁(yè)面按鈕定時(shí)隱藏功能,結(jié)合實(shí)例形式分析了WinForm基于定時(shí)器的頁(yè)面控件屬性動(dòng)態(tài)操作相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2017-05-05