天天看點

UWP:可滾動的PivotHeader

原文: UWP:可滾動的PivotHeader

UWP開發裡,Pivot真是個令人又愛又恨的控件。為了實作某些可滾動Header的效果,有些大佬甚至去掉了原本的Header,使用一個ListView或者ListBox自己畫Header,不過這樣會讓控件變得很複雜。

既然Pivot是一個模闆化控件,那麼應該有方法直接讓Header可以滾動。

先貼效果圖:

UWP:可滾動的PivotHeader

先自定義Pivot的Style,從generic.xaml找(位置應該在C:\Program Files (x86)\Windows Kits\10\DesignTime\CommonConfiguration\Neutral\UAP\(你的SDK版本)\Generic),或者在xaml設計器裡右鍵,編輯Style也可以。

找到Style中的<VisualStateGroup x:Name="NavigationButtonsVisibility">,到</VisualStateGroup>,包括這兩行,全部注釋掉,就可以取消左右兩側的按鈕。

 分析一下,Pivot有兩個狀态:

當HeaderPanel寬度小于Pivot寬度的時候,也就是Headers不溢出的時候,Header的位置是固定的;

當HeaderPanel寬度大于Pivot寬度的時候,也就是Headers溢出的時候,被選中的Header會被移動到第一位。

觀察一下Style可以得知,這個是HeaderStates這個VisualStateGroup控制的,是以和上面一樣,注釋掉HeaderStates這個VisualStateGroup,這樣就取消了動态Header和固定Header的狀态轉換。

然後往下找,找到<PivotHeaderPanel x:Name="Header" >到</PivotHeaderPanel>,全部注釋掉,這是動态的Header,我們隻需要靜态的。

然後把<PivotHeaderPanel x:Name="StaticHeader">的Visibility改成Visible,這樣就預設使用靜态的Header,即使Headers溢出也不會自己移動。

最後,在PivotHeaderPanel外面的Grid外面套一層ScrollViewer,代碼會變成下面的樣子:

<ScrollViewer ScrollViewer.HorizontalScrollBarVisibility="Hidden" ScrollViewer.HorizontalScrollMode="Enabled" ScrollViewer.VerticalScrollBarVisibility="Disabled" ScrollViewer.VerticalScrollMode="Disabled" >
    <Grid Background="{ThemeResource PivotHeaderBackground}">
        <Grid.RenderTransform>
            <CompositeTransform x:Name="HeaderOffsetTranslateTransform" />
        </Grid.RenderTransform>
        <PivotHeaderPanel x:Name="StaticHeader" Visibility="Visible" >
            <PivotHeaderPanel.RenderTransform>
                <CompositeTransform x:Name="StaticHeaderTranslateTransform"/>
            </PivotHeaderPanel.RenderTransform>
        </PivotHeaderPanel>
        <!--<PivotHeaderPanel x:Name="Header" >
            <PivotHeaderPanel.RenderTransform>
                <CompositeTransform x:Name="HeaderTranslateTransform"/>
            </PivotHeaderPanel.RenderTransform>
        </PivotHeaderPanel>-->
    </Grid>
</ScrollViewer>      

運作一下試試看,Header是不是可以使用滑鼠滾輪左右滾動了。

至此,本文就已經可以結束了。不過有人可能會問,為什麼你的Pivot會有下面的Focus,我的就沒有呢?請接着往下看:

從xaml設計器貼出來的Pivot的Style裡,并沒有Header相關的,Selected、Unselected之類的VisualState,是微軟忘了寫?其實并不是。

如果你和ItemsControl經常打交道,你會發現ListView、GridView之類的控件都有個ItemContainerStyle屬性,控制Items的容器的Style,一般來說Select之類的VisualState都在這裡面,可是Pivot并沒有提供Header的ItemContainerStyle啊?

其實PivotHeaderItemContainerStyle也是有的,隻是微軟沒有直接提供給我們,需要手動從檔案裡複制一下,并且用一些非正常的方式使其生效。

首先打開generic.xaml,,在裡面全局搜尋PivotHeaderItem,可以找到如下段落:

UWP:可滾動的PivotHeader

将這一段複制出來,這時你有三個選擇:

  1. 如果你自定義了Pivot的Style,請将這段放在<ControlTemplate TargetType="Pivot"> <Grid x:Name="RootElement" ...><Grid.Resource>(放在這裡)</Grid.Resource>。
  2. 如果沒有自定義Style,請将這段放在<Pivot><Pivot.Resource>(放在這裡)</Pivot.Resource>
  3. 單獨寫在資源字典或者Page.Resource或者Application.Resource裡,把x:Key設定為PivotHeaderItemContainerStyle,然後在如上兩個位置寫<Style TargetType="PivotHeaderItem" BaseOn="{StaticResource PivotHeaderItemContainerStyle}">

注意:對于最終生效的Style(1、2和3中帶BaseOn的Style),不要設定x:Key和x:Name!(不設定x:Key和x:Name的Style資源,會應用給他的所有TargetType比對的子控件。)

這樣我們就可以自定義PivotHeaderItemContainerStyle了。

然後找到<VisualStateGroup x:Name="SelectionStates">,在裡面的Selected,SelectedPointerOver,SelectedPressed的Storyboard中加入如下的段落:

<ObjectAnimationUsingKeyFrames Storyboard.TargetName="FocusPipe" Storyboard.TargetProperty="Visibility">
    <DiscreteObjectKeyFrame KeyTime="0" Value="Visible" />
</ObjectAnimationUsingKeyFrames>      

這樣再運作,就可以在Header被選中的時候顯示下面的Focus啦。