有没有办法在Xamarin.Forms
中创建水平滚动的ListView
,就像图片所示:
这是我为垂直滚动做的:
var myListView = new ListView
{
ItemTemplate = new DataTemplate(typeof(ImageCell))
};
有没有办法在Xamarin.Forms
中创建水平滚动的ListView
,就像图片所示:
这是我为垂直滚动做的:
var myListView = new ListView
{
ItemTemplate = new DataTemplate(typeof(ImageCell))
};
自Xamarin Forms 2.3起,CarouselView
实现了这一点,而且更多功能。在此处阅读更多信息。
<ContentView HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
<CarouselView ItemsSource="{Binding MyDataSource}">
<CarouselView.ItemTemplate>
<DataTemplate>
<Label Text="{Binding LabelText}" />
</DataTemplate>
</CarouselView.ItemTemplate>
</CarouselView>
</ContentView>
是的,从技术上讲你可以这样做。将旋转角度设置为270度(所有VisualElements都有一个可绑定的Rotation属性)。然而,这看起来像是一个次优解决方案,因为顶部和底部会有空白,并且你必须左右拖动视图才能完全查看所有内容。
public static readonly BindableProperty RotationProperty;
public static readonly BindableProperty RotationXProperty;
public static readonly BindableProperty RotationYProperty;
上面的代码来自于VisualElement类。下面的代码是我自己写的一个小样例。
∨∨∨
<ListView x:Name="MessagesListView" Rotation="270" ItemsSource="{Binding Items}" RowHeight="40">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<StackLayout>
<!--mylayouthere-->
</StackLayout>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
正如其他人所说,Xamarin.Forms中没有现成的可用项。
然而,任何人都可以编写自己的自定义渲染器来实现此类型的控件。
正如Stephane Delcroix所提到的那样,您可以创建一个ScrollView,然后将StackLayout作为其子元素来创建相同的效果。
然后,您需要实现以下内容:
*) 可绑定属性,接受需要创建的(IEnumerable)ItemsSource属性。
*) 可绑定属性,接受需要创建的(DataTemplate)ItemTemplate属性。
*) 绑定代码,以实例化ItemTemplate的实例,取特定数据源项并将其呈现到StackLayout中。您还需要考虑移除的项目等。
*) 为项目选择附加事件处理程序/轻敲手势。
*) 实现选定状态/停用其他选定项目。
......等等,以获取完整实现。
以上所有方法存在的问题是它们适用于相对较小的项目列表。
但是,如果您正在寻找一个包含大量条目的长列表,则以上方法会有点不太理想,因为您要创建所有视图。即使您延迟加载它们,您仍然需要考虑所有视图的内存占用。
这就引出了另一种处理虚拟项的可能实现,这是一个完全不同的故事需要考虑。
如上所述,没有标准的方法来实现此操作,但是使用标准的 ListView
和 @MillieSmiths 方法可以绕过此问题。
解决方案需要多层嵌套布局。从 ListView 开始,我们将其旋转 270 度,但这也会旋转我们的项目内容,因此我们需要再旋转回来 90 度。
旋转 ListView 会创建大量空白,通过将 ListView 包装在绝对布局中,我们可以解决这个问题(我们需要在其中添加额外的 contentview 以解决一些剪裁问题)。
最后,在代码后台中,我们需要呈现布局剪切。
完整解决方案如下:
<AbsoluteLayout x:Name="MessagesLayoutFrame" Padding="0" HorizontalOptions="FillAndExpand">
<ContentView x:Name="MessagesLayoutFrameInner" Padding="0" HorizontalOptions="FillAndExpand">
<ListView x:Name="MessagesListView"
ItemsSource="{Binding Images}"
RowHeight="240"
VerticalOptions="Start"
HeightRequest="240"
WidthRequest="240"
SeparatorVisibility="None"
Rotation="270"
HorizontalOptions="Center">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ContentView Rotation="90" Padding="12">
<Image Source="{Binding Source}" Aspect="AspectFill" />
</ContentView>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentView>
</AbsoluteLayout>
对于后台代码,我们只需要检查是否已经设置好了,如果是,则让它继续运行。基本上我们正在查找页面的宽度(NameGrid
只是其他地方的全宽容器),然后将直接的 ListView 容器向上移动一半的空白,并在底部剪裁另一半。
bool hasAppearedOnce = false;
protected override void OnAppearing() {
base.OnAppearing();
if (!hasAppearedOnce) {
hasAppearedOnce = true;
var padding = (NameGrid.Width - MessagesListView.Height) / 2;
MessagesListView.HeightRequest = MessagesLayoutFrame.Width;
MessagesLayoutFrameInner.WidthRequest = MessagesLayoutFrame.Width;
MessagesLayoutFrameInner.Padding = new Thickness(0);
MessagesLayoutFrame.Padding = new Thickness(0);
MessagesLayoutFrame.IsClippedToBounds = true;
Xamarin.Forms.AbsoluteLayout.SetLayoutBounds(MessagesLayoutFrameInner, new Rectangle(0, 0 - padding, AbsoluteLayout.AutoSize, MessagesListView.Height - padding));
MessagesLayoutFrameInner.IsClippedToBounds = true;
// */
}
}
警告
不要使用<FRAMES>
来进行布局的移动和旋转。它会在Windows Phone上崩溃。
P.S. 我确信这可以封装在一个漂亮的UserControl中供大家使用。
<CollectionView ItemsSource="{Binding Monkeys}">
<CollectionView.ItemsLayout>
<ListItemsLayout>
<x:Arguments>
<ItemsLayoutOrientation>Horizontal</ItemsLayoutOrientation>
</x:Arguments>
</ListItemsLayout>
</CollectionView.ItemsLayout>
</CollectionView>
不,没有水平的ListView
的方式。您可以将水平的StackLayout包装在水平的ScrollView中,以实现相同的视觉效果,但这并不完全相同,因为您将无法使用DataTemplating。
这个NuGet软件包非常适合你的情况。我以前使用过它,真的很喜欢:
https://github.com/SuavePirate/DynamicStackLayout
Xamarin.FFImageLoading (https://github.com/luberda-molinet/FFImageLoading/wiki/Xamarin.Forms-API)
Xamarin.FFImageLoading.Forms
Xamarin.FFImageLoading.Transformations (https://github.com/luberda-molinet/FFImageLoading/wiki/Transformations-Guide)
<!--Add this code to the top of your page-->
xmlns:ffimageloading="clr-namespace:FFImageLoading.Forms;assembly=FFImageLoading.Forms"
xmlns:fftransformations="clr-namespace:FFImageLoading.Transformations;assembly=FFImageLoading.Transformations"
xmlns:dynamicStackLayout="clr-namespace:SuaveControls.DynamicStackLayout;assembly=SuaveControls.DynamicStackLayout"
<!-- Here is your control inside a ScrollView. The property Photos is a list of images address (Urls) -->
<ScrollView Orientation="Horizontal" HorizontalOptions="FillAndExpand">
<dynamicStackLayout:DynamicStackLayout ItemsSource="{Binding Photos}" HorizontalOptions="Fill" Orientation="Horizontal" Padding="10, -0, 100, 10">
<dynamicStackLayout:DynamicStackLayout.ItemTemplate>
<DataTemplate>
<StackLayout BackgroundColor="Transparent" >
<ffimageloading:CachedImage HorizontalOptions="Start" VerticalOptions="Center" DownsampleToViewSize="true" Aspect="AspectFit" Source="{Binding .}">
<ffimageloading:CachedImage.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Path=PhotoCommand}" CommandParameter="{Binding .}" NumberOfTapsRequired="1" />
</ffimageloading:CachedImage.GestureRecognizers>
<ffimageloading:CachedImage.HeightRequest>
<OnPlatform x:TypeArguments="x:Double">
<On Platform="iOS" Value="50" />
<On Platform="Android" Value="60" />
</OnPlatform>
</ffimageloading:CachedImage.HeightRequest>
<ffimageloading:CachedImage.WidthRequest>
<OnPlatform x:TypeArguments="x:Double">
<On Platform="iOS" Value="50" />
<On Platform="Android" Value="60" />
</OnPlatform>
</ffimageloading:CachedImage.WidthRequest>
<ffimageloading:CachedImage.Transformations>
<fftransformations:CircleTransformation BorderHexColor="#eeeeee">
<fftransformations:CircleTransformation.BorderSize>
<OnPlatform x:TypeArguments="x:Double">
<On Platform="iOS" Value="10" />
<On Platform="Android" Value="10" />
</OnPlatform>
</fftransformations:CircleTransformation.BorderSize>
</fftransformations:CircleTransformation>
</ffimageloading:CachedImage.Transformations>
</ffimageloading:CachedImage>
</StackLayout>
</DataTemplate>
</dynamicStackLayout:DynamicStackLayout.ItemTemplate>
</dynamicStackLayout:DynamicStackLayout>
</ScrollView>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="test.ListPage"
xmlns:Controls="clr-namespace:HorizontalList;assembly=HorizontalList">
<Controls:HorizontalListView ItemsSource="{Binding Categories}" ListOrientation="Horizontal">
<Controls:HorizontalListView.ItemTemplate>
<DataTemplate>
<Label Text="{Binding Name}" />
</DataTemplate>
</Controls:HorizontalListView.ItemTemplate>
</Controls:HorizontalListView>
</ContentPage>