Xamarin Forms可展开ListView仅部分项分组折叠展开的实现咨询
实现方案
核心思路是把无分组的单个菜单项伪装成仅包含单个元素的分组,隐藏该类分组的头部使其看起来是独立项,仅对有实际分组的菜单项显示可折叠的分组头部。
步骤1:新增分组模型类
定义支持折叠状态通知的分组模型:
using System.Collections.ObjectModel; using System.ComponentModel; using System.Runtime.CompilerServices; public class MenuGroup : ObservableCollection<NavMenuItem>, INotifyPropertyChanged { private string _groupName; public string GroupName { get => _groupName; set { _groupName = value; OnPropertyChanged(); } } private bool _isExpanded = true; public bool IsExpanded { get => _isExpanded; set { _isExpanded = value; OnPropertyChanged(); } } // 标记是否为无分组的独立菜单项 public bool IsStandalone => Count == 1 && string.IsNullOrEmpty(GroupName); public new event PropertyChangedEventHandler PropertyChanged; protected new void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }
步骤2:改造数据源构造逻辑
将原有的平级菜单项列表转换成分组列表:
// 原有的菜单项定义保持不变 var allItems = new List<NavMenuItem> { new NavMenuItem {Id = MenuItemType.Home, Title="Home", IconSource="homeicon.png" }, new NavMenuItem {Id = MenuItemType.Offers, Title="Offerings", IconSource = "offeringsicon.png", Group = "Shopping"}, // 剩下的菜单项和之前完全一致,此处省略 }; var menuGroups = new List<MenuGroup>(); // 处理有分组的菜单项,按Group值聚合 var groupedItems = allItems.Where(x => !string.IsNullOrEmpty(x.Group)) .GroupBy(x => x.Group) .Select(g => new MenuGroup { GroupName = g.Key, g.ToList() }); menuGroups.AddRange(groupedItems); // 处理无分组的菜单项,每个单独生成一个分组 var standaloneItems = allItems.Where(x => string.IsNullOrEmpty(x.Group)); foreach (var item in standaloneItems) { menuGroups.Add(new MenuGroup { GroupName = "", new List<NavMenuItem> { item } }); } // 可按需调整分组排序,比如将Home放在最顶部 ListViewMenu.ItemsSource = menuGroups;
步骤3:修改ListView的XAML代码
新增分组头部模板,控制头部显示和折叠交互:
<!-- 新增布尔值反转转换器,用于控制独立项分组的头部隐藏 --> <ContentPage.Resources> <ResourceDictionary> <local:InverseBoolConverter x:Key="InverseBoolConverter" /> <local:ExpandedIconConverter x:Key="ExpandedIconConverter" /> </ResourceDictionary> </ContentPage.Resources> <ListView x:Name="ListViewMenu" HasUnevenRows="True" HorizontalOptions="Start" IsGroupingEnabled="True"> <!-- 分组头部模板 --> <ListView.GroupHeaderTemplate> <DataTemplate> <ViewCell Height="{Binding IsStandalone, Converter={StaticResource InverseBoolConverter}, ConverterParameter=40;0}"> <StackLayout Padding="15,8" BackgroundColor="#f5f5f5"> <StackLayout.GestureRecognizers> <TapGestureRecognizer Tapped="GroupHeader_Tapped" /> </StackLayout.GestureRecognizers> <Grid IsVisible="{Binding IsStandalone, Converter={StaticResource InverseBoolConverter}}"> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"/> <ColumnDefinition Width="Auto"/> </Grid.ColumnDefinitions> <Label Text="{Binding GroupName}" FontSize="14" TextColor="#333" Grid.Column="0"/> <!-- 展开/折叠状态箭头,可自行替换为图片 --> <Label Text="{Binding IsExpanded, Converter={StaticResource ExpandedIconConverter}}" FontSize="14" Grid.Column="1" HorizontalOptions="End"/> </Grid> </StackLayout> </ViewCell> </DataTemplate> </ListView.GroupHeaderTemplate> <!-- 原有菜单项模板,仅新增IsVisible绑定 --> <ListView.ItemTemplate> <DataTemplate> <ViewCell IsVisible="{Binding Source={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:MenuGroup}}, Path=IsExpanded}"> <Frame HasShadow="True" CornerRadius="10" BorderColor="#282828" Padding="1"> <StackLayout> <Grid Padding="10" > <Grid.ColumnDefinitions> <ColumnDefinition Width="0.2*"/> <ColumnDefinition Width="0.8*"/> </Grid.ColumnDefinitions> <Image Source="{Binding Image}" Grid.Column="0" WidthRequest="30" HeightRequest="30"/> <Label Text="{Binding Title}" FontSize="Small" Grid.Column="1" TextColor="black"/> </Grid> </StackLayout> </Frame> </ViewCell> </DataTemplate> </ListView.ItemTemplate> </ListView>
步骤4:新增辅助逻辑
- 两个简单的转换器:
InverseBoolConverter用于反转布尔值,ExpandedIconConverter用于将折叠状态转为箭头符号(展开返回↑,折叠返回↓) - 分组头部点击事件:
private void GroupHeader_Tapped(object sender, EventArgs e) { var layout = sender as StackLayout; var group = layout.BindingContext as MenuGroup; group.IsExpanded = !group.IsExpanded; }
该方案完全符合需求:有Group值的菜单项会显示分组头部,点击可折叠展开子项;无Group值的菜单项不会显示分组头部,直接作为独立项展示。
内容的提问来源于stack exchange,提问作者Ricardo Jahn
相关产品推荐
相关产品推荐

