WPF水珠效果按鈕組的實(shí)現(xiàn)教程
效果圖
相關(guān)知識(shí)
這部分基本就是廢話,網(wǎng)上都能找到,我只不過(guò)是整理了以下.建議先不看,用到的時(shí)候可以回來(lái)看看
貝塞爾曲線
先來(lái)看兩組圖,有助于理解什么是貝塞爾曲線(圖片取自維基百科,參考鏈接1)
二次貝塞爾曲線:
P0是起點(diǎn),P2是終點(diǎn),P1是控制點(diǎn)
三次貝塞爾曲線:
P0是起點(diǎn),P2是終點(diǎn),P1是控制點(diǎn)1,P2是控制點(diǎn)2
依次連接所有點(diǎn),組成線段
t是比例,在0-1之間,就是每條線段的長(zhǎng)度都是1
貝塞爾曲線就是最里層的線段在t位置的點(diǎn)所組成的路徑
三次貝塞爾曲線公式:B(t)=(1-t)^3*P0+3(1-t)^2*t*P1+3(1-t)*t^2*P2+t^3*P3,0<=t<=1
B(t)代表曲線上任意點(diǎn),P0,1,2,3分別代表決定曲線的4個(gè)點(diǎn),t代表曲線長(zhǎng)度為1的任意取值
其他知識(shí)
沒(méi)接觸過(guò)貝塞爾曲線的話,可能得花些時(shí)間整理下,其他的知識(shí)就比較簡(jiǎn)單了
直角三角形,角A的對(duì)邊a,臨邊b,斜邊c
三角函數(shù):
sinA=a/c
cosA=b/c
勾股定理:
c^2=a^2+b^2
概括介紹
這個(gè)效果難點(diǎn)就兩部分:一是水球分離和融合時(shí)候的連接,二是主體圓的抖動(dòng)
然而其實(shí)網(wǎng)上都有解決方案了
第一部分是在兩個(gè)圓之間加個(gè)用貝塞爾曲線組成的path,用一樣的顏色,其實(shí)是障眼法.見參考鏈接4
第二部分是用4段三次貝塞爾曲線組成的path代替Ellipse,因?yàn)镋llipse是抖動(dòng)不起來(lái)的,這樣就可以控制貝塞爾曲線的點(diǎn)來(lái)讓圓抖動(dòng).見參考鏈接3
主體的大圓
Path畫法
主體的大圓是個(gè)ToggleButton,替換模版,背景換成貝塞爾曲線組成的圓.
每個(gè)貝塞爾曲線的起點(diǎn)和終點(diǎn)就不說(shuō)了,非常簡(jiǎn)單,這里主要說(shuō)說(shuō)控制點(diǎn).
計(jì)算出1/4圓弧的中間位置的點(diǎn),此時(shí)t=0.5, 三角型邊長(zhǎng)h=sin45*r
讓控制點(diǎn)P1,P2分別在起點(diǎn)和終點(diǎn)的切線上,P1到X軸的距離等于P2到Y(jié)軸的距離L
B(0.5)=h=sin45*r=(1-0.5)^3*0+3*(1-0.5)^2*0.5*L+3*(1-0.5)*0.5^2*r+0.5^3*r
sin45*r=0+0.375*L+0.375*r+0.125*r
L=(sin45*r-0.5*r)/0.375
于是兩個(gè)控制點(diǎn)(r,L)和(L,r)可以確定
求出來(lái)的兩個(gè)點(diǎn)是數(shù)學(xué)的坐標(biāo),要轉(zhuǎn)換成程序的坐標(biāo),對(duì)應(yīng)成4個(gè)象限,無(wú)非就是加減半徑,加減L,不細(xì)說(shuō)了
完整的path,取半徑是50,見代碼
<Path> <Path.Data> <PathGeometry> <PathFigure StartPoint="50,0"> <BezierSegment Point1="77.614237491541,0" Point2="100,22.385762508459" Point3="100,50"></BezierSegment> <BezierSegment Point1="100,77.614237491541" Point2="77.614237491541,100" Point3="50,100"></BezierSegment> <BezierSegment Point1="22.385762508459,100" Point2="0,77.614237491541" Point3="0,50"></BezierSegment> <BezierSegment Point1="0,22.385762508459" Point2="22.385762508459,0" Point3="50,0"></BezierSegment> </PathFigure> </PathGeometry> </Path.Data> </Path>
抖動(dòng)動(dòng)畫
由于圓是被12個(gè)點(diǎn)控制的,讓圓抖動(dòng),也就是對(duì)12個(gè)點(diǎn)做點(diǎn)動(dòng)畫
可以用關(guān)鍵幀動(dòng)畫,這樣控制的比較細(xì)致,要注意的是,銜接的地方要平滑.我這里做的比較簡(jiǎn)陋,就找了一個(gè)變換后的圖形,重復(fù)了5次.如果你有興趣,可以多做些,做的越多,動(dòng)畫看起來(lái)表現(xiàn)力越強(qiáng)
這里我并沒(méi)有去研究什么算法,就是簡(jiǎn)單的在blend里,找了一些點(diǎn)
見代碼:
<EventTrigger RoutedEvent="Click"> <BeginStoryboard> <Storyboard> <PointAnimationUsingKeyFrames Storyboard.TargetName="pf_main" Storyboard.TargetProperty="StartPoint" BeginTime="0:0:0.7" AutoReverse="True" RepeatBehavior="5x" FillBehavior="Stop"> <EasingPointKeyFrame Value="40,0" KeyTime="0:0:0.2"></EasingPointKeyFrame> </PointAnimationUsingKeyFrames> <PointAnimationUsingKeyFrames Storyboard.TargetName="bs_main0" Storyboard.TargetProperty="Point1" BeginTime="0:0:0.7" AutoReverse="True" RepeatBehavior="5x" FillBehavior="Stop"> <EasingPointKeyFrame Value="68,-10" KeyTime="0:0:0.2"></EasingPointKeyFrame> </PointAnimationUsingKeyFrames> <PointAnimationUsingKeyFrames Storyboard.TargetName="bs_main0" Storyboard.TargetProperty="Point2" BeginTime="0:0:0.7" AutoReverse="True" RepeatBehavior="5x" FillBehavior="Stop"> <EasingPointKeyFrame Value="115,14" KeyTime="0:0:0.2"></EasingPointKeyFrame> </PointAnimationUsingKeyFrames> <PointAnimationUsingKeyFrames Storyboard.TargetName="bs_main0" Storyboard.TargetProperty="Point3" BeginTime="0:0:0.7" AutoReverse="True" RepeatBehavior="5x" FillBehavior="Stop"> <EasingPointKeyFrame Value="100,66" KeyTime="0:0:0.2"></EasingPointKeyFrame> </PointAnimationUsingKeyFrames> <PointAnimationUsingKeyFrames Storyboard.TargetName="bs_main1" Storyboard.TargetProperty="Point1" BeginTime="0:0:0.7" AutoReverse="True" RepeatBehavior="5x" FillBehavior="Stop"> <EasingPointKeyFrame Value="100,67" KeyTime="0:0:0.2"></EasingPointKeyFrame> </PointAnimationUsingKeyFrames> <PointAnimationUsingKeyFrames Storyboard.TargetName="bs_main1" Storyboard.TargetProperty="Point2" BeginTime="0:0:0.7" AutoReverse="True" RepeatBehavior="5x" FillBehavior="Stop"> <EasingPointKeyFrame Value="85,111" KeyTime="0:0:0.2"></EasingPointKeyFrame> </PointAnimationUsingKeyFrames> <PointAnimationUsingKeyFrames Storyboard.TargetName="bs_main1" Storyboard.TargetProperty="Point3" BeginTime="0:0:0.7" AutoReverse="True" RepeatBehavior="5x" FillBehavior="Stop"> <EasingPointKeyFrame Value="33,103" KeyTime="0:0:0.2"></EasingPointKeyFrame> </PointAnimationUsingKeyFrames> <PointAnimationUsingKeyFrames Storyboard.TargetName="bs_main2" Storyboard.TargetProperty="Point1" BeginTime="0:0:0.7" AutoReverse="True" RepeatBehavior="5x" FillBehavior="Stop"> <EasingPointKeyFrame Value="22,103" KeyTime="0:0:0.2"></EasingPointKeyFrame> </PointAnimationUsingKeyFrames> <PointAnimationUsingKeyFrames Storyboard.TargetName="bs_main2" Storyboard.TargetProperty="Point2" BeginTime="0:0:0.7" AutoReverse="True" RepeatBehavior="5x" FillBehavior="Stop"> <EasingPointKeyFrame Value="-15,85" KeyTime="0:0:0.2"></EasingPointKeyFrame> </PointAnimationUsingKeyFrames> <PointAnimationUsingKeyFrames Storyboard.TargetName="bs_main2" Storyboard.TargetProperty="Point3" BeginTime="0:0:0.7" AutoReverse="True" RepeatBehavior="5x" FillBehavior="Stop"> <EasingPointKeyFrame Value="-6,50" KeyTime="0:0:0.2"></EasingPointKeyFrame> </PointAnimationUsingKeyFrames> <PointAnimationUsingKeyFrames Storyboard.TargetName="bs_main3" Storyboard.TargetProperty="Point1" BeginTime="0:0:0.7" AutoReverse="True" RepeatBehavior="5x" FillBehavior="Stop"> <EasingPointKeyFrame Value="4,9" KeyTime="0:0:0.2"></EasingPointKeyFrame> </PointAnimationUsingKeyFrames> <PointAnimationUsingKeyFrames Storyboard.TargetName="bs_main3" Storyboard.TargetProperty="Point2" BeginTime="0:0:0.7" AutoReverse="True" RepeatBehavior="5x" FillBehavior="Stop"> <EasingPointKeyFrame Value="41,-1" KeyTime="0:0:0.2"></EasingPointKeyFrame> </PointAnimationUsingKeyFrames> <PointAnimationUsingKeyFrames Storyboard.TargetName="bs_main3" Storyboard.TargetProperty="Point3" BeginTime="0:0:0.7" AutoReverse="True" RepeatBehavior="5x" FillBehavior="Stop"> <EasingPointKeyFrame Value="42,0" KeyTime="0:0:0.2"></EasingPointKeyFrame> </PointAnimationUsingKeyFrames> </Storyboard> </BeginStoryboard> </EventTrigger>
item
按鈕的位置
不管是奇數(shù)個(gè),還是偶數(shù)個(gè),我們都想讓它以Y軸對(duì)稱
首先把圓分成8等份,每一份都是45度,也就是最多只能放下8個(gè)item,
從上圖可以看出來(lái),其實(shí)就是奇數(shù)個(gè)在線上,偶數(shù)個(gè)在兩線之間
有個(gè)簡(jiǎn)單的辦法,就是先在頂點(diǎn)依次順時(shí)針排列,每個(gè)item間隔45度,然后再逆時(shí)針旋轉(zhuǎn),每多一個(gè)item就多轉(zhuǎn)45/2度(兩條分割線是45度,中間也就是45/2度),如下圖:
上圖是item終點(diǎn)的位置,起點(diǎn)的位置是在圓心.
動(dòng)畫用DoubleAnimation控制item按鈕的位移,從圓心移動(dòng)到計(jì)算后的位置
計(jì)算位置的代碼:
//函數(shù)是弧度制 2PI是360度 1 a = c * Math.Sin(2 * Math.PI / 8 * i - (itemsSource.Count - 1) * 2 * Math.PI / 8 / 2); 2 b = c * Math.Cos(2 * Math.PI / 8 * i - (itemsSource.Count - 1) * 2 * Math.PI / 8 / 2);
水球連接的部分
連接的部分是用兩個(gè)二次貝塞爾和一條直線做一個(gè)path
開始的時(shí)候,兩條貝塞爾曲線的高度是0,控制點(diǎn)在path所在矩形的邊上,然后對(duì)而塞爾曲線上面的點(diǎn)和控制點(diǎn)做動(dòng)畫,分別向上和內(nèi)移動(dòng),最終形成上圖右邊的圖形,然后把這個(gè)動(dòng)畫和item按鈕向外部移動(dòng)的動(dòng)畫結(jié)合起來(lái),就偽裝成了水球分離的效果.
上圖紅色矩形就是連接部分的path.動(dòng)畫的過(guò)程就是Item按鈕的直徑和大圓相交的時(shí)候開始和item按鈕一起做動(dòng)畫,最后移動(dòng)到Item按鈕直徑所在的位置,整個(gè)距離就是Item的半徑+item到主體的距離+藍(lán)色的d,而藍(lán)色的d可以通過(guò)公式求出
開始的時(shí)候也是讓連接部分path在圓心的位置.定位方法和定位Item按鈕的方法是完全一樣的.這里就不在重復(fù)了.只說(shuō)一下c邊的距離是:大圓和小圓圓心的距離-連接path高度的一半
源碼下載:WaterDropsButtonGroup(jb51.net).zip
以上這篇WPF水珠效果按鈕組的實(shí)現(xiàn)教程就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Asp.net GridView隔行變色和光棒效果2種方法實(shí)現(xiàn)
兩種方法實(shí)現(xiàn)GridView隔行變色和光棒效果:前臺(tái)和后臺(tái)配合使用及JQuery方式,感興趣的朋友可以參考下哈,希望可以幫助到你2013-04-04詳解ASP.NET Core 網(wǎng)站發(fā)布到Linux服務(wù)器
本篇文章主要介紹了ASP.NET Core 網(wǎng)站發(fā)布到Linux服務(wù)器 。具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-04-04ASP.NET自定義Web服務(wù)器控件之Button控件
這篇文章主要介紹了ASP.NET自定義Web服務(wù)器控件之Button控件,詳細(xì)講述了Button控件的實(shí)現(xiàn)代碼、前臺(tái)頁(yè)面的調(diào)用以及對(duì)應(yīng)的事件響應(yīng)代碼,具有很好的參考借鑒價(jià)值,需要的朋友可以參考下2014-11-11ASP.NET微信公眾號(hào)之用戶分組管理web頁(yè)面
這篇文章主要為大家詳細(xì)介紹了ASP.NET微信公眾號(hào)之用戶分組管理web頁(yè)面,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-11-11解析利用wsdl.exe生成webservice代理類的詳解
本篇文章是對(duì)利用wsdl.exe生成webservice代理類進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05.NET Core利用swagger進(jìn)行API接口文檔管理的方法詳解
這篇文章主要給大家介紹了關(guān)于.NET Core利用swagger進(jìn)行API接口文檔管理的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2018-03-03.NET?Core?Web?APi類庫(kù)內(nèi)嵌運(yùn)行的方法
這篇文章主要介紹了.NET?Core?Web?APi類庫(kù)內(nèi)嵌運(yùn)行的方法,本節(jié)我們重點(diǎn)討論如何內(nèi)嵌運(yùn)行.NET Core Web APi類庫(kù),同時(shí)介紹了兩種激活比如控制器特性方案,需要的朋友可以參考下2022-09-09.Net Core中使用ExceptionFilter過(guò)濾器的方法
這篇文章主要介紹了.Net Core中使用ExceptionFilter過(guò)濾器的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03在asp.net(C#)中采用自定義標(biāo)簽和XML、XSL顯示數(shù)據(jù)
在asp.net(C#)中采用自定義標(biāo)簽和XML、XSL顯示數(shù)據(jù)的實(shí)現(xiàn)代碼。2009-06-06