在显示表格数据时,我认为在某些情况下,具有始终可见的标题行和始终可见的第一列确实可以提高表格的可读性和整体可用性,特别是当表格中有大量数据时。当表格必须支持水平和垂直滚动时,就会出现问题。在查看过去比赛的得分时,可以从 NBA 应用程序中找到此类表格的一个很好的示例。以下是来自 NBA Android 应用程序的示例图像:NBA 移动应用程序中的示例表
从图像中可以清楚地看到,标题行与实际表格数据水平对齐,第一列与表格数据垂直对齐。我不知道这是一个非自愿的还是自愿的决定,以防止使用相同的触摸动作水平和垂直滚动,但这是我不关心的一个小细节。
我不知道如何使用 Xamarin Forms 来实现这一点。我对闭源/付费解决方案不感兴趣,因为我想实际学习如何自己完成此任务。我确实意识到我很可能必须为 Android 和 IOS 使用自定义渲染器。我当前的想法是我有一个绝对布局,其中包含以下元素:
- 第一个单元格(它是静止的,也是唯一静止的东西)
- 水平滚动视图内标题行的其余部分
- listview/stacklayout + 垂直滚动视图中的第一列
- 列表视图+水平滚动视图/堆栈布局+水平和垂直滚动视图内的实际表格数据
通过此设置,我将捕获触摸事件并将其发送到其他列表视图/滚动视图,从而同步滚动。事实上,通过将表数据设置在与第一列相同的垂直滚动视图内,我可以轻松实现第一列和实际表数据的同步滚动。但我不知道如何将水平滚动同步到标题行,并且我确实相信这不能通过巧妙的组件结构来完成。到目前为止,我只在 Android 上进行了测试,我可以在滚动视图自定义渲染器的 OnTouchEvent 方法中捕获触摸事件,但我不知道如何将其从自定义渲染器发送到标题行滚动视图。
这是说明我的方法的 XAML 草案。
<AbsoluteLayout xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
HorizontalOptions="FillAndExpand">
<ScrollView
Orientation="Horizontal"
x:Name="HeaderScrollView"
AbsoluteLayout.LayoutBounds="0,0,1,1"
AbsoluteLayout.LayoutFlags="All">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="50" />
</Grid.RowDefinitions>
<!-- Skip first column, leave it empty for stationary cell -->
<Label Text="Column 1" Grid.Row="0" Grid.Column="1" />
<Label Text="Column 2" Grid.Row="0" Grid.Column="2" />
<Label Text="Column 3" Grid.Row="0" Grid.Column="3" />
<Label Text="Column 4" Grid.Row="0" Grid.Column="4" />
</Grid>
</ScrollView>
<ScrollView
x:Name="FirstColumnScrollView"
Orientation="Vertical"
AbsoluteLayout.LayoutBounds="0,50,1,1"
AbsoluteLayout.LayoutFlags="SizeProportional"
BackgroundColor="Aqua">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackLayout
Grid.Column="0"
Grid.Row="0"
BindableLayout.ItemsSource="{Binding DataSource}">
<BindableLayout.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150" />
</Grid.ColumnDefinitions>
<Label Text="{Binding Column1}" Grid.Row="0" Grid.Column="0" />
</Grid>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
<ScrollView
x:Name="TableDataScrollView"
Grid.Column="1"
Grid.Row="0"
Orientation="Horizontal">
<StackLayout
BindableLayout.ItemsSource="{Binding DataSource}">
<BindableLayout.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="50" />
</Grid.RowDefinitions>
<Label Text="{Binding Column2}" Grid.Row="0" Grid.Column="0" />
<Label Text="{Binding Column3}" Grid.Row="0" Grid.Column="1" />
<Label Text="{Binding Column4}" Grid.Row="0" Grid.Column="2" />
<Label Text="{Binding Column5}" Grid.Row="0" Grid.Column="3" />
</Grid>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
</ScrollView>
</Grid>
</ScrollView>
<Label Text="First Column" BackgroundColor="White" AbsoluteLayout.LayoutBounds="0,0,200,50" />
</AbsoluteLayout>
正如您所看到的,问题在于 HeaderScrollView 和 TableDataScrollView 之间的水平滚动事件不共享,我不知道如何以最好的方式或根本不知道如何实现这一点。
我非常感谢所有的帮助和反馈!