天天看點

通過Measure & Arrange實作UWP瀑布流布局簡介MeasureOverride方法ArrangeOverride方法效果總結

在以XAML為主的控件布局體系中,有用于完成布局的核心步驟,分别是measure和arrange。繼承體系中由UIElement類提供Measure和Arrange方法,并由其子類FrameworkElement類提供protected的MeasureOverride和ArrangeOverride方法來為自定義控件提供實作自定義布局的接口。本文通過一個瀑布流布局實作來為大家簡單地介紹這兩個核心方法。

所謂瀑布流布局,是多列布局的一種形式,列中元素等比縮放使得自身與列等寬,每列再以StackPanel的形式布局,下一個元素自動排布到最短的那一列上。

大緻效果可以參考百度圖檔首頁,點選“攝影”,“美食”或“寵物”後進入的頁面效果。(寵物here:http://image.baidu.com/channel?c=%E5%AE%A0%E7%89%A9&t=%E5%85%A8%E9%83%A8&s=0)

一言以蔽之,擷取大小。

每個控件有提供給外部調用的Measure方法,用來決定該控件需要的空間。這個方法會對布局設定進行簡單的處理,比如對Margin等屬性進行預處理,然後把主要的步驟交給MeasureOverride方法。

這一方法的參數代表了該控件本身能擁有的大小。布局時需要考慮到它。

在這一方法中,控件需要做的就是周遊所有子控件,并調用他們的Measure方法,按照自己的布局方式對這些空間的大小進行運算。最後遞歸出一個總的空間大小,然後傳回給它的父控件。

在這一過程中,按照需要,可能連子控件的位置資訊也需要考慮(比如我們的瀑布流)。

所有的控件在計算完自己的所需控件後,會設定自己的DesiredSize屬性,表明它所需的尺寸。這一屬性在之後的Arrange過程中可以使用(不過不要在非自定義布局的情況下使用哦)。

此時控件和子控件的大小都已經确定了。

我們通過繼承Panel來實作自己的瀑布流布局,這麼做的目的,主要是可以将Panel用于ItemsControl及其子類的ItemsPanel屬性(Panel類此時或許可以有另一個名字:LayoutPolicy)。配合ItemTemplate和ItemsSource,可以友善的填充和具象資料。

讓我們看看如何實作一個這樣行為的MeasureOverride:

傳回值是該元素本身實際需要的大小。

可看出我們也沒有考慮縮放的問題。如果子控件要求的大小(特别是寬度)比流的寬度要大,就會導緻顯示不全的情況。這一點我們可以通過ViewBox來調整,不一定要在這個panel裡實作(當然有特殊需求的除外)。

至此,panel和子控件的大小計算都已結束。

Arrange,一言以蔽之,設定位置和大小。

這裡的大小,就是通過Measure系列方法确定的DesiredSize。

在ArrangeOverride方法中,我們要做的,同樣是周遊子控件,利用它們在Measure過程中确定的大小,來為它們加上位置資訊。

可以看到,雖然我們的瀑布流panel在measure過程中也記錄了位置資訊,但隻是用于計算總大小。而在arrange過程中,位置資訊将被确實的利用上。

讓我們看看ArrangeOverride方法的實作。對本例來說,它和MeasureOverride十分相似。

至此,整個流的布局都已經完成。

讓我們看看,這個瀑布流實作了怎樣的效果。

我們先定義個結構,主要使用随機數來造成流中元素參差不齊的效果:

ic是一個ItemsControl(也可以是其子類,如ListView。這樣我們的panel就隻負責布局,至于子控件的點選行為,動畫行為,全部交給ListView)。

我們在UI事件中設定資料源:

XAML中對ItemsControl的設定如下。Border嘗試占滿其水準空間。同時所有的流内容可以上下滾動。

效果如下:

通過Measure & Arrange實作UWP瀑布流布局簡介MeasureOverride方法ArrangeOverride方法效果總結

我們可以直接把ItemsControl換成ListView,再進行簡單的Style設定,直接讓我們的瀑布流與ListView的豐富特性融合:

通過Measure & Arrange實作UWP瀑布流布局簡介MeasureOverride方法ArrangeOverride方法效果總結

這篇部落格隻是為大家介紹了一下對Measure和Arrange的簡單嘗試,但XAML中的控件卻全部依賴這樣的規則來完成布局。

每當大家遇到不同的控件組合達到的效果時,比如用Canvas可以讓内容畫在範圍之外,StackPanel對其内容的處理等等,往往可以通過分析那個控件樹的Measure和Arrange過程從中獲得解答。

希望本文抛磚引玉,讓UWP開發中出現更多有趣的設計和實作。