Horizontal ListView Xamarin.Forms

核能气质少年 提交于 2019-12-17 10:57:15

问题


Is any way to create ListView with horizontal scroll in Xamarin.Forms like image

this is what i have done for vertical

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

回答1:


Yes, you technically can. Set the Rotation to 270 (all VisualElements have a 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. 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>



回答2:


As everyone else has said, No - there isn't one available out of the box in 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.

You will then need to implement:-

*) bindable property to accept the (IEnumerable) ItemsSource property that needs creating.

*) bindable property to accept the (DataTemplate) ItemTemplate property that needs creating.

*) binding code to instantiate instances of the ItemTemplate taking the specific datasource item and rendering this into the 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.




回答3:


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.

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.

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

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)

    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. It will crash on Windows Phone.

P.S I am sure this could be wrapped up in a nice UserControl for everyone to use.




回答4:


As of Xamarin Forms 2.3 CarouselView does just that, and more. Read more here.

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



回答5:


Like the others have said, not possible with ListView and I think it's a big oversight by Xamarin with 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. 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

Someone does seem to have a work around for that problem:

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




回答6:


No, there's no way to have an horizontal 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.




回答7:


In Xamarin.Forms 4.0-pre you can use the CollectionView, which simplifies getting this type of layout.

Sample:

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



回答8:


I've not tried it, but this might be worth checking out.

https://github.com/Cheesebaron/Cheesebaron.HorizontalListView




回答9:


This nuget package will fit perfectly for your case. 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. The photos will be shaped in a circle but this nuget has other types of transformations:

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




回答10:


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
  2. listView row height does not work properly anymore because it becomes cell width
  3. verticalalign becomes horizontalalign etc, not very maintainable.

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



回答11:


Till the CollectionView is out, you can use my Xamarin.Forms HorizontalListView.

It has:

  • Snapping on first or middle element
  • Padding and item spacing
  • Handles NotifyCollectionChangedAction Add, Remove and Reset actions
  • View recycling
  • RecyclerView on Android
  • UICollectionView on iOS
  • This implementation is in fact very close in terms of philosophy and implementation to what will provide the future Xamarin CollectionView.



回答12:


As far as I know, there is 3 ways to implement this:

  1. Rotation (as mentioned by other guys)
    • No need to do anymore that standard ListView
    • ItemTemplate is available
    • Ugly solution!
  2. Custom Render (RecyclerView in Android and (I think) UICollectionView in iOS)
    • Custom cell is available (I'm sure about Android, but don't sure about iOS)
    • Needs more work and code
  3. Grid and Horizontal ScrollView (using horizontal as value for orientation prop in 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



回答13:


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. Please see the code: https://gist.github.com/fonix232/b88412a976f67315f915



来源:https://stackoverflow.com/questions/24329849/horizontal-listview-xamarin-forms

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!