-
Notifications
You must be signed in to change notification settings - Fork 72
HorizontalListView Grid And Carousel
You can find the blog post on www.sharpnado.com/a-real-horizontal-list-view/.
The HorizontalListView is presented in the Silly! app in the following repository:
https://github.com/roubachof/Xamarin-Forms-Practices
If you want to know how to use it, it's the best place to start.
public HorizontalListViewLayout ListLayout { get; set; } = HorizontalListViewLayout.Linear;
By default the layout is in Linear
mode, which means you will have only one row.
You can specify the ItemWidth
and ItemHeight
.
You can also specify ItemSpacing
and CollectionPadding
.
<renderedViews:HorizontalListView Grid.Row="3"
Margin="-16,8"
CollectionPadding="8,8"
ItemSpacing="8"
ItemHeight="144"
ItemWidth="144"
ItemsSource="{Binding SillyPeopleLoader.Result}"
SnapStyle="Center">
<renderedViews:HorizontalListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<views:SillySquareCell effects:TapCommandEffect.Tap="{Binding OnItemTappedCommand}"
effects:TapCommandEffect.TapParameter="{Binding .}"
effects:ViewEffect.TouchFeedbackColor="{StaticResource Accent}" />
</ViewCell>
</DataTemplate>
</renderedViews:HorizontalListView.ItemTemplate>
</renderedViews:HorizontalListView>
A HorizontalListView
with SnapStyle=Center
and ItemWidth/ItemHeight
set.
As you can see TapCommand
and TouchFeedbackColor
(aka Ripple) are brought to you by the awesome effects created by mrxten (https://github.com/mrxten/XamEffects). The class effects are directly integrated in the Sharpnado projects so you don't have to reference another nuget package.
You can also decide to just specify the number of column you want, the ColumnCount
property, and the ItemWidth
will be computed for you.
<renderedViews:HorizontalListView Grid.Row="3"
Margin="-16,8"
CollectionPadding="8,8"
ItemSpacing="8"
ColumnCount="2"
ItemsSource="{Binding SillyPeopleLoader.Result}"
SnapStyle="Start">
...
</renderedViews:HorizontalListView>
A HorizontalListView
with ColumnCount=2
.
You can set ListLayout
to Carousel
.
In this mode you can't specify ItemWidth
(obviously).
If you don't specify the ItemHeight
, it will be automatically computed for you.
<renderedViews:HorizontalListView Grid.Row="3"
Margin="-16,8"
CollectionPadding="8,8"
ItemSpacing="8"
ListLayout="Carousel"
ItemsSource="{Binding SillyPeopleLoader.Result}"
SnapStyle="Center">
...
</renderedViews:HorizontalListView>
A HorizontalListView
with ListLayout=Carousel
.
If you set the ListLayout
property to Grid
, you will have access to the same properties.
<renderedViews:HorizontalListView CollectionPadding="16"
ItemSpacing="8"
EnableDragAndDrop="True"
ItemWidth="110"
ItemHeight="120"
ItemsSource="{Binding SillyPeople}"
ListLayout="Grid">
<renderedViews:HorizontalListView.ItemTemplate>
<DataTemplate>
<renderedViews:DraggableViewCell x:Name="DraggableViewCell">
<ContentView>
<renderedViews:MaterialFrame Margin="4"
Padding="{StaticResource StandardThickness}"
Elevation="4">
<Frame.Triggers>
<DataTrigger Binding="{Binding Source={x:Reference DraggableViewCell}, Path=IsDragAndDropping}"
TargetType="renderedViews:MaterialFrame"
Value="True">
<Setter Property="Elevation" Value="8" />
</DataTrigger>
</Frame.Triggers>
<Grid ColumnSpacing="0" RowSpacing="0">
<Grid.RowDefinitions>
<RowDefinition Height="2*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<abstractions:CircleImage Grid.Row="0"
Style="{StaticResource SmallAvatar}"
Aspect="AspectFill"
Source="{Binding ImageUrl}" />
<Label Grid.Row="1"
Margin="{StaticResource MediumTopThickness}"
Style="{StaticResource TextSmallCaption}"
HorizontalTextAlignment="Center"
Text="{Binding Name}" />
</Grid>
</renderedViews:MaterialFrame>
</ContentView>
</renderedViews:DraggableViewCell>
</DataTemplate>
</renderedViews:HorizontalListView.ItemTemplate>
</renderedViews:HorizontalListView>
The nuget package comes also with a MaterialFrame
view with Elevation
property. Some code has been taken from Alex Dunn work.
A Grid
ListLayout
with padding and item spacing.
You can use the IsDragAndDropping
property of the DraggableViewCell
to achieve an Elevation effect while dragging your view with a simple DataTrigger
.
The ColumnCount
property works also with the grid layout.
<renderedViews:HorizontalListView CollectionPadding="8"
ItemSpacing="8"
EnableDragAndDrop="True"
ColumnCount="1"
ItemHeight="120"
ItemsSource="{Binding SillyPeople}"
ListLayout="Grid">
A Grid
ListLayout
with ColumnCount=1
.
You can achieve infinite loading really easily by using the Paginator
component, and bind it to the InfiniteListLoader
property.
All is explained here:
https://www.sharpnado.com/paginator-platform-independent/
If you want to have both drag and drop enabled and still be able to tap the item, you need to use the TapCommand
instead of the TapCommandEffect
.
It's less nice since you won't have the nice color ripple, but it will work :)
The only thing you have to do to enable drag and drop is setting EnableDragAndDrop
to true
.
Remark: You don't have to inherit from DraggableViewCell
, any ViewCell
can be dragged.
The DraggableViewCell
is useful for using triggers on the IsDragAndDropping
property (changing its background color or elevation during drag and drop for example).
You can also disable the drag and drop for certain cells thanks to the IsDraggable
property.
public static readonly BindableProperty ListLayoutProperty = BindableProperty.Create(
nameof(ListLayout),
typeof(HorizontalListViewLayout),
typeof(HorizontalListView),
HorizontalListViewLayout.Linear);
public static readonly BindableProperty TapCommandProperty = BindableProperty.Create(
nameof(TapCommand),
typeof(ICommand),
typeof(HorizontalListView));
public static readonly BindableProperty ItemsSourceProperty = BindableProperty.Create(
nameof(ItemsSource),
typeof(IEnumerable),
typeof(HorizontalListView),
default(IEnumerable<object>),
BindingMode.TwoWay);
public static readonly BindableProperty InfiniteListLoaderProperty = BindableProperty.Create(
nameof(ItemsSource),
typeof(IInfiniteListLoader),
typeof(HorizontalListView));
public static readonly BindableProperty ScrollBeganCommandProperty = BindableProperty.Create(
nameof(ScrollBeganCommand),
typeof(ICommand),
typeof(HorizontalListView));
public static readonly BindableProperty ScrollEndedCommandProperty = BindableProperty.Create(
nameof(ScrollEndedCommand),
typeof(ICommand),
typeof(HorizontalListView));
public static readonly BindableProperty CurrentIndexProperty = BindableProperty.Create(
nameof(CurrentIndex),
typeof(int),
typeof(HorizontalListView),
defaultValue: 0,
defaultBindingMode: BindingMode.TwoWay);
public static readonly BindableProperty VisibleCellCountProperty = BindableProperty.Create(
nameof(VisibleCellCount),
typeof(int),
typeof(HorizontalListView),
defaultValue: 0,
defaultBindingMode: BindingMode.TwoWay);
public static readonly BindableProperty DisableScrollProperty = BindableProperty.Create(
nameof(DisableScroll),
typeof(bool),
typeof(HorizontalListView),
defaultValue: false,
defaultBindingMode: BindingMode.TwoWay);
/// In certain scenarios, the first scroll of the list can be smoothen
/// by pre-building some views.
public int ViewCacheSize { get; set; } = 0;
public SnapStyle SnapStyle { get; set; } = SnapStyle.None;
public int ColumnCount { get; set; } = 0;
public ScrollSpeed ScrollSpeed { get; set; } = ScrollSpeed.Normal;
public bool EnableDragAndDrop { get; set; } = false;
public static readonly BindableProperty DragAndDropEndedCommandProperty = BindableProperty.Create(
nameof(DragAndDropEndedCommand),
typeof(ICommand),
typeof(HorizontalListView));
public static readonly BindableProperty IsDragAndDroppingProperty = BindableProperty.Create(
nameof(IsDragAndDropping),
typeof(bool),
typeof(HorizontalListView),
defaultValue: false);
The Android renderer is implemented with a RecyclerView
.
Padding and item spacing is computed by an extension of ItemDecoration
.
While column computing and item distribution is achieved by a custom GridLayoutManager
.
The Snap to first item is implemented with a custom LinearSnapHelper
. Drag and drop is handled by an ItemTouchHelper.Callback
.
The iOS renderer is implemented by a UICollectionView
.
Padding and item spacing are natively provided by the UICollectionViewFlowLayout
.
Snap to Center item is brought by a little trick on DecelerationEnded
callback.
Darg and drop is handled by a UILongPressGestureRecognizer
followed by calls to the xxxInteractiveMovementxxx
methods.