在UWP UI系統中,使用Shape是繪製2D圖形最簡單的方式,小到圖標,大到圖表都用到Shape的派生類,可以說有舉足輕重的地位。幸運的是從Silverlight以來Shape基本沒有什麼大改動,簡直是UWP中的一股清流。
上圖來自Pro Silverlight 5 in C#,可見Silverlight中的Shape和UWP的Shape基本架構一致。Shape的API從WPF以來就幾乎沒變,對熟悉WPF/Silverlight的開發者來說幾乎是零學習成本。
1. Ellipse(圓形)
Ellipse沒有在Shape的基礎上增加任何屬性,是Shape的派生類中最簡單的一個。
1.1 Fill、Stroke與StrokeThickness
public Brush Fill { get; set; }
、public Brush Stroke { get; set; }
與public System.Double StrokeThickness { get; set; }
是Shape中最常用的三個屬性,分別用於設置Shape的填充顏色、邊框顏色、邊框寬度。改變StrokeThickness並不會改變形狀的大小。
<Ellipse Height="100" Width="100" Fill="#FF7E9EC0" Stroke="#FFFF0EC4" StrokeThickness="5" Margin="10" />
1.2 Stretch
public Stretch Stretch { get; set; }
用於確定形狀如何填充可用的區域。Stretch的所有枚舉值如下:
None: 形狀不被拉伸。
Fill: 形狀拉伸其寬度和高度,從而可以正好適應其容器。
Uniform: 按比例改變形狀的寬度和高度,直至形狀到達容器板邊緣。
UniformToFill: 按比例改變形狀的寬度和高度,直到形狀填滿了整個可用控件的高度和寬度。
效果如下
<StackPanel Orientation="Horizontal"> <Ellipse Fill="#FF7E9EC0" Stroke="#FFFF0EC4" StrokeThickness="5" Height="50" Width="100" Stretch="Fill" /> <Ellipse Fill="#FF7E9EC0" Stroke="#FFFF0EC4" StrokeThickness="5" Height="50" Width="100" Stretch="None" /> <Ellipse Fill="#FF7E9EC0" Stroke="#FFFF0EC4" StrokeThickness="5" Height="50" Width="100" Stretch="Uniform" /> <Ellipse Fill="#FF7E9EC0" Stroke="#FFFF0EC4" StrokeThickness="5" Height="50" Width="100" Stretch="UniformToFill" /> </StackPanel>
1.3 StrokeDashArray
public DoubleCollection StrokeDashArray { get; set; }用於將邊框變成虛線。StrokeDashArray的值是一個double類型的有序集合,集合中的值指虛線中每一段的長度,長度單位是邊框值的寬度。例如以下圓形:
<Ellipse StrokeDashArray="1,2,3" Stroke="#FFFF0EC4" StrokeThickness="10" Height="200" Width="200" />
邊框寬度爲10,虛線的第一段是長度爲10的實線,第二段爲長度爲20的空白,第三段爲長度爲30的實線,然後如此循環直到結束。
自從開始WPF工作以來,我一直將StrokeDashArray的值設爲一個好看又好記的值:4 2,the answer to life, the universe, and everything。
<Ellipse StrokeDashArray="4 2" Stroke="#FFFF0EC4" StrokeThickness="3" Height="200" Width="200" />
1.4 StrokeDashCap
public PenLineCap StrokeDashCap { get; set; }
表示虛線中實線兩端的邊緣輪廓。PenLineCap的枚舉值如下:
Flat: 一個未超出直線上最後一點的線帽。 等同於無線帽。
Square: 一個高度等於直線粗細、長度等於直線粗細一半的矩形。
Round: 一個直徑等於直線粗細的半圓形。
Triangle: 一個底邊長度等於直線粗細的等腰直角三角形。
<Grid Margin="10,10" Width="200" Height="10" Background="Gray"> <Line Stretch="Fill" Stroke="Red" StrokeThickness="10.5" X2="1" StrokeEndLineCap="Flat" /> </Grid> <TextBlock Text="Flat" Grid.Column="1" VerticalAlignment="Center" /> <Grid Width="200" Margin="10,10" Height="10" Background="Gray" Grid.Row="1"> <Line Stretch="Fill" Stroke="Red" StrokeThickness="10" X2="1" StrokeEndLineCap="Round" /> </Grid> <TextBlock Text="Round" Grid.Row="1" Grid.Column="1" VerticalAlignment="Center" /> <Grid Width="200" Margin="10,10" Height="10" Background="Gray" Grid.Row="2"> <Line Stretch="Fill" Stroke="Red" StrokeThickness="10" X2="1" StrokeEndLineCap="Square" /> </Grid> <TextBlock Text="Square" Grid.Row="2" Grid.Column="1" VerticalAlignment="Center" /> <Grid Width="200" Margin="10,10" Height="10" Background="Gray" Grid.Row="3"> <Line Stretch="Fill" Stroke="Red" StrokeThickness="10" X2="1" StrokeEndLineCap="Triangle" /> </Grid> <TextBlock Text="Triangle" Grid.Row="3" Grid.Column="1" VerticalAlignment="Center" />
1.5 StrokeDashOffset
public System.Double StrokeDashOffset { get; set; }用於指定虛線開始的位置。
2. Rectangle(矩形)
Rectangle 只比Shape多了RadiusX和RadiusY兩個屬性。
2.1 RadiusX和RadiusY
public System.Double RadiusX { get; set; }和public System.Double RadiusY { get; set; }分別用於指定用於使矩形的角變圓的橢圓的x軸和 y軸半徑。
如下面這個例子,可以看到 RadiusX="50" RadiusY="20"
的Rectangle的圓角和Width="100" Height="40"
的Ellipse(x軸半徑50,y軸半徑20)完全重合在一起。
<Rectangle Height="100" Width="100" Fill="#FF7E9EC0" Stroke="#FFFF0EC4" StrokeThickness="5" RadiusX="50" RadiusY="20" /> <Ellipse HorizontalAlignment="Left" VerticalAlignment="Top" StrokeThickness="5" Stroke="Yellow" Fill="Red" Width="100" Height="40" Opacity="0.5" />
2.2 StrokeLineJoin和StrokeMiterLimit
public PenLineJoin StrokeLineJoin { get; set; }
和public System.Double StrokeMiterLimit { get; set; }
確定形狀拐角處的形狀。這兩個屬性都是Shape的屬性,但對Ellipse和Line這兩個沒有拐角的形狀不起作用。
3. Line(直線)
Line表示從第一個點(X1,Y1)到第二個點(X2,Y2)的一條直線。
3.1 X1,Y1,X2,Y2
這四個屬性確定了Line的起點和終點。
除了使用絕對值定位Line的位置,還可以使用相對定位。
<Line Stretch="Fill" X1="0" X2="1" StrokeDashArray="4 2" Stroke="BlueViolet" StrokeThickness="1" />
3.2 StrokeStartLineCap與StrokeEndLineCap
public PenLineCap StrokeStartLineCap { get; set; }
和public PenLineCap StrokeEndLineCap { get; set; }
決定直線開始端和結束端的輪廓。這兩個屬性都是Shape的屬性,但隻影響Line、Polyline和Path,對Rectangle這類沒有開始和結束端的形狀沒有影響。
4. Polygon(多邊形)和Polyline(折線)
這兩個形狀具有相同的屬性,外觀也相似。區別只是如果Points的最後一個點和第一個點不一樣,Polygon會自動將這兩個點連接到一起。
4.1 Points
public PointCollection Points { get; set; }
用於設置Polygon和Polyline的頂點。
<Polygon Points="15,200 68,70 110,200 0,125 135,125" Fill="Red" Stroke="Blue" StrokeThickness="4" Stretch="Fill" Height="100" Width="100" /> <Polyline Points="15,200 68,70 110,200 0,125 135,125" Fill="Red" Stroke="Blue" StrokeThickness="4" Stretch="Fill" Height="100" Width="100" Margin="20,0,0,0" />
4.2 FillRule
public FillRule FillRule { get; set; }
指定如何確定形狀的內部填充。默認值是EvenOdd,如果設置成Nonzero,效果如下:
5 Path(路徑)
Path是功能最強大的形狀,它基本上由上面的其它形狀組成並且可以替代它們中的任何一個。只是Path使用起來也比較複雜,只有在圖表和少量場景用到,很多時候比起構造複雜的Path還不如用直接用圖片。
5.1 Data
public Geometry Data { get; set; }
屬性指定要繪製形狀的Geometry。Geometry 定義幾何圖形並且定義了座標和尺寸等細節 ,由Path繪製到屏幕。UWP中的Geometry包含以下幾個:
EllipseGeometry: 表示圓或橢圓的幾何圖形。
LineGeometry: 表示線條的幾何圖形。
PathGeometry: 表示一個可能由弧、曲線、橢圓、直線和矩形組成的基於矢量的複雜形狀。
RectangleGeometry: 描述二維矩形這一幾何圖形。
除此之外,還可以使用由多個Geometry組成的GeometryGroup構造組合形狀。
5.2 PathGeometry
在所有Geometry中PathGeometry是功能最強大的,唯一的缺點是太多複雜。它使用public PathFigureCollection Figures { get; set; }
描述包含的圖形內容,PathFigure由PathSegment的派生類描述,包括:
ArcSegment: 表示兩點之間的一條橢圓弧。
BezierSegment: 表示在兩個點之間繪製的一條三次貝塞爾曲線。
LineSegment: 表示在兩個點之間繪製的一條線,它可能是 PathFigure 在 Path 數據內的一部分。
PolyBezierSegment: 表示一條或多條三次方貝塞爾曲線。
PolyLineSegment: 表示由 Point 集合定義的一組線段,每個 Point 指定一個線段的終點。
PolyQuadraticBezierSegment: 表示一系列二次貝塞爾線段。
QuadraticBezierSegment: 在 PathFigure 中的兩點之間創建二次貝塞爾曲線。
下面是一個Path的官方示例,同時使用了各種Geometry及部分PathSegment:
<Path Stroke="Black" Margin="10" StrokeThickness="1" Fill="#CCCCFF"> <Path.Data> <GeometryGroup> <RectangleGeometry Rect="50,5 100,10" /> <RectangleGeometry Rect="5,5 95,180" /> <EllipseGeometry Center="100, 100" RadiusX="20" RadiusY="30" /> <RectangleGeometry Rect="50,175 100,10" /> <PathGeometry> <PathGeometry.Figures> <PathFigureCollection> <PathFigure IsClosed="true" StartPoint="50,50"> <PathFigure.Segments> <PathSegmentCollection> <BezierSegment Point1="75,300" Point2="125,100" Point3="150,50" /> <BezierSegment Point1="125,300" Point2="75,100" Point3="50,50" /> </PathSegmentCollection> </PathFigure.Segments> </PathFigure> </PathFigureCollection> </PathGeometry.Figures> </PathGeometry> </GeometryGroup> </Path.Data> </Path>
5.3 圖形微語言(geometry mini-language)
Path的XAML雖然具備很高的可讀性,但在存儲上不具優勢。所以UWP提供了一種替代語法:圖形微語言。圖形微語言使用一組簡單的字符串描述Path的圖形,一般來說不需要學習它的語法,因爲通常它是由工具生成的。
<Path Stroke="DarkGoldenRod" StrokeThickness="3" Data="M 100,200 C 100,25 400,350 400,175 H 280" />
5.4 使用Blend
通常用一個Path代替多個Shape不止更好管理,用戶界面的性能也會更好。Blend裏面提供了針對Shape的功能,可以對多個Shape進行合併或轉換爲路勁。
6. Shape各項屬性比較
下面表格列出了Shape的各項屬性,標記爲“×”的屬性代碼這個屬性對這個形狀無效。
7. ViewBox
ViewBox是拉伸或縮放單個子元素的容器,最常用來搭配Shape(或文字)使用,因爲Shape是矢量圖形,放大後不會失真。
ViewBox有以下三個屬性:
Child: 獲取或設置 Viewbox 元素的單一子元素。
Stretch: 獲取或設置確定內容如何適合可用空間的 Stretch 模式。
StretchDirection: 獲取或設置確定縮放如何應用於 Viewbox 內容的 StretchDirection。
<StackPanel Orientation="Horizontal"> <Canvas Width="30" Height="30"> <Rectangle Stroke="Red" StrokeThickness="1" Height="20" Width="20" /> <Rectangle Stroke="Green" StrokeThickness="1" Height="20" Width="20" Canvas.Left="10" Canvas.Top="10" /> </Canvas> <Viewbox Height="100" Width="100" Margin="30,0,0,0" Stretch="Uniform"> <Canvas Height="30" Width="30"> <Rectangle Stroke="Red" StrokeThickness="1" Height="20" Width="20" /> <Rectangle Stroke="Green" StrokeThickness="1" Height="20" Width="20" Canvas.Left="10" Canvas.Top="10" /> </Canvas> </Viewbox> </StackPanel>
8. 結語
系統地學過Shape相關知識只在很多年前剛開始學WPF/Silverlight時做過,平時除了Rectangle和Line其他的Shape好少會用到,所以即使有多年經驗對Shape的很多知識點還是有點陌生,這次趁學習UWP的機會複習一下。
但因爲很多知識點平時就很少會用到,後面越寫越膩味。