WPF 實現水珠效果按鈕組

本文經原作者授權以原創方式二次分享,歡迎轉載、分享。

原文作者:普通的地球人

原文地址:https://www.cnblogs.com/tsliwei/p/8041928.html

相關知識

這部分基本就是廢話,網上都能找到,我只不過是整理了以下.建議先不看,用到的時候可以回來看看

貝塞爾曲線

先來看兩組圖,有助于理解什么是貝塞爾曲線(圖片取自維基百科,參考鏈接)

二次貝塞爾曲線:

5e65c63e19961054a532960cf12eed4b.pngabe4904afdafc4d0d0e8b9ef354bf473.gif

P0是起點,P2是終點,P1是控制點

三次貝塞爾曲線:

a5c62b924dad7cdd4d593f3997ff8e63.png4f145da9cc27084b0f52c3a39e8cd0ed.gif

P0是起點,P3是終點,P1是控制點1,P2是控制點2

依次連接所有點,組成線段

t是比例,在0-1之間,就是每條線段的長度都是1

貝塞爾曲線就是最里層的線段在t位置的點所組成的路徑

三次貝塞爾曲線公式: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)代表曲線上任意點,P0,1,2,3分別代表決定曲線的4個點,t代表曲線長度為1的任意取值

其他知識

沒接觸過貝塞爾曲線的話,可能得花些時間整理下,其他的知識就比較簡單了

b28ea359e3dca4061893f3e10ec1e87e.png

直角三角形,角A的對邊a,臨邊b,斜邊c

三角函數:

sinA=a/c

cosA=b/c

勾股定理:

c^2=a^2+b^2

概括介紹

這個效果難點就兩部分:一是水球分離和融合時候的連接,二是主體圓的抖動

然而其實網上都有解決方案了

第一部分是在兩個圓之間加個用貝塞爾曲線組成的path,用一樣的顏色,其實是障眼法.見參考鏈接

第二部分是用4段三次貝塞爾曲線組成的path代替Ellipse,因為Ellipse是抖動不起來的,這樣就可以控制貝塞爾曲線的點來讓圓抖動.見參考鏈接

主體的大圓

Path畫法 主體的大圓是個ToggleButton,替換模版,背景換成貝塞爾曲線組成的圓.

每個貝塞爾曲線的起點和終點就不說了,非常簡單,這里主要說說控制點.

997172e68c2ff3ebf414229f16dd01ab.png

計算出1/4圓弧的中間位置的點,此時t=0.5, 三角型邊長h=sin45*r

讓控制點P1,P2分別在起點和終點的切線上,P1X軸的距離等于P2Y軸的距離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

于是兩個控制點(r,L)(L,r)可以確定

求出來的兩個點是數學的坐標,要轉換成程序的坐標,對應成4個象限,無非就是加減半徑,加減L,不細說了

完整的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>

抖動動畫

由于圓是被12個點控制的,讓圓抖動,也就是對12個點做點動畫

可以用關鍵幀動畫,這樣控制的比較細致,要注意的是,銜接的地方要平滑.我這里做的比較簡陋,就找了一個變換后的圖形,重復了5次.如果你有興趣,可以多做些,做的越多,動畫看起來表現力越強

這里我并沒有去研究什么算法,就是簡單的在blend里,找了一些點

見代碼:

<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按鈕的位置 不管是奇數個,還是偶數個,我們都想讓它以Y軸對稱

首先把圓分成8等份,每一份都是45度,也就是最多只能放下8item,

968b7efc5d85c314ee2fa10dd5abfccd.png從上圖可以看出來,其實就是奇數個在線上,偶數個在兩線之間

有個簡單的辦法,就是先在頂點依次順時針排列,每個item間隔45度,然后再逆時針旋轉,每多一個item就多轉45/2度(兩條分割線是45度,中間也就是45/2度),如下圖:

9d41ac8f9bca8f657fd144b034a11617.png上圖是item終點的位置,起點的位置是在圓心.

動畫用DoubleAnimation控制item按鈕的位移,從圓心移動到計算后的位置

計算位置的代碼:

//函數是弧度制?2PI是360度
a?=?c?*?Math.Sin(2?*?Math.PI?/?8?*?i?-?(itemsSource.Count?-?1)?*?2?*?Math.PI?/?8?/?2);
b?=?c?*?Math.Cos(2?*?Math.PI?/?8?*?i?-?(itemsSource.Count?-?1)?*?2?*?Math.PI?/?8?/?2);

水球連接的部分 連接的部分是用兩個二次貝塞爾和一條直線做一個path

c04fa7227de47485ef2e1520da156060.png

開始的時候,兩條貝塞爾曲線的高度是0,控制點在path所在矩形的邊上,然后對而塞爾曲線上面的點和控制點做動畫,分別向上和內移動,最終形成上圖右邊的圖形,然后把這個動畫和item按鈕向外部移動的動畫結合起來,就偽裝成了水球分離的效果.

ba01222b45a237832fe4246851518688.png上圖紅色矩形就是連接部分的path.動畫的過程就是Item按鈕的直徑和大圓相交的時候開始和item按鈕一起做動畫,最后移動到Item按鈕直徑所在的位置,整個距離就是Item的半徑+item到主體的距離+藍色的d,而藍色的d可以通過公式求出

開始的時候也是讓連接部分path在圓心的位置.定位方法和定位Item按鈕的方法是完全一樣的.這里就不在重復了.只說一下c邊的距離是:大圓和小圓圓心的距離-連接path高度的一半

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/286851.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/286851.shtml
英文地址,請注明出處:http://en.pswp.cn/news/286851.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

GetDisplayName 獲取枚舉的顯示值

item.State.GetDisplayName(), 轉載于:https://www.cnblogs.com/zhongku/p/4944315.html

組策略管理——軟件限制策略(4)

編寫軟件限制規則 在前面幾篇文章中講了軟件限制規則的基本概念&#xff0c;現在就來學習如何編寫自定義軟件限制策略。 編寫規則應遵循的原則 首先&#xff0c;需要大家注意的是&#xff0c;軟件限制策略應本著方便、安全、實用的原則來編寫。限制規則靈活方便&#xff0c;自定…

我使用 html 反向輸出自己打自己(7)

作者簡介 作者名&#xff1a;1_bit 簡介&#xff1a;CSDN博客專家&#xff0c;2020年博客之星TOP5&#xff0c;藍橋簽約作者。15-16年曾在網上直播&#xff0c;帶領一批程序小白走上程序員之路。歡迎各位小白加我咨詢我相關信息&#xff0c;迷茫的你會找到答案。 目錄 HTML基…

甘肅省普通高等學校高職(專科)升本科考試英語科考試大綱(試行)

甘肅省普通高等學校高職&#xff08;專科&#xff09;升本科考試英語科考試大綱&#xff08;試行&#xff09; 一、考試目的 全面考核普通高等學校高職&#xff08;專科&#xff09;應屆畢業生英語課程是否達到教學大綱所規定的目標&#xff08;領會式掌握3500單詞&#xff0c…

256種編程語言大薈萃

本文是碼農網原創翻譯&#xff0c;轉載請看清文末的轉載要求&#xff0c;謝謝合作&#xff01; 雙休日常常意味著很多休息時間。與其懶洋洋地坐在那里玩游戲&#xff0c;為何不學點新知識武裝自己&#xff1f;本文中不會特定推薦哪種編程語言&#xff0c;但是會提供基于GitHub上…

java 獲取系統當前時間

Calendar ca Calendar.getInstance(); int year ca.get(Calendar.YEAR);//獲取年份 int monthca.get(Calendar.MONTH);//獲取月份 int dayca.get(Calendar.DATE);//獲取日 int minuteca.get(Calendar.MINUTE);//分 int hourca.get(Calendar.HOUR)…

Android之最簡單的遍歷某個目錄下的所有文件(遞歸)

1、問題 遍歷某個目錄下的所有問題文件 2、代碼實現 fun getRecoverTrashFile(path: String) {if (TextUtils.isEmpty(path))returntry {var file File(path)if (file null || !file.exists()) {return}var files file.listFiles()if (files null || files.size < 0) {…

Castle.DynamicProxy攔截器

在asp.net mvc或asp.net miniapi中&#xff0c;有過濾器&#xff0c;可以在請求前或后增加一層&#xff0c;達到驗證&#xff0c;過濾等作用&#xff0c;如果在Service的方法前后加一層呢&#xff1f;這里介紹一下Castle.DynamicProxy的用法。首先引入Castle.Core實現代碼相對輕…

甘肅省普通高等學校高職(專科)升本科考試計算機科考試大綱(試行)

甘肅省普通高等學校高職&#xff08;專科&#xff09;升本科考試計算機科考試大綱&#xff08;試行&#xff09; 一、考試目的及要求 全面考核普通高等學校高職&#xff08;專科&#xff09;應屆畢業生計算機應用能力是否達到教學大綱所規定的要求。所有考生計算機基礎知識必須…

Android選項切換條SHSegmentControl

&#xfeff;&#xfeff;Android選項切換條SHSegmentControl SHSegmentControl是github上一個開源的選項切換條&#xff0c;其樣式如圖所示&#xff1a; SHSegmentControl在github上的項目主頁地址&#xff1a;https://github.com/7heaven/SHSegmentControl SHSegmentControl…

從零開始編寫自己的C#框架(14)——T4模板在邏輯層中的應用(三)

原本關于T4模板原想分5個章節詳細解說的&#xff0c;不過因為最近比較忙&#xff0c;也不想將整個系列時間拉得太長&#xff0c;所以就將它們整合在一塊了&#xff0c;可能會有很多細節沒有講到&#xff0c;希望大家自己對著代碼與模板去研究。 本章代碼量會比較大&#xff0c;…

趕緊3分鐘學完15分鐘的內容我要出去玩(8)

作者簡介 作者名&#xff1a;1_bit 簡介&#xff1a;CSDN博客專家&#xff0c;2020年博客之星TOP5&#xff0c;藍橋簽約作者。15-16年曾在網上直播&#xff0c;帶領一批程序小白走上程序員之路。歡迎各位小白加我咨詢我相關信息&#xff0c;迷茫的你會找到答案。 目錄 HTML基…

Android之獲取到音視頻的時長后按格式(00:00或者00:00:00)顯示

1 需求 我們獲取到了本地視頻時長(秒為單位),然后需要按照如下格式顯示 沒有到小時的時長如下格式 00:00 有到小時的時長如下格式 00:00:00 2 代碼實現 /*** 可以顯示小時*/fun getDateStr(ms: Long): String? {val ss = 1val mi = ss * 60val hh = mi * 60val dd = …

Hello Playwright:(5)查找元素

操作瀏覽器歸根到底就是和頁面進行交互&#xff0c;那么必不可少的操作就是查找頁面上的元素。因此我們需要熟練掌握Locator 定位器。在上一節我們講過&#xff0c;可以使用Page.Locator(selector, options)方法創建定位器&#xff0c;而如何定位到元素則取決于selector 選擇器…

RxSwift 之官方文檔

RxSwift 官方文檔結構 Introduction:SubjectsTransforming ObservablesFiltering ObservablesCombining ObservablesError Handing OperatorsObservable Utility OperatorsConditional and Boolean OperatorsMathematical and Aggregate OperatorsConnectable Observable Opera…

SQL一鍵備份用戶數據庫

大家都知道&#xff0c;Ms Sql 有自動備份的功能&#xff0c;但如果由于某種原因不能自動備份&#xff0c;或者我們想手動備份的話&#xff0c;就可以用下邊的sql語句來執行備份。 --------------------代碼開始------------- USE [master]------刪除舊數據-------------------…

2019年甘肅省普通高等學校高職(專科)升本科考試招生工作實施辦法

2019年甘肅省普通高等學校高職&#xff08;專科&#xff09;升本科考試招生工作實施辦法 2019年甘肅省普通高等學校高職&#xff08;專科&#xff09;升本科考試招生工作實施辦法 根據教育部有關規定及要求&#xff0c;結合我省實際&#xff0c;為確保普通高等學校高職&#x…

HTML基礎之bit哥的反客為主之道(9)

作者簡介 作者名&#xff1a;1_bit 簡介&#xff1a;CSDN博客專家&#xff0c;2020年博客之星TOP5&#xff0c;藍橋簽約作者。15-16年曾在網上直播&#xff0c;帶領一批程序小白走上程序員之路。歡迎各位小白加我咨詢我相關信息&#xff0c;迷茫的你會找到答案。 目錄 HTML基…

Atom編輯Markdown文件保存后行尾的空格自動消失的問題解決

Markdown文件的行尾增加兩個空格表示一行結束需要換行。 但保存文件后&#xff0c;行尾的空格自動消失&#xff0c;導致不換行。 解決方法&#xff1a; 1、【Edit】->【Preferences】->【Packages】->【whitespace】->【Settings】->【Keep Markdown Line Brea…

將Abp移植進.NET MAUI項目

前言寫在.NET MAUI官宣正式發布之際&#xff0c;熱烈慶祝MAUI正式發布&#xff01;去年12月份做了MAUI混合開發框架的調研&#xff0c;想起來文章里給自己挖了個坑&#xff0c;要教大家如何把Abp移植進Maui項目。熟悉Abp的同學都知道&#xff0c;Abp 是一套強大的應用程序設計時…