最近好久沒有寫部落格了,今天分享一下關於工作中遇到的關於Visibility變化而引起的布局變化的問題。
先以一個小例子開場,需求: 新浪微博 添加帳號介面中需要有“登陸”按鈕,當使用者點擊此按鈕後,需要把按鈕換成ProgressRing。如果登陸不成功,彈出錯誤資訊並把ProgressRing替換成“登陸”按鈕。
如:
在按鈕與ProgressRing切換的時候我們的一般做法是兩種:
1. 用兩個Visibility屬性隱藏其中按鈕,然後再顯示;
2. 刪除按鈕、添加ProgressRing;刪除ProgressRing,添加按鈕;
第二種比較浪費資源,所以大家都把第一種作為較為常用的方法,即: 用Visibility屬性來控制某些UI元素的隱藏與否,特別是需要重複切換的。
現在切入正題,先:
想必玩過Win8開發的童鞋們一定不陌生,這是在VS中建立GridView模版的應用,啟動後的首頁面。
需求是:點擊某一項,使其從介面中消失,但是布局不變,即:如果我任意刪除一個單元,後面的單元會補充到前面去,中間不會有空白空間。
乍一看跟上面例子的需求類似,可以在資料集的單中繼資料中添加個Visibility類型的屬性,通過綁定到ItemTemplate中的最外層布局控制項上來實現隱藏。但是你真的這麼做了,卻發現結果是這樣的:
Wow! 為什麼? 如果你看看GridView的代碼,並試圖修改點內容,或許會有所發現:
<GridView x:Name="itemGridView" AutomationProperties.AutomationId="ItemGridView" AutomationProperties.Name="Grouped Items" Grid.RowSpan="2" Padding="116,137,40,46" ItemsSource="{Binding Source={StaticResource groupedItemsViewSource}}" ItemTemplate="{StaticResource Standard250x250ItemTemplate}" SelectionMode="None" IsSwipeEnabled="false" IsItemClickEnabled="True" ItemClick="ItemView_ItemClick"> <GridView.ItemsPanel> <ItemsPanelTemplate> <VirtualizingStackPanel Orientation="Horizontal"/> </ItemsPanelTemplate> </GridView.ItemsPanel> <GridView.GroupStyle> <GroupStyle> <GroupStyle.HeaderTemplate> <DataTemplate> <Grid Margin="1,0,0,6"> <Button AutomationProperties.Name="Group Title" Click="Header_Click" Style="{StaticResource TextPrimaryButtonStyle}" > <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding Title}" Margin="3,-7,10,10" Style="{StaticResource GroupHeaderTextStyle}" /> <TextBlock Text="{StaticResource ChevronGlyph}" FontFamily="Segoe UI Symbol" Margin="0,-7,0,10" Style="{StaticResource GroupHeaderTextStyle}"/> </StackPanel> </Button> </Grid> </DataTemplate> </GroupStyle.HeaderTemplate> <GroupStyle.Panel> <ItemsPanelTemplate> <VariableSizedWrapGrid Orientation="Vertical" Margin="0,0,80,0"/> </ItemsPanelTemplate> </GroupStyle.Panel> </GroupStyle> </GridView.GroupStyle> </GridView>
關鍵因素1:<GroupStyle.Panel>中的 VariableSizedWrapGrid
如果把<GroupStyle.Panel>中的 VariableSizedWrapGrid替換成<StackPanel Orientation="Horizontal" Margin="0,0,80,0"/>,你會發現效果變成了這樣:
Group Title 1 中的 Item Titile 2的項被刪除掉了以後,後面的元素都向前移動了,證明VariableSizedWrapGrid控制項內部對Visibility變化導致的布局變化的支援度不是很好。(你注意到在ItemTitile2項被隱藏後,為什麼中間的空間會比較大,不像其他元素一樣? 這個留給大家去研究吧,賣個關子。。。)
關鍵因素2:WrapGrid
或許你的應用中不需要分組,也會出現類似的情況,那可能是這樣的:
<GridView x:Name="itemGridView" AutomationProperties.AutomationId="ItemGridView" AutomationProperties.Name="Grouped Items" Grid.RowSpan="2" Padding="116,137,40,46" ItemsSource="{Binding Source={StaticResource groupedItemsViewSource}}" ItemTemplate="{StaticResource Standard250x250ItemTemplate}" SelectionMode="None" IsSwipeEnabled="false" IsItemClickEnabled="True" ItemClick="ItemView_ItemClick"> <GridView.ItemsPanel> <ItemsPanelTemplate> <WrapGrid Orientation="Vertical"/> </ItemsPanelTemplate> </GridView.ItemsPanel> </GridView>
同樣的,隱藏某一項後,後面的元素並不會填充被隱藏元素的空間,而只是隱藏了那一項,剩下的位置不動。。。
那你試試把WrapGrid換成 VirtualizingStackPanel,問題解決了。
你或許在問,如果這樣改,空白的空間是解決了,但是我們的整體布局也被打亂了。。。
沒錯,其實這些都只是下下策,更多的是為了告訴大家,這幾個控制項對Visibility屬性變化而引起的布局變化的支援程度,而相比較之下,或許從資料來源中刪除資料才是更好的解決方案,即解決了空白空間的問題,也解決了布局被打亂的問題。