Xamarin.Forms Horizontal Listview Explained

The greatest advantage of using Xamarin Forms is obviously the Binding system and the viewmodels. Especially, collections of data fits perfectly with ListViews allowing views prototyping and decoupling of views and models.

Quite often you need to show List of elements in a row, perhaps with a scrolling pane. For instance, you are trying to show an horizontal list of images or buttons which are not predetermined, but changes on user inputs or remote response.

If you are getting started with Xamarin.Forms documentation really not provide any info about Horizontal ListViews and you think they can’t be done, so you start browsing the Forum and Stackoverflow, which quite often redirect you to download a component, to write Platform specific code. Things mess up quite soon.

Fortunately, your search is over. You can make Horizontal ListViews with Bindings without doing much more than write few Xaml rows of code. Let’s go understand the logic.

Horizontal ListViews in Xaml basics

First, you have to know that each element in Xaml derive from base class that has Rotation property.

  • Rotation property is used to get and set the current Rotation of the element.

First step to create an Horizontal ListView is Rotate 270 degrees (for left to right) or 90 degrees (for right to left) and the inner View element should compensate this rotation as follows:

<ListView Rotation="270" ItemSource="{Binding Items}">
 <ListView.ItemTemplate>
  <DataTemplate>
   <ViewCell>
    <ContentView Rotation="90">
     <Image Source="{Binding Source}"></Image>
    </ContentView>
   </ViewCell>
  </DataTemplate>
 </ListView.ItemTemplate>
</ListView>

If you try this code you can see that dimensions are all messed up. The problem here is that listview sizes are calculated before rotation. If your list view is wider than taller you’ll probably see it floating vertically on other elements of the page. This is not the required behavior.

Let’s see how to fix layout.

Fixing Horizontal ListView Layout

The trick here is all about wrapping the ListView in a container and constraint the ListView to match conteiner bounds.

The element in Xamarin.Forms to do this is the Relative Layout.

First, we wrap the ListView in a RelativeLayout element and set the Layout Height to the desired height:

<RelativeLayout HeightRequest="60">
 <ListView Rotatation="270" ItemSource="{Binding Items}" RowHeight="60">
   ....
 </ListView>
</RelativeLayout>

In this example we will show square images, so we’ll also set RowHeight in ListView equal to RelativeLayout Height. Note that as the ListView is rotated the ListView.RowHeight property describe how wide the element is, while RelativeLayout.HeightRequest property describe how tall the element is. Just not get confused with rotation and names.

Second, we need to tell the ListView to bind to RelativeLayout bounds. This is possible setting the RelativeLayout constraints in the child element.

<RelativeLayout HeightRequest="60">
 <ListView Rotatation="270" ItemSource="{Binding Items}" RowHeight="60"
 RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=0.5, Constant=-30}"
 RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=-0.5, Constant=30}"
 RelativeLayout.WidthConstraint="{ConstraintExpression Type=Constant, Constant=60}"
 RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=1}">
   ....
 </ListView>
</RelativeLayout>

With XConstraint and YConstraint we adjust ListView X,Y anchors, then we set its Width (don’t forget it’s rotated so it correspond to how tall is shown) to a constant equal to parent height and we set its Height (again its shown width) to its parent width.

If you run this code now you should see the ListView much better. But probably you won’t see any element as they are now shifted out of the visible pane.

Last, indeed, we need to translate the content view on the X axis and make sure that images will fit the available viewport. Hereafter the whole code:

<RelativeLayout HeightRequest="60">
 <ListView Rotatation="270" ItemSource="{Binding Items}" RowHeight="60" SeparatorVisibility="None"
 RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=0.5, Constant=-30}"
 RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=-0.5, Constant=30}"
 RelativeLayout.WidthConstraint="{ConstraintExpression Type=Constant, Constant=60}"
 RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=1}">
  <ListView.ItemTemplate>
   <DataTemplate>
    <ViewCell>
     <ContentView Rotatation="90" Padding="1" TranslationX="60">
      <Image Source="{Binding Source}" HeightRequest="58" WidthRequest="58" Aspect="AspectFill"></Image>
     </ContentView>
    </ViewCell>
   </DataTemplate>
  </ListView.ItemTemplate>
 </ListView>
</RelativeLayout>

Here you are! Your Horizontal ListView for Xamarin.Forms in XAML is ready

You can now play with Rotation, Width and Height to obtained the desired effect. Just don’t forget that ListView Width and Height refers to element Width and Height and do not take in consideration that you have Rotate the element.

If you have downloaded strange components get rid of them, notwithstanding if you have written a fantastic code and you want to share just put a comment below. We are keen to know about other solutions for the Best Horizontal ListView in Xamarin.Forms.

Annunci

25 commenti Aggiungi il tuo

  1. raja ha detto:

    Your code doest wok

    Mi piace

  2. rositacabrera05 ha detto:

    Thanks, good contribution

    Mi piace

  3. ivan ha detto:

    Yo buddy, your example code is full of bad typos 😀 ❤

    Liked by 1 persona

    1. lucazepfiro ha detto:

      sorry 🙂 send coorection I’m glad to correct!

      Mi piace

  4. Armando Marin ha detto:

    Thanks!!, very useful, I was looking for a lot and this solution is nice.

    Mi piace

  5. Luca ha detto:

    Luca buonasera,
    mi sto avvicinando al mondo Xamarin Forms e vorrei creare una pagina con il dettaglio di un immobile e sotto una image gallery; per fare questo ho trovato il tuo esempio molto interessante ma non riesco ad usarlo causa vari errori in esecuzione.
    Avresti un esempio più esteso da mostrarmi?
    Ti ringrazio..

    Luca

    Mi piace

    1. lucazepfiro ha detto:

      Ciao Luca, non aggiornavo il blog da un po’, se ti serve scrivimi pure per mail, sarò felice di aiutarti

      Mi piace

  6. Manoj ha detto:

    The above code is not working at my end. Data is not visible and also exception is thrown as below…
    Xamarin.Forms.Xaml.XamlParseException: Position 46:21. Cannot assign property “Rotation”: Property does not exists, or is not assignable, or mismatching type between value and property
    at Xamarin.Forms.Xaml.ApplyPropertiesVisitor.SetPropertyValue(Object xamlelement, XmlName propertyName, Object value, Object rootElement, INode node, HydratationContext context, IXmlLineInfo lineInfo)
    at Xamarin.Forms.Xaml.ApplyPropertiesVisitor.Visit(ValueNode node, INode parentNode)
    at Xamarin.Forms.Xaml.ValueNo

    How can i get working listview with horizontal scroll. Also how to display multiple items in that view as right now you are showing only single image.
    Please help me to solve this issue.

    Thanks

    Mi piace

    1. lucazepfiro ha detto:

      This is strange, rotation should work as it is a parent attribute. Could you share your code?

      Mi piace

  7. joo ha detto:

    Thank you 🙂 your posting helped me

    I found some typing errors.
    Rotatation => Rotation
    ItemSource => ItemsSource

    Mi piace

  8. orestesgaolin ha detto:

    It seems that there’s a typo in the snippet. I think it should be
    ItemsSource= instead ItemSource=. Similarly with Rotation (not Rotatation).

    Mi piace

    1. lucazepfiro ha detto:

      Thx! I updated the code 🙂

      Mi piace

    1. lucazepfiro ha detto:

      I’m glad to support, but I don’t speak your tongue

      Mi piace

  9. Anton ha detto:

    Have you ever tried to compile that?
    Rotatation, ItemSource ..
    and even fixed this doesn’t work..

    Mi piace

    1. lucazepfiro ha detto:

      There were a few typo, i used many times honestly. Can i help with your code?

      Mi piace

  10. Sam Nanduri ha detto:

    Very well done… One question is that the scrollbar appears on the top of the list ( when scrolling in iOS) . How can you make it come at the bottom ?

    Mi piace

    1. lucazepfiro ha detto:

      I guess that you should thing upside down and rotate counterclockwise, just make sure all stuff has the correct position

      Mi piace

  11. Sam Nanduri ha detto:

    I have used it for the MyWeather demo app by James Montemagno as a test …
    Here is the XAML for it… I created another String in my Weather.cs file to display how i wanted it ( DisplayDateFinal ). The only little issue is that the scrollbar appears on the top… It’s not a big issue, but will be nice if it appears on the bottom 😉

    [JsonIgnore]
    public string DisplayDateFinal
    {
    get
    {
    int hh = Convert.ToInt32(DateTime.Parse(Date).ToLocalTime().ToString(“hh”));
    string tt = DateTime.Parse(Date).ToLocalTime().ToString(“tt”);

    return hh.ToString()+” “+tt+”, “+ DateTime.Parse(Date).ToLocalTime().ToString(“dd MMM”);
    }
    }

    Mi piace

  12. mama mia ha detto:

    share some image screenshots…

    Mi piace

  13. Javier H ha detto:

    Man, you saved my day!!

    Mi piace

    1. lucazepfiro ha detto:

      Really good to hear! Have a great Ferragosto 😉

      Mi piace

  14. jay-ho ha detto:

    Brilliant!

    Mi piace

Rispondi

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione / Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione / Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione / Modifica )

Google+ photo

Stai commentando usando il tuo account Google+. Chiudi sessione / Modifica )

Connessione a %s...