简体   繁体   English

水平列表视图 Xamarin.Forms

[英]Horizontal ListView Xamarin.Forms

Is any way to create ListView with horizontal scroll in Xamarin.Forms like image有什么方法可以像图像一样在Xamarin.Forms创建带有horizontal scroll ListView

列表视图水平

this is what i have done for vertical这就是我为垂直所做的

var myListView = new ListView
{
    ItemTemplate = new DataTemplate(typeof(ImageCell))
};

As of Xamarin Forms 2.3 CarouselView does just that, and more.从 Xamarin Forms 2.3 CarouselView ,就可以做到这一点,甚至更多。 Read more here . 在这里阅读更多。

<ContentView HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
  <CarouselView ItemsSource="{Binding MyDataSource}">
    <CarouselView.ItemTemplate>
      <DataTemplate>
        <Label Text="{Binding LabelText}" />
      </DataTemplate>
    </CarouselView.ItemTemplate>
  </CarouselView>
</ContentView>

Yes, you technically can.是的,技术上可以。 Set the Rotation to 270 (all VisualElements have a Rotation BindableProperty).将 Rotation 设置为 270(所有 VisualElements 都有一个 Rotation BindableProperty)。 However, this looks like a suboptimal solution as there are white spaces at the top and bottom and you have to drag the view left and right to see everything fully.但是,这看起来像是一个次优的解决方案,因为顶部和底部都有空白区域,您必须左右拖动视图才能完全查看所有内容。

public static readonly BindableProperty RotationProperty;
public static readonly BindableProperty RotationXProperty;
public static readonly BindableProperty RotationYProperty;

The code above is from the VisualElement class.上面的代码来自 VisualElement 类。 The code below is a small sample of my own.下面的代码是我自己的一个小示例。

                                              ∨∨∨                                                  
<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>

As everyone else has said, No - there isn't one available out of the box in Xamarin.Forms .正如其他人所说,不 - Xamarin.Forms 中没有现成可用的。

However - it doesn't stop anyone from writing there own custom renderer to achieve this type of control.但是 - 它不会阻止任何人编写自己的自定义渲染器来实现这种类型的控制。

As Stephane Delcroix has mentioned, you can create a ScrollView and then a StackLayout as a child to create the same effect.正如Stephane Delcroix所提到的,您可以创建一个ScrollView ,然后创建一个StackLayout作为子项来创建相同的效果。

You will then need to implement:-然后,您需要实施:-

*) bindable property to accept the ( IEnumerable ) ItemsSource property that needs creating. *)可绑定属性以接受需要创建的 ( IEnumerable ) ItemsSource属性。

*) bindable property to accept the ( DataTemplate ) ItemTemplate property that needs creating. *)可绑定属性以接受需要创建的 ( DataTemplate ) ItemTemplate属性。

*) binding code to instantiate instances of the ItemTemplate taking the specific datasource item and rendering this into the StackLayout . *)绑定代码以实例化ItemTemplate 的实例,采用特定的数据源项并将其呈现到StackLayout 中 Your have to consider items removed etc also.您还必须考虑删除项目等。

*) attach event handlers / tap gestures for item selection. *) 为项目选择附加事件处理程序/点击手势。

*) implementing a selected state / deactivating other selected items. *) 实现选定状态/停用其他选定项目。

... and so on to get a full implementation. ...等等以获得完整的实施。

The problem with all of the above is that it is fine for relatively small item lists.以上所有问题都适用于相对较小的项目列表。

However, if you are looking for a long list of entries, then above would be a little undesirable as you are creating all of the Views upfront.但是,如果您正在寻找一长串条目,那么在您预先创建所有视图时,上面会有点不受欢迎。

Even if you delayed loading of these, you still have the memory footprint of all the Views to consider.即使您延迟加载这些,您仍然需要考虑所有视图内存占用

This then leads onto another possible implementation that deals with Virtualized Items , which is a whole different story to consider.然后,这导致了另一个可能的实现,它处理Virtualized Items ,这是一个完全不同的故事。

As pointed out above, there is no standard way of doing this, however there is a way around it using a standard ListView and @MillieSmiths approach.如上所述,没有标准的方法可以做到这一点,但是有一种方法可以使用标准的ListView和 @MillieSmiths 方法来解决它。

The solution needs several layers of nested layouts.该解决方案需要多层嵌套布局。 Starting with the ListViewwe will rotate that 270 degrees, however that also rotates our item content, so we need to rotate that back by 90 degrees.从 ListView 开始,我们将旋转 270 度,但这也会旋转我们的项目内容,因此我们需要将其向后旋转 90 度。

Rotating the ListView creates an awful lot of whitespace, by wrapping the ListView in an absolute layout we can solve that (we need an extra contentview in there to fix some clipping problems).旋转 ListView 会产生大量空白,通过将 ListView 包装在绝对布局中我们可以解决这个问题(我们需要一个额外的 contentview 来解决一些剪辑问题)。

Finally in the codebehind we need to render the layout clipping最后在代码隐藏中我们需要渲染布局裁剪

Behold the full solution:看看完整的解决方案:

<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>

For the code behind we just need to check if we have set things up before, if we have, let it go.对于后面的代码,我们只需要检查我们之前是否已经设置好了,如果有,就放手吧。 Basically we are finding out what the width of the page is ( NameGrid is just a full width container somewhere else) then moving the direct ListView container up by half the whitespace, and clipping it by the other half on the bottom)基本上我们要找出页面的宽度是NameGridNameGrid只是其他地方的全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;
             // */
        } 
    }

WARNING DO NOT USE <FRAMES> for the layout moving and rotating.警告不要使用<FRAMES>来移动和旋转布局。 It will crash on Windows Phone.它会在 Windows Phone 上崩溃。

PS I am sure this could be wrapped up in a nice UserControl for everyone to use. PS 我相信这可以包含在一个很好的 UserControl 中供每个人使用。

In Xamarin.Forms 4.0-pre you can use the CollectionView , which simplifies getting this type of layout.在 Xamarin.Forms 4.0-pre 中,您可以使用CollectionView ,这简化了获取此类布局的过程。

Sample:样本:

<CollectionView ItemsSource="{Binding Monkeys}">
    <CollectionView.ItemsLayout>
        <ListItemsLayout>
            <x:Arguments>
                <ItemsLayoutOrientation>Horizontal</ItemsLayoutOrientation>    
            </x:Arguments>
        </ListItemsLayout>
    </CollectionView.ItemsLayout>
</CollectionView>

Like the others have said, not possible with ListView and I think it's a big oversight by Xamarin with Forms.就像其他人所说的那样,ListView 不可能,我认为这是 Xamarin 对 Forms 的重大疏忽。 We need to dynamically display data driven objects in more than just a list doing down....come on ya'll!!我们需要在不仅仅是一个列表中动态显示数据驱动的对象……加油!

However, in the Xamarin Labs project there is GridView which you could use.但是,在 Xamarin Labs 项目中,您可以使用 GridView。 It's still a bit rough and folks are working through some bugs now with selecting the items.它仍然有点粗糙,人们现在正在通过选择项目来解决一些错误。

https://github.com/XForms/Xamarin-Forms-Labs https://github.com/XForms/Xamarin-Forms-Labs

Someone does seem to have a work around for that problem:似乎有人可以解决这个问题:

https://github.com/XForms/Xamarin-Forms-Labs/issues/236 https://github.com/XForms/Xamarin-Forms-Labs/issues/236

No, there's no way to have an horizontal ListView .不,没有办法有一个水平的ListView You can wrap an horizontal StackLayout in an horizontal ScrollView to achieve the same visual result, but that's not quite the same, as you won't have DataTemplating.您可以将水平 StackLayout 包装在水平 ScrollView 中以实现相同的视觉效果,但这并不完全相同,因为您没有 DataTemplating。

I've not tried it, but this might be worth checking out.我没有尝试过,但这可能值得一试。

https://github.com/Cheesebaron/Cheesebaron.HorizontalListView https://github.com/Cheesebaron/Cheesebaron.Horizo​​ntalListView

This nuget package will fit perfectly for your case.这个 nuget 包将非常适合您的情况。 I have used this one before and I really like it:我以前用过这个,我真的很喜欢它:

https://github.com/SuavePirate/DynamicStackLayout

To make things even better download these 3 Nuget packages to have an image loading, caching & transformation on your photos.为了让事情变得更好,请下载这 3 个 Nuget 包,以便对您的照片进行图像加载、缓存和转换。 The photos will be shaped in a circle but this nuget has other types of transformations:照片将被塑造成一个圆圈,但这个 nuget 有其他类型的转换:

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)

Here is a piece of code to help you to start:这里有一段代码可以帮助您开始:

<!--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>

I hope it helps :)我希望它有帮助:)

I have tried the mentioned "rotating" solution and besides it being an "ugly" solution, it also comes with several limitations :我已经尝试过提到的“旋转”解决方案,除了它是一个“丑陋”的解决方案外,它还具有几个限制

  1. list view WidthRequest has to be the same as HeightRequest列表视图 WidthRequest 必须与 HeightRequest 相同
  2. listView row height does not work properly anymore because it becomes cell width listView 行高不再正常工作,因为它变成了单元格宽度
  3. verticalalign becomes horizontalalign etc, not very maintainable. verticalalign 变成了horizo​​ntalalign 等,不是很容易维护。

A better option is to make your own custom control or, like I did, use an existing HorizontalListView : https://www.nuget.org/packages/HorizontalListView1.1/ This one is easy to use.更好的选择是制作自己的自定义控件,或者像我一样,使用现有的 Horizo​​ntalListViewhttps : //www.nuget.org/packages/Horizo​​ntalListView1.1/这个很容易使用。 You can find the source code and documentation here您可以在此处找到源代码和文档

Implementation:执行:

<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>

Till the CollectionView is out, you can use my Xamarin.Forms HorizontalListView .直到CollectionView出来,你可以使用我的 Xamarin.Forms Horizo​​ntalListView

It has:它有:

  • Snapping on first or middle element捕捉第一个或中间元素
  • Padding and item spacing填充和项目间距
  • Handles NotifyCollectionChangedAction Add, Remove and Reset actions处理 NotifyCollectionChangedAction 添加、删除和重置操作
  • View recycling查看回收
  • RecyclerView on Android Android 上的 RecyclerView
  • UICollectionView on iOS iOS 上的 UICollectionView
  • This implementation is in fact very close in terms of philosophy and implementation to what will provide the future Xamarin CollectionView.实际上,此实现在哲学和实现方面与将提供未来 Xamarin CollectionView 的内容非常接近。

As far as I know, there is 3 ways to implement this:据我所知,有3种方法可以实现这一点:

  1. Rotation ( as mentioned by other guys )轮换(如其他人提到的
    • No need to do anymore that standard ListView不需要再做那个标准的 ListView
    • ItemTemplate is available ItemTemplate 可用
    • Ugly solution!丑陋的解决方案!
  2. Custom Render ( RecyclerView in Android and (I think) UICollectionView in iOS )自定义渲染( Android 中的 RecyclerView 和(我认为)iOS 中的 UICollectionView
    • Custom cell is available (I'm sure about Android, but don't sure about iOS)自定义单元可用(我确定 Android,但不确定 iOS)
    • Needs more work and code需要更多的工作和代码
  3. Grid and Horizontal ScrollView ( using horizontal as value for orientation prop in ScrollView ) Grid 和 Horizo​​ntal ScrollView(在 ScrollView 中使用水平作为方向属性的值
    • Custom layout is available自定义布局可用
    • There is no CachingStrategy available in this solution, so for huge list this may cause huge RAM usage for your app此解决方案中没有可用的 CachingStrategy,因此对于庞大的列表,这可能会导致您的应用占用大量 RAM

What about this: https://docs.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/collectionview/layout#horizontal-list这个怎么样: https : //docs.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/collectionview/layout#horizo​​ntal-list

In XAML, a CollectionView can display its items in a horizontal list by setting its ItemsLayout property to HorizontalList:在 XAML 中,CollectionView 可以通过将其 ItemsLayout 属性设置为 Horizo​​ntalList 来在水平列表中显示其项目:

<CollectionView ItemsSource="{Binding Monkeys}"
                ItemsLayout="HorizontalList">
    <CollectionView.ItemTemplate>
        <DataTemplate>
            <Grid Padding="10">
                <Grid.RowDefinitions>
                    <RowDefinition Height="35" />
                    <RowDefinition Height="35" />
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="70" />
                    <ColumnDefinition Width="140" />
                </Grid.ColumnDefinitions>
                <Image Grid.RowSpan="2"
                       Source="{Binding ImageUrl}"
                       Aspect="AspectFill"
                       HeightRequest="60"
                       WidthRequest="60" />
                <Label Grid.Column="1"
                       Text="{Binding Name}"
                       FontAttributes="Bold"
                       LineBreakMode="TailTruncation" />
                <Label Grid.Row="1"
                       Grid.Column="1"
                       Text="{Binding Location}"
                       LineBreakMode="TailTruncation"
                       FontAttributes="Italic"
                       VerticalOptions="End" />
            </Grid>
        </DataTemplate>
    </CollectionView.ItemTemplate>
</CollectionView>

Alternatively, this layout can also be accomplished by setting the ItemsLayout property to a LinearItemsLayout object, specifying the Horizontal ItemsLayoutOrientation enumeration member as the Orientation property value:或者,也可以通过将 ItemsLayout 属性设置为 LinearItemsLayout 对象,将 Horizo​​ntal ItemsLayoutOrientation 枚举成员指定为 Orientation 属性值来完成此布局:

<CollectionView ItemsSource="{Binding Monkeys}">
    <CollectionView.ItemsLayout>
        <LinearItemsLayout Orientation="Horizontal" />
    </CollectionView.ItemsLayout>
    ...
</CollectionView>

This has been solved with a custom class called ItemsView (not to be confused with Xamarin's ItemsView for data templating in a ListView) which implements a ScrollView/StackPanel pattern mentioned above which example has already been requested for.这已通过名为 ItemsView 的自定义类解决(不要与 Xamarin 的 ItemsView 混淆,用于 ListView 中的数据模板),该类实现了上面提到的 ScrollView/StackPanel 模式,该示例已经被请求。 Please see the code: https://gist.github.com/fonix232/b88412a976f67315f915代码请看: https : //gist.github.com/fonix232/b88412a976f67315f915

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM