-
Notifications
You must be signed in to change notification settings - Fork 1.9k
[Spec] CarouselView #4996
Description
CarouselView
CarouselView is a concept used in a lot of mobile applications. We already had a CarouselPage
since the initial XF version, but that only supported Pages and didn't support virtualisation. Based on the new CollectionView we are introducing CarouselView that allows to create performant CarouselView's that could be snap to position, swiped and provide position and paging info.
We are looking at other existing versions try to have a full feature set to make our users happy, this will be allowing them to specify scroll direction, position, spacing between items , how the pager dot works and feels.
CarouselView will always have all items sized to fit the viewport and taking in account the visible items on each side the user specified, and all items will have the same size.
CarouselView must easily integrate with IndicatorsView
#6577
Note: Nothing in this specification is guaranteed to be final; all features, implementations, and interfaces are subject to change.
Related issues
- IndicatorsView [Spec] IndicatorsView #6577
- [Enhancement] CollectionView item spacing #4681
- https://github.com/xamarin/Xamarin.Forms.CarouselView/blob/master/txt/src/carouselView/dev/Shared/CarouselView.cs
API
CarouselView
public class CarouselView : ItemsView
{
public const string CurrentItemVisualState = "CurrentItem";
public const string NextItemVisualState = "NextItem";
public const string PreviousItemVisualState = "PreviousItem";
public const string VisibleItemVisualState = "VisibleItem";
public const string DefaultItemVisualState = "DefaultItem";
public static readonly BindableProperty PeekAreaInsetsProperty = BindableProperty.Create(nameof(PeekAreaInsets), typeof(Thickness), typeof(CarouselView), default(Thickness));
public Thickness PeekAreaInsets
{
get { return (Thickness)GetValue(PeekAreaInsetsProperty); }
set { SetValue(PeekAreaInsetsProperty, value); }
}
static readonly BindablePropertyKey IsScrollingPropertyKey = BindableProperty.CreateReadOnly(nameof(IsScrolling), typeof(bool), typeof(CarouselView), false);
public static readonly BindableProperty IsScrollingProperty = IsScrollingPropertyKey.BindableProperty;
public bool IsScrolling => (bool)GetValue(IsScrollingProperty);
public static readonly BindablePropertyKey IsDraggingPropertyKey = BindableProperty.CreateReadOnly(nameof(IsDragging), typeof(bool), typeof(CarouselView), false);
public static readonly BindableProperty IsDraggingProperty = IsDraggingPropertyKey.BindableProperty;
public bool IsDragging => (bool)GetValue(IsDraggingProperty);
public static readonly BindableProperty IsBounceEnabledProperty =
BindableProperty.Create(nameof(IsBounceEnabled), typeof(bool), typeof(CarouselView), true);
public bool IsBounceEnabled
{
get { return (bool)GetValue(IsBounceEnabledProperty); }
set { SetValue(IsBounceEnabledProperty, value); }
}
public static readonly BindableProperty IsLoopEnabledProperty = BindableProperty.Create(nameof(IsLoopEnabled), typeof(bool), typeof(CarouselView), false);
public bool IsLoopEnabled
{
get { return (bool)GetValue(IsLoopEnabledProperty); }
set { SetValue(IsLoopEnabledProperty, value); }
}
public static readonly BindableProperty IsSwipeEnabledProperty = BindableProperty.Create(nameof(IsSwipeEnabled), typeof(bool), typeof(CarouselView), true);
public bool IsSwipeEnabled
{
get { return (bool)GetValue(IsSwipeEnabledProperty); }
set { SetValue(IsSwipeEnabledProperty, value); }
}
public static readonly BindableProperty IsScrollAnimatedProperty =
BindableProperty.Create(nameof(IsScrollAnimated), typeof(bool), typeof(CarouselView), true);
public bool IsScrollAnimated
{
get { return (bool)GetValue(IsScrollAnimatedProperty); }
set { SetValue(IsScrollAnimatedProperty, value); }
}
public static readonly BindableProperty NumberOfSideItemsProperty =
BindableProperty.Create(nameof(NumberOfSideItems), typeof(int), typeof(CarouselView), 0);
public int NumberOfSideItems
{
get { return (int)GetValue(NumberOfSideItemsProperty); }
set { SetValue(NumberOfSideItemsProperty, value); }
}
public static readonly BindableProperty PositionProperty =
BindableProperty.Create(nameof(Position), typeof(int), typeof(CarouselView), default(int), BindingMode.TwoWay,
propertyChanged: PositionPropertyChanged);
public static readonly BindableProperty PositionChangedCommandProperty =
BindableProperty.Create(nameof(PositionChangedCommand), typeof(ICommand), typeof(CarouselView));
public static readonly BindableProperty PositionChangedCommandParameterProperty =
BindableProperty.Create(nameof(PositionChangedCommandParameter), typeof(object),
typeof(CarouselView));
public int Position
{
get => (int)GetValue(PositionProperty);
set => SetValue(PositionProperty, value);
}
public ICommand PositionChangedCommand
{
get => (ICommand)GetValue(PositionChangedCommandProperty);
set => SetValue(PositionChangedCommandProperty, value);
}
public object PositionChangedCommandParameter
{
get => GetValue(PositionChangedCommandParameterProperty);
set => SetValue(PositionChangedCommandParameterProperty, value);
}
public static readonly BindableProperty CurrentItemProperty =
BindableProperty.Create(nameof(CurrentItem), typeof(object), typeof(CarouselView), default(object), BindingMode.TwoWay, propertyChanged: CurrentItemPropertyChanged);
public static readonly BindableProperty CurrentItemChangedCommandProperty =
BindableProperty.Create(nameof(CurrentItemChangedCommand), typeof(ICommand), typeof(CarouselView));
public static readonly BindableProperty CurrentItemChangedCommandParameterProperty =
BindableProperty.Create(nameof(CurrentItemChangedCommandParameter), typeof(object), typeof(CarouselView));
public object CurrentItem
{
get => GetValue(CurrentItemProperty);
set => SetValue(CurrentItemProperty, value);
}
public ICommand CurrentItemChangedCommand
{
get => (ICommand)GetValue(CurrentItemChangedCommandProperty);
set => SetValue(CurrentItemChangedCommandProperty, value);
}
public object CurrentItemChangedCommandParameter
{
get => GetValue(CurrentItemChangedCommandParameterProperty);
set => SetValue(CurrentItemChangedCommandParameterProperty, value);
}
public event EventHandler<CurrentItemChangedEventArgs> CurrentItemChanged;
public event EventHandler<PositionChangedEventArgs> PositionChanged;
public event EventHandler<ScrolledEventArgs> Scrolled;
//Methods to be called by the platforms
void SendScrolled(double value, ScrollDirection direction);
void SetCurrentItem(object item);
void SetIsScrolling(bool value);
void SetIsDragging(bool value);
}
Properties
API | Description |
---|---|
CurrentItem | Current item visible and centered on the CarouselView |
Position | Current position of the current item in the collection, when changed raises PositionChanged should also sync with CurrentItem |
IsLoopEnabled | Specify if when arriving to last source position we should show next the first position |
IsScrollAnimated | Specify if should see animation when changing position or selected item |
IsSwipeEnabled | If swipe left and right are enable to switch times |
NumberOfSideItems | Number of visible items on each side of the current item , defaults to 0 |
IsBounceEnabled | If the CarouselView bounces when reaching the end of the list |
IsDragging | Readonly that is True when the user is interacting and dragging the carousel |
IsScrolling | Readonly that is True when the CarouselView is being scrolled by changing the position value |
PeakAreaInsets | Set the viewport insets, this will allow to "peek" items |
VisualStateManager States | Description |
---|---|
CurrentItemVisualState | VisualState set for when a view is set as CurrentItem and visible on screen |
NextItemVisualState | VisualState set for when a view is visible on screen and next the current item |
PreviousItemVisualState | VisualState when a view is on screen and before the current item |
VisibleItemVisualState | VisualState when a view is visible on screen but not Next,Previous or Current state |
DefaultItemVisualState | VisualState default when a view is created initially |
Events
API | Description |
---|---|
Scrolled | Fires when the carousel is scrolling |
PositionChanged | [API documentation/description] |
CurrentItemChanged | [API documentation/description] |
CurrentItemChangedEventArgs
public class CurrentItemChangedEventArgs : EventArgs
{
public object PreviousItem { get; }
public object CurrentItem { get; }
internal CurrentItemChangedEventArgs(object previousItem, object currentItem)
{
PreviousItem = previousItem;
CurrentItem = currentItem;
}
}
Properties
API | Description |
---|---|
PreviousItem | Get's the previous item. |
CurrentItem | Get's the current item. |
Extend ScrolledEventArgs
//extend existing ScrolledEvent args with new Ctor and DeltaX and DeltaY properties
public class ScrolledEventArgs : EventArgs
{
public ScrolledEventArgs(double scrollX, double scrollY, double deltaX, double deltaY)
{
ScrollX = scrollX;
ScrollY = scrollY;
DeltaX = deltaX;
DeltaY = deltaY;
}
public double ScrollX { get; private set; }
public double ScrollY { get; private set; }
public double DeltaX { get; private set; }
public double DeltaY { get; private set; }
}
Properties
API | Description |
---|---|
ScrollX | Get's the current scroll x offset |
DeltaX | Get's the current delta x from the last scroll event |
ScrollY | Get's the current scroll y offset |
DeltaY | Get's the current delta y from the last scroll event |
PositionChangedEventArgs
public class PositionChangedEventArgs : EventArgs
{
public int PreviousPosition { get; }
public int CurrentPosition { get; }
}
Properties
API | Description |
---|---|
PreviousPosition | Gets the previous position before the position changed. |
CurrentPosition | Gets the current position |
3D and Custom layouts
Users can achieve other layouts in the future we can provide a CoverFlowItemsLayout
and a StackedItemsLayout
public class CoverFlowItemsLayout : ItemsLayout
{
public CoverFlowItemsLayout(ItemsLayoutOrientation orientation) : base(orientation)
{
}
public static readonly BindableProperty ViewPointOffSetProperty =
BindableProperty.Create(nameof(SnapPointsAlignment), typeof(double), typeof(CoverFlowItemsLayout), 2.2);
public double ViewPointOffSet
{
get => (double)GetValue(ViewPointOffSetProperty);
set => SetValue(ViewPointOffSetProperty, value);
}
public static readonly IItemsLayout Vertical = new CoverFlowItemsLayout(ItemsLayoutOrientation.Vertical);
public static readonly IItemsLayout Horizontal = new CoverFlowItemsLayout(ItemsLayoutOrientation.Horizontal);
}
public class StackedItemsLayout : ItemsLayout
{
public StackedItemsLayout(ItemsLayoutOrientation orientation) : base(orientation)
{
}
public static readonly IItemsLayout Vertical = new StackedItemsLayout(ItemsLayoutOrientation.Vertical);
public static readonly IItemsLayout Horizontal = new StackedItemsLayout(ItemsLayoutOrientation.Horizontal);
}
Scenarios
var carouselView = new CarouselView
{
ItemsSource = itemsSource,
ItemsLayout = itemsLayout,
ItemTemplate = itemTemplate,
Position = 2,
NumberofSideItems = 1
};
Backward Compatibility
We should make sure there's no conflicts with old versions of CarouselView created by us or other.
Difficulty :
High