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))
};
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))
};
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>
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>
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.
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.
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>
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:
I've not tried it, but this might be worth checking out.
https://github.com/Cheesebaron/Cheesebaron.HorizontalListView
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 :)
I have tried the mentioned "rotating" solution and besides it being an "ugly" solution, it also comes with several limitations:
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>
Till the CollectionView is out, you can use my Xamarin.Forms HorizontalListView.
It has:
As far as I know, there is 3 ways to implement this:
What about this: https://docs.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/collectionview/layout#horizontal-list
In XAML, a CollectionView can display its items in a horizontal list by setting its ItemsLayout property to HorizontalList:
<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:
<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. Please see the code: https://gist.github.com/fonix232/b88412a976f67315f915