Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Spec] CarouselView #4996

Open
rmarinho opened this issue Jan 16, 2019 · 21 comments

Comments

9 participants
@rmarinho
Copy link
Member

commented Jan 16, 2019

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.

Note: Nothing in this specification is guaranteed to be final; all features, implementations, and interfaces are subject to change.

Related issues

API

CarouselView

[EditorBrowsable(EditorBrowsableState.Never)]
public interface ICarouselViewController : IViewController
{
	void SendScrolled(double value, ScrollDirection direction);
	void SetCurrentItem(object item);
	void SetIsScrolling(bool value);
	void SetIsDragging(bool value);
}

public class CarouselView :  ItemsView, ICarouselViewController
{
	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 PeakAreaInsetsProperty = BindableProperty.Create(nameof(PeakAreaInsets), typeof(Thickness), typeof(CarouselView), default(Thickness));

	public Thickness PeakAreaInsets
	{
		get { return (Thickness)GetValue(PeakAreaInsetsProperty); }
		set { SetValue(PeakAreaInsetsProperty, value); }
	}

	public 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 LoopProperty = BindableProperty.Create(nameof(Loop), typeof(bool), typeof(CarouselView), false);

	public bool Loop
	{
		get { return (bool)GetValue(LoopProperty); }
		set { SetValue(LoopProperty, 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),
			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;
}

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
Loop 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 [API documentation/description]
DeltaX [API documentation/description]
ScrollY [API documentation/description]
DeltaY [API documentation/description]

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

IndicatorsView

public class IndicatorsView : View
{
	 public static readonly BindableProperty IndicatorsColorProperty = BindableProperty.Create(nameof(IndicatorsColor), typeof(Color), typeof(IndicatorsView), Color.Silver);

	public Color IndicatorsColor
	{
		get { return (Color)GetValue(IndicatorsColorProperty); }
		set { SetValue(IndicatorsColorProperty, value); }
	}

	public static readonly BindableProperty SelectedIndicatorColorProperty = BindableProperty.Create(nameof(SelectedIndicatorColor), typeof(Color), typeof(IndicatorsView), Color.Gray);

	public Color SelectedIndicatorColor
	{
		get { return (Color)GetValue(SelectedIndicatorColorProperty); }
		set { SetValue(SelectedIndicatorColorProperty, value); }
	}

	public static readonly BindableProperty IndicatorsShapeProperty = BindableProperty.Create(nameof(IndicatorsShape), typeof(IndicatorsShape), typeof(IndicatorsView), IndicatorsShape.Circle);

	public IndicatorsShape IndicatorsShape
	{
		get { return (IndicatorsShape)GetValue(IndicatorsShapeProperty); }
		set { SetValue(IndicatorsShapeProperty, value); }
	}

	public static readonly BindableProperty CountProperty = BindableProperty.Create(nameof(Count), typeof(int), typeof(IndicatorsView), default(int));

	public int Count
	{
		get => (int)GetValue(CountProperty);
		set => SetValue(CountProperty, value);
	}

	 public static readonly BindableProperty MaxVisibleCountProperty = BindableProperty.Create(nameof(MaxVisibleCount), typeof(int), typeof(IndicatorsView), -1);

	public int MaxVisibleCount
	{
		get => (int)GetValue(MaxVisibleCountProperty);
		set => SetValue(MaxVisibleCountProperty, value);
	}

	public static readonly BindableProperty PositionProperty = BindableProperty.Create(nameof(Position), typeof(int), typeof(IndicatorsView), default(int), BindingMode.TwoWay, propertyChanged: OnPositionPropertyChanged);

	public int Position
	{
		get => (int)GetValue(PositionProperty);
		set => SetValue(PositionProperty, value);
	}

	public event EventHandler<PositionChangedEventArgs> PositionChanged;
}

Properties

API Description
IndicatorsColor Color of the indicators
SelectedIndicatorColor Color of the indicator that shows the selected item
IndicatorShape Shape to render on Indicator
Count Number of indicators
MaxVisibleCount Number of visible indicators, defaults to -1 so Count is used
Position Current selected indicator index

IndicatorShape

Specify how the Indicator should look, Circle or Square

public enum IndicatorShape
{
    Circle,
    Square
}

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

Backward Compatibility

We should make sure there's no conflicts with old versions of CarouselView created by us or other.

Difficulty :

High

@pauldipietro pauldipietro added this to New in Triage Jan 16, 2019

@rmarinho rmarinho removed this from New in Triage Jan 16, 2019

@andreinitescu

This comment has been minimized.

Copy link
Contributor

commented Jan 16, 2019

Just a thought, once CollectionView is released and fully stabilized, couldn't it be used to create a carousel view easily?

Except the pager, CollectionView has all the features for displaying a carousel (item virtualization, snapping, swiping, item template, etc.).
To add and create the pager, one can put have a Grid with a CollectionView and a bindable layout as a pager. The pager can be a linear StackLayout with ItemsSource of a collection of booleans and a DataTemplateSelector to show some images to be filled or empty.

The carousels can look different, the pager can be positioned differently, some have it at the bottom, some at the top, vertical distance to the where pages slide can be different, some carousels show a text displayed for every page (which is not inside the carousel items, it's above or below the pager), or have border around the actual container where pages slide.

But if you want to provide and support this out of the box, this can very cool too.

@rmarinho

This comment has been minimized.

Copy link
Member Author

commented Jan 16, 2019

Hi @andreinitescu yes we will be using the same core from CollectionView, this will just augment some more properties.

You are right one could have lots of ways of creating the pager etc.. Users want it to work out of the box, so the idea is to add support for the pager, styling the pager and possible some arrows to move on the side.

Thanks for your feedback.

@SamuelDebruyn

This comment has been minimized.

Copy link

commented Jan 16, 2019

Typo: IndicatoraVisibilityProperty

@mattleibow

This comment has been minimized.

Copy link
Contributor

commented Jan 16, 2019

Same with IndicatorsVisibility - probably doesn't need the s, unless there can be multiple indicators at a time? If it can have multiple, then maybe we sould think about what it would mean to show/hide individual ones?

@mattleibow

This comment has been minimized.

Copy link
Contributor

commented Jan 16, 2019

I also see we have a selected and a deselected indicator, maybe we should merge the IndicatorShape into this? What if i want to have a small dot for the default, and a bigger one for the selected? We could have a:

public IndicatorAppearance Indicator { get; set; }
public IndicatorAppearance SelectedIndicator { get; set; }
class IndicatorAppearance {
    public Color TintColor { get; set; }
    public IndcatorShape Shape { get; set; }
}

That might be harder to write in XAML, but then we can just split the properties out so there would be 4 properties - 2 per indicator?

I see there is also the indicator template - which is probably better than just a basic shape. But, what does the shape do if I specify both? I suppose the shape is more of a quick - use dots - without having to create a full view. We just need to specify a rule that determines the order of usage: first check template, else use shape.

@mattleibow

This comment has been minimized.

Copy link
Contributor

commented Jan 16, 2019

I think the Loop property may be confusing - maybe Wrap or AllowWrap is better? I also note that it (along with the animation property) does not have a dependency property?

@mattleibow

This comment has been minimized.

Copy link
Contributor

commented Jan 16, 2019

ArrowsVisibility probably should not be a boolean as the words imply that there is a choice - like the indicators type. We may want to use a ArrowsVisible.

Another thing comes to mind, would we want to control the position of the arrows? If I am doing a vertically scrolling list, would i want to put the arrows at the top and bottom? How would one control the orientation of the scroll? This may not be relevant depending on the answer, but what about ArrowDirection: Horizontal, Vertical, None? (Chances are the scroll orientation dictates the position, but just checking)

I see we only have 1 arrow template, how do we support the forward/back style? What if I want a big arrow for next, but a small one for back (because we never go back in life) :).

@mattleibow

This comment has been minimized.

Copy link
Contributor

commented Jan 16, 2019

With regards to arrows and indicators, would we want to use images out the box? I may have a simple carousel and just want to replace the images for the arrows? We do have the new font image source that will be great for many of these things. Especially for the indicators as well - there are fonts that have all the bits that we need - without resorting to embedding images or having multiple layouts just to add an image view.

this reminds me that I still need to get back to #4915 with all the changes there for something like this

@davidortinau

This comment has been minimized.

Copy link
Contributor

commented Jan 17, 2019

Need:

  • a SelectionChanged Command.
  • direction of scroll (as @mattleibow mentions)
  • scroll events to be able to apply transforms

carousel_alexa_vertical

  • offsets and view point (offset)
  • set number of elements to view on screen at once and/or a viewport to be able to achieve something with items peeking in from the sides

2019-01-16_18-08-16-1

  • IndicatorVisibility isn't enough. How do I position over the top of my content in a chosen position?

carousel_rei

@mattleibow

This comment has been minimized.

Copy link
Contributor

commented Jan 17, 2019

Maybe this is what @davidortinau said, but the ability to control the separator gap size asa well as scaling differences with the visible page. This control is pretty good: https://github.com/nicklockwood/iCarousel. Items may have different sizes, and may change size as they get nearer the selection. There is also this: https://www.syncfusion.com/xamarin-ios-ui-controls/carousel-view 😄

@andreinitescu

This comment has been minimized.

Copy link
Contributor

commented Jan 17, 2019

There's also a question how to control the viewport/camera in such a way it looks good on a table in landscape. It won't look good if the currently selected item is huge.

@samhouts samhouts added this to To do in Sprint 148 Jan 18, 2019

@rmarinho

This comment has been minimized.

Copy link
Member Author

commented Jan 23, 2019

Hi everyone thanks for the feedback I have playing a little bit with the feedback and updated the spec.

Some of the changes are:

  • CarouselView shares same implementation with SelectableItemsView, when the user swipes and moves the position of the item, we change the SelectedItem, CarouselView will sync it's position by listen for SelectedItem changes.

  • Moving Indicators to its own control, with BP for Position and Count one could use it to anything it wants, to link to a Carousel (or any SelectableItemsView) just use ItemsSourceBy to specify a reference, we also drop IndicatorTemplate this could be achieve it the users want with a BindableLayout.

  • Added Scrolled event with Direction and NewValue and Delta.. I need to double check if this is enough

I think we need a VisibleItems int and or maybe a HintNextItems that would peek the next , still not sure, playing with some concepts to see what feels better and most common.

I also have been playing with the spec in this branch https://github.com/xamarin/Xamarin.Forms/tree/spec-carousel

@hartez I refactor some stuff to make it easy to use between platforms, please take a look give me your thoughts.

Thanks you all, keep that feedback coming.

@rmarinho

This comment has been minimized.

Copy link
Member Author

commented Jan 23, 2019

I also am trying to figure how will handle Something like MaxItems on the IndicatorsView and how that will relate with Position

@andreinitescu

This comment has been minimized.

Copy link
Contributor

commented Jan 23, 2019

Will the CarouselView be able to use a custom layout to draw the items? For example in order to draw a 3D carousel like in the examples above. If yes, how?

@rmarinho rmarinho referenced this issue Jan 23, 2019

Open

[Feature] CarouselView #5044

0 of 3 tasks complete

@samhouts samhouts added this to In Progress in v3.5.0 Jan 23, 2019

@samhouts samhouts moved this from To do to In progress in Sprint 148 Jan 23, 2019

@hartez

This comment has been minimized.

Copy link
Member

commented Jan 29, 2019

@rmarinho Per #4681, we are adding ItemSpacing to CollectionView at a lower level, so you would get that in CarouselView for free. I think you can probably remove it from this spec.

@rmarinho

This comment has been minimized.

Copy link
Member Author

commented Jan 29, 2019

@hartez does IsScrolling and IsDragging something we would consider for ItemsView ?

@rmarinho

This comment has been minimized.

Copy link
Member Author

commented Feb 1, 2019

Updated the spec with the Padding property so we can give insets to viewport , we could use this to allow other items to Peek items, we might need to had a ClipToBounds.
Also introduce known VisualStates for the ItemTemplates of CarouselView this will allow users to perform visual changes and with some enhancements to VSM allow to easily style and animate CarouselView items.

added

API Description
Padding Set the viewport insets, this will allow to "peek" items
VSM 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
@rmarinho

This comment has been minimized.

Copy link
Member Author

commented Feb 1, 2019

Example achieve with the above :

Set Padding of 60 in left and right will allow to "Peek" the items

	var carouselView = new CarouselView
	{
		ItemTemplate = itemTemplate
		HeightRequest = 500,
		Padding = new Thickness(60,0,60,0)
	};

Setting the VSM states to default the opacity

<Grid xmlns="http://xamarin.com/schemas/2014/forms" Padding="10,0,10,0" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.ExampleTemplateCarousel">
    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup x:Name="CarouselViewStates">
            <VisualState x:Name="CurrentItem">
                <VisualState.Setters>
                    <Setter Property="Opacity" Value="1" />
                </VisualState.Setters>
            </VisualState>
            <VisualState x:Name="PreviousItem">
                <VisualState.Setters>
                    <Setter Property="Opacity" Value="0.7" />
                </VisualState.Setters>
            </VisualState>
            <VisualState x:Name="NextItem">
                <VisualState.Setters>
                    <Setter Property="Opacity" Value="0.7" />
                </VisualState.Setters>
            </VisualState>
			  <VisualState x:Name="VisibleItem">
                <VisualState.Setters>
                    <Setter Property="Opacity" Value="0.6" />
                </VisualState.Setters>
            </VisualState>
            <VisualState x:Name="DefaultItem">
                <VisualState.Setters>
                    <Setter Property="Opacity" Value="0.5" />
                </VisualState.Setters>
            </VisualState>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>
    <Frame x:Name="frame" HasShadow="True" Padding="0" HorizontalOptions="Center" VerticalOptions="Center">
        <Image Source="cardBackground" InputTransparent="true" Aspect="AspectFit" />
    </Frame>
</Grid>

CarouselView works with Gestures on the templates to make cool animations like the remove you see above.

public partial class ExampleTemplateCarousel : Grid
	{
		double initialY = -1;
		bool delete;
		double maxYScroll = 300;
		double diffYScroll = -150;
		double minYScroll = -30;

		public ExampleTemplateCarousel()
		{
			InitializeComponent();

			var gesture = new PanGestureRecognizer();

			gesture.PanUpdated += (sender, e) =>
			{
				if (e.StatusType == GestureStatus.Started)
				{
					initialY = Y;
				}

				if (e.StatusType == GestureStatus.Running)
				{
					if (e.TotalY < minYScroll)
					{
						var scaledValue = 1 - (Math.Abs(e.TotalY) / maxYScroll);
						this.ScaleTo(0.9);
						this.FadeTo(scaledValue);
						this.TranslateTo(X, Y + e.TotalY);
					}
					if (e.TotalY < diffYScroll)
					{
						delete = true;
					}
				}

				if (e.StatusType == GestureStatus.Completed || e.StatusType == GestureStatus.Canceled)
				{
					if (delete)
					{
						this.FadeTo(0.1);
						this.TranslateTo(X, Y - 1000);
						MessagingCenter.Send<ExampleTemplateCarousel>(this, "remove");
					}
					else
					{
						this.ScaleTo(1);
						this.FadeTo(1);
						this.TranslateTo(X, initialY);
					}
				}
			};
			GestureRecognizers.Add(gesture);
		}
	}

ezgif-5-3b93ce491170

States are not fully implemented in the demo above this is just to show the possibilities

@modplug

This comment has been minimized.

Copy link

commented Feb 4, 2019

One thing I would like to see supported is to be able to set SelectedItem to the last item in the collection upon an ItemsSource change or a reset action for INotififyCollectionChanged.

An example would be a collection of months within a year and you want to start at the last month and navigate "backwards in time".

I've actually run into this issue with two apps recently and my "fix" has been to wait until the CarouselView has finished rendering before setting SelectedItem to the last item in the source collection. In reality this is not a fix, just an ugly workaround.

@samhouts samhouts added this to In Progress in Enhancements Feb 5, 2019

@samhouts samhouts removed this from In Progress in Enhancements Feb 5, 2019

@rmarinho

This comment has been minimized.

Copy link
Member Author

commented Feb 15, 2019

Yesterday, 14/2/19, we had our first design review meeting for this spec.

We discussed most of the public API of CarouselView and IndicatorsView here's the feedback and changes that came from that:

CarouselView

  • Drop Padding from the CarouselView and replace it for it's own property that express better what it does, PeakAreaInsets .

  • Change NumberOfVisibleItems to NumberOfSideItems , instead of worrying about even and odd numbers and how that works to express how many items are visible on screen, user can express the number of items on the side he wants visible , it defaults to 0. So only 1 item will show on screen, if you set NumberOfSideItems = 1 then 3 items will show on screen.

  • Rename AnimateTransition to IsScrollAnimated

  • Drop ScrollDirectionEventArgs and instead just extend the existing ScrollEventArgs with DeltaX and DeltaY properties,

IndicatorsView
Keep it simple for now, users that want templates and more fancy stuff could just use a BindableLayout , we might add an Interface to allow to be user to "mimic the IndicatorsView mor easily.

  • Rename and drop "Tint" from IndicatorsTintColor to IndicatorsColor and SelectedIndicatorTintColor to SelectedIndicatorColor

  • Add MaxItemCount this will allow users when "hook" to a CarouselView ItemsSource we could override the number of visible indicators shown for large collections. Defaults to -1 so Count is used.

We are going to schedule another meeting soon to discuss more issues and do a 2nd review on the API. here are the topics that will be covering in the next meeting and that anyone can feel free to comment on the spec and give feedback.

  • API (should Loop/Wrap be a BP, do we need ICarouselViewController)

  • 3D layout options / enum mode - CoverFlowItemsLayout and StackedItemsLayout

  • Scrolling
    Scroll offset attached property , CurrentOffsetOfView
    GetScrollOffSetForView(view)
    GetViewForScrollOffSet(double)
    Specific to Carousel
    ScrollOffSetFromCurrentItemForPosition(int)

  • Discuss behaviors, sizing and edge cases
    SelectedItem and Position sync
    SelectedItem and ItemsSource = null

  • Discuss VisualStateManager States for CarouselView
    DefaultItemVisualState = "DefaultItem"; - Initial State when template is inflated
    CurrentItemVisualState = "CurrentItem"; State set as soon as the item is selected and visible on the screen
    NextItemVisualState = "NextItem"; State set to the next item after the selected item if it's visible on the screen
    PreviousItemVisualState = "PreviousItem";State set to the previous item before the selected item if it's visible on the screen
    VisibleItemVisualState = "VisibleItem"; State set as soon as the item is visible on the screen and not Curren, Next or Previous

  • Minimal viable API

  • Extra properties to discuss
    DecelerationRate - the inertia it takes to snap
    CenterCurrentItem - bool
    SlideShowTimer - timespan > 0

  • Extra Helper methods to discuss
    GetViewForPosition
    GetPositionForView

Spec
Spec folder - inside our repo? where , template?

@samhouts samhouts added this to To do in Sprint 149 via automation Feb 19, 2019

@samhouts samhouts moved this from To do to In progress in Sprint 149 Feb 19, 2019

@IgorKravchenko10

This comment has been minimized.

Copy link

commented Feb 24, 2019

Can you please provide properties Position and IsSwipeEnabled as soon as possible? I have downloaded last XF prerelease version and its CarouselView conflicted with old CarouselView. But I need new CarouselView with Position and IsSwipeEnabled, these two properties are very needed for developers.
Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.