[WP8.1UI控件编程]Windows Phone自定义布局规则
3.2 自定義布局規則
??? 上一節介紹了Windows Phone的系統布局面板和布局系統的相關原理,那么系統的布局面板并不一定會滿足所有的你想要實現的布局規律,如果有一些特殊的布局規律,系統的布局面板是不支持,這時候就需要去自定義實現一個布局面板,在自定義的布局面板里面封裝布局規律的邏輯。那么我們這一節從一個實際的需求出發,來實現一個自定義規律的布局面板。我們這一小節要實現的布局規律是把布局面板里面的子元素,按照圓形的排列規則進行排列,下面我們來看下這個例子的詳細實現過程。
3.2.1 創建布局類
??? 在Windows Phone要實現類似Grid、StackPanel的自定義布局規則的面板,首先要做的事情是要創建一個自定義的布局類。所有的布局面板都需要從Panel類派生,自定義實現其測量和排列的過程。Panel類中的Children屬性表示是布局面板里面的子對象,測量和排列的過程中需要根據Children屬性來獲取面板中所有的子對象,然后再根據相關的規律對這些子對象進行測量和排列。
??? 如果我們的布局類需要外面傳遞進來一些特殊的參數,那么就需要我們在布局類里面去實現相關的屬性。當然像Heigh、Width等這些Panel類原本就支持的屬性我們就無需再去定義,如我們在這個例子里面要實現的圓形布局,這時候是需要一個圓形的半徑大小的,這個半徑的大小就可以作為一個屬性讓外面把數值傳遞進來,然后布局類再根據這個半徑的大小來進行處理對子對象的測量和排列。需要注意的是,自定義的半徑屬性發生改變的時候,需要調用InvalidateArrange方法重新觸發布局的排列過程,否則修改半徑后將不會起到任何作用。
代碼清單3-2:自定義布局規則(源代碼:第3章\Examples_3_2)
??? 下面我們來看一下,自定義的CirclePanel類:
????public?class?CirclePanel?:?Panel{????????//自定義的半徑變量private?double?_radius?=?0;????????public?CirclePanel(){}????????//注冊半徑依賴屬性????????//"Radius"?表示半徑屬性的名稱????????//?typeof(double)?表示半徑屬性的類型????????//?typeof(CirclePanel)?表示半徑屬性的歸屬者類型????????//?new?PropertyMetadata(0.0,?OnRadiusPropertyChanged))?表示半徑屬性的元數據實例,0.0是默認值,OnRadiusPropertyChanged是屬性改變的事件public?static?readonly?DependencyProperty?RadiusProperty?=?DependencyProperty.RegisterAttached("Radius",????????????typeof(double),?typeof(CirclePanel),????????????new?PropertyMetadata(0.0,?OnRadiusPropertyChanged));????????//定義半徑屬性public?double?Radius{????????????get?{?return?(double)GetValue(RadiusProperty);?}????????????set?{?SetValue(RadiusProperty,?value);?}}????????//實現半徑屬性改變事件private?static?void?OnRadiusPropertyChanged(DependencyObject?obj,?DependencyPropertyChangedEventArgs?e){????????????//獲取觸發屬性改變的CirclePanel對象CirclePanel?target?=?(CirclePanel)obj;????????????//獲取傳遞進來的最新的值,并賦值給半徑變量target._radius?=?(double)e.NewValue;????????????//使排列狀態失效,進行重新排列????????????target.InvalidateArrange();}????????//重載基類的MeasureOverride方法protected?override?Size?MeasureOverride(Size?availableSize){????????????//處理測量子對象的邏輯return?availableSize;}????????//重載基類的ArrangeOverride方法protected?override?Size?ArrangeOverride(Size?finalSize){????????????//處理排列子對象的邏輯return?finalSize;}}3.2.2 實現測量過程
??? 測量的過程是在重載的MeasureOverride方法上實現,在MeasureOverride方法上需要做的第一件事情就是要把所有的子對象都遍歷一次,調用其Measure方法來測量子對象的大小。然后在測量的過程中可以獲取到子對象測量出來的寬度高度,我們可以根據這些信息來給自定義的面板分配其大小。
????protected?override?Size?MeasureOverride(Size?availableSize){????????//最大的寬度的變量double?maxElementWidth?=?0;????????//遍歷所有的子對象,并調用子對象的Measure方法進行測量,取出最大的寬度的子對象foreach?(UIElement?child?in?Children){????????????//測量子對象????????????child.Measure(availableSize);maxElementWidth?=?Math.Max(child.DesiredSize.Width,?maxElementWidth);}????????//兩個半徑的大小和最大的寬度的兩倍最為面板的寬度double?panelWidth?=?2?*?this.Radius?+?2?*?maxElementWidth;????????//取面板的所分配的高度寬度和計算出來的寬度的最小值最為面板的實際大小double?width?=?Math.Min(panelWidth,?availableSize.Width);????????double?heigh?=?Math.Min(panelWidth,?availableSize.Height);????????return?new?Size(width,?heigh);}3.2.3 實現排列過程
??? 排列的過程是在重載的ArrangeOverride方法上實現,在ArrangeOverride方法上通過相關的規則把子對象一一地進行排列。我們在例子里面要實現的是把子對象按照一個固定的圓形進行排列,所以在ArrangeOverride方法上需要計算每個子對象所占的角度大小,通過角度計算子對象在面板中的坐標,然后按照一定的角度對子對象進行旋轉來適應圓形的布局。排列原理圖如圖3.7所示,實現代碼如下。
????protected?override?Size?ArrangeOverride(Size?finalSize){????????//當前的角度,從0開始排列double?degree?=?0;????????//計算每個子對象所占用的角度大小double?degreeStep?=?(double)360?/?this.Children.Count;????????//計算double?mX?=?this.DesiredSize.Width?/?2;????????double?mY?=?this.DesiredSize.Height?/?2;????????//遍歷所有的子對象進行排列foreach?(UIElement?child?in?Children){????????????//把角度轉換為弧度單位double?angle?=?Math.PI?*?degree?/?180.0;????????????//根據弧度計算出圓弧上的x,y的坐標值double?x?=?Math.Cos(angle)?*?this._radius;????????????double?y?=?Math.Sin(angle)?*?this._radius;????????????//使用變換效果讓控件旋轉角度degreeRotateTransform?rotateTransform?=?new?RotateTransform();rotateTransform.Angle?=?degree;rotateTransform.CenterX?=?0;rotateTransform.CenterY?=?0;child.RenderTransform?=?rotateTransform;????????????//排列子對象child.Arrange(new?Rect(mX?+?x,?mY?+?y,?child.DesiredSize.Width,?child.DesiredSize.Height));????????????//角度遞增degree?+=?degreeStep;}????????return?finalSize;}3.2.4 應用布局規則
??? 在上面我們已經把自定義的圓形布局控件實現了,現在要在XAML頁面上應用該布局面板來進行布局。在這個例子里面,我們還通過一個Slider控件來動態改變布局面板的半徑大小,來觀察布局的變化。
??? 首先我們在XAML頁面上引入布局面板所在的空間,如下所示:
??? xmlns:local="clr-namespace:CustomPanelDemo"
??? 然后在XAML頁面上運用自定義的圓形布局控件,并且通過Slider控件的ValueChanged來動態給圓形布局控件的半徑賦值。代碼如下:
MainPage.xaml文件主要代碼------------------------------------------------------------------------------------------------------------------<Grid?x:Name="ContentPanel"?Grid.Row="1"?Margin="12,0,12,0"><Grid.RowDefinitions><RowDefinition?Height="Auto"/><RowDefinition?Height="Auto"/></Grid.RowDefinitions><Slider?Grid.Row="0"?Value="5"?ValueChanged="Slider_ValueChanged_1"></Slider><local:CirclePanel?x:Name="circlePanel"?Radius="50"?Grid.Row="1"??HorizontalAlignment="Center"?VerticalAlignment="Center"><TextBlock>Start?here</TextBlock><TextBlock>TextBlock?1</TextBlock><TextBlock>TextBlock?2</TextBlock><TextBlock>TextBlock?3</TextBlock><TextBlock>TextBlock?4</TextBlock><TextBlock>TextBlock?5</TextBlock><TextBlock>TextBlock?6</TextBlock><TextBlock>TextBlock?7</TextBlock></local:CirclePanel></Grid> MainPage.xaml.cs文件主要代碼------------------------------------------------------------------------------------------------------------------????private?void?Slider_ValueChanged_1(object?sender,?RangeBaseValueChangedEventArgs?e){????????if?(circlePanel?!=?null){?circlePanel.Radius?=?e.NewValue?*?10;}}本文來源于《深入理解Windows Phone 8.1 UI控件編程》
源代碼下載:http://vdisk.weibo.com/s/zt_pyrfNHoezI
歡迎關注我的微博@WP林政
WP8.1技術交流群:372552293
總結
以上是生活随笔為你收集整理的[WP8.1UI控件编程]Windows Phone自定义布局规则的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 26.Silverlight多线程技术T
- 下一篇: 看似无参却有参-----JS中的函数传参