1. 需求
前天看到有人問弧形進度條怎么做,我模仿了一下,成果如下圖所示:

當時我第一反應是可以用 Microsoft.Toolkit.Uwp.UI.Controls 里的 RadialGauge 實作,雖然這是個 UWP 的控制元件,不過代碼沒有很復雜,應該很輕松就能移植到 WPF:

但仔細想想,我實作過很多次圓形的進度條,這種弧形的進度條則沒碰過,原型進度潭訓本只需要用 Ellipse 就能實作,而且只需要 Progress 一個引數,而弧形進度條則還需要 StartAngle 和 EndAngle 兩個屬性,而且計算復雜許多,于是興致來了試試用不同的方式實作弧形進度條,
這篇文章只介紹了怎么顯示弧形及怎么顯示進度,只有原理,沒有具體實作一個弧形進度條控制元件,
2. 使用 Path 及 ArcSegment
Path 用于繪制曲線和復雜形狀,而且 ArcSegment 用于描述 Path 中兩點之間的一條橢圓弧,通常使用以下幾個屬性控制 ArcSegment:
| 屬性 | 描述 |
|---|---|
| Point | 終點(起始點在 Path 或前一個 Segment 中描述), |
| Size | X 軸和 Y 軸的半徑, |
| IsLargeArc | 圓弧是整個圓形中大的那部分,還是小的那部分, |
| SweepDirection | 弧線繪制的方向, |

具體說明可以看 這個檔案,
用 Path 和 ArcSegment 可以很好地實作弧形的進度條,它的 XAML 如下:
<Path Stroke="SlateBlue"
StrokeThickness="4">
<Path.Data>
<PathGeometry>
<PathFigure IsClosed="False" StartPoint="30,170">
<ArcSegment IsLargeArc="True"
Point="170,170"
Size="96,96"
SweepDirection="Clockwise" />
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
疊加兩個不同顏色的 Path,就可以實作這種效果:

Path 和 ArcSegment 是一個很正統的方案,前面提到的 RadialGauge 就用了這個方案,不過它的計算很麻煩,三角函式我已經忘光了,
另外,請注意弧線兩端都是平平的直角,這和需求不符,所以需要設定 StrokeStartLineCap 和 StrokeEndLineCap 這兩個屬性的值為 Round:
StrokeStartLineCap="Round" StrokeEndLineCap="Round"
它們控制線條兩端邊緣的輪廓,Round 表示一個直徑等于線條粗細的半圓形,這樣才能實作需求中的圓角:

順便一提,這兩個屬性的型別是 PenLineCap 列舉,這個列舉的四個值分別代表以下幾種形狀:

3. 使用 Arc
第二個方案是使用 Microsoft.Expression.Drawing 中的 Arc 形狀直接畫出一個弧形,如果安裝了舊版的 Blend(好像 2017 或以前的都可以),可以在 資產->形狀 里找到這個形狀(我裝的是英文版所以沒有中文截圖):

或者在 Nuget 上搜索 Microsoft.Expression.Drawing 找到一個符合自己專案的版本,
Arc 的用法很簡單,只需要執行 StartAngle 和 EndAngle 即可輸出一個弧形:
<ed:Arc ArcThickness="12"
ArcThicknessUnit="Pixel"
EndAngle="150"
Fill="#101a26"
StartAngle="-150"
Stretch="None"
StrokeEndLineCap="Round"
StrokeStartLineCap="Round" />
疊加兩個不同顏色的 Arc,可以實作這種效果:

可是仔細看,就算用了 StrokeStartLineCap 和 StrokeEndLineCap 兩個屬性,Arc 的兩端任然是直角,這不符合需求,所以這個方案簡單但不完美,我還要嘗試下一個方案,
4. 使用 Ellipse
這個方案還算有趣,Ellipse 明明是圓形,卻能用來畫弧形,為了用 Ellipse 顯示進度,我們會用 StrokeDashArray 控制它的邊框長度,StrokeDashArray 用于將邊框變成虛線,它的值是一個 double 型別的有序集合,集合中的值指虛線中每一段的長度,長度單位是邊框值的寬度,例如以下圓形:
<Ellipse StrokeDashArray="1,2,3"
Stroke="#FFFF0EC4"
StrokeThickness="10"
Height="200"
/>

邊框寬度為 10,虛線的第一段是長度為 10 的實線,第二段為長度為 20 的空白,第三段為長度為 30 的實線,然后如此回圈直到結束,
用 StrokeDashArray 做進度提示的基本做法就是將進度(Progress)通過 Converter 轉換為分成兩段的 StrokeDashArray,第一段為實線,表示當前進度,第二段為空白,假設一個 Shape 的邊長是 100,當前進度為 50,則將 StrokeDashArray 設定成 {50,double.MaxValue} 兩段,
為了實作弧形進度條,我們還需要控制 Ellipse 旋轉的角度,具體來說我實作了一個 EllipseProgressBehavior,里面有 Progress、StartAngle 和 EndAngle 三個屬性,具體代碼在 這里,用這個 Behavior 控制 Ellipse 的邊框長度和旋轉角度,使用方式如下:
<Ellipse Margin="4"
Stroke="#7bcdd9"
StrokeThickness="4">
<interactivity:Interaction.Behaviors>
<local1:EllipseProgressBehavior EndAngle="150"
Progress="50"
StartAngle="-150" />
</interactivity:Interaction.Behaviors>
</Ellipse>
疊加兩個 Ellipse,即可實作需求中的弧形進度條,可是這時候弧形的兩端都是直角,即使設定了 StrokeStartLineCap 和 StrokeEndLineCap 兩個屬性都不起作用,對于用 StrokeDashArray 顯示的邊框,不能使用 StrokeStartLineCap 和 StrokeEndLineCap 去控制它的兩端的輪廓,而應該使用 StrokeDashCap:
StrokeDashCap="Round"
最終通過疊加兩個 Ellipse 實作了戶型進度條的需求:

5. 最后
童話和寓言都喜歡把相似的內容說上三次,例如三只小豬,三顧茅廬,弗利薩的三段變身,所以不是我在研究回字有多少種寫法,我只是遵循古法想把一種技術講透而已,
6. 參考
ArcSegment 類
幾何圖形
WPF 中的形狀和基本圖形概述
實用的Shape指南
7. 原始碼
- https://github.com/DinoChan/wpf_design_and_animation_lab
作者:dino.c
出處:http://www.cnblogs.com/dino623/
說明:歡迎轉載并請標明來源和作者,如有錯漏請指出,謝謝,
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/346829.html
標籤:.NET技术
上一篇:產品型公司的“偽產品”?
