Navigation Menu

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

CarouselView #853

Closed
wants to merge 28 commits into from
Closed

CarouselView #853

wants to merge 28 commits into from

Conversation

alexrainman
Copy link

@alexrainman alexrainman commented Apr 1, 2017

Description

Pulling CarouselView control into Xamarin.Forms.Core (As requested by Dave Ortinau)

File list

Xamarin.Forms.Core

  • CarouselView/CarouselView.cs
  • CarouselView/CarouselViewOrientation.cs
  • CarouselView/IEnumerableExtensions.cs
  • CarouselView/IndicatorsShape.cs

Xamarin.Forms.Platform.Android

  • AppCompat/Resource.cs (updated)
  • CarouselView/CarouselViewRenderer.cs
  • CarouselView/CirclePageIndicator.cs
  • CarouselView/CustomViewPager.cs
  • CarouselView/DefaultPageTransformer.cs
  • CarouselView/FormsToNativeDroid.cs
  • CarouselView/IViewPager.cs
  • CarouselView/PageIndicator.cs
  • CarouselView/Tag.cs
  • CarouselView/VerticalViewPager.cs
  • Resources/layout/horizontal_viewpager.xml
  • Resources/layout/vertical_viewpager.xml
  • Resources/values/vpi__attrs.xml
  • Resources/values/vpi__colors.xml
  • Resources/values/vpi__defaults.xml
  • Resources/values/vpi__styles.xml
  • Properties/AssemblyInfo.cs (updated)

Xamarin.Forms.Platform.iOS

  • CarouselView/CarouselViewRenderer.cs
  • CarouselView/FormsToNativeiOS.cs
  • CarouselView/ViewContainer.cs
  • Properties/AssemblyInfo.cs (updated)

Xamarin.Forms.Platform.UAP

  • CarouselView/CarouselViewRenderer.cs
  • CarouselView/FlipViewControl.xaml
  • CarouselView/FlipViewControl.xaml.cs
  • CarouselView/FormsToNativeUWP.cs
  • CarouselView/Timer.cs
  • CarouselView/VerticalFlipViewControl.xaml
  • CarouselView/VerticalFlipViewControl.xaml.cs
  • Properties/AssemblyInfo.cs (updated)

ControlGallery/Xamarin.Forms.Controls (portable)

  • GalleryPages/CarouselView/CarouselPageViewModel.cs
  • GalleryPages/CarouselView/MyView.xaml
  • GalleryPages/CarouselView/MyView.xaml.cs
  • GalleryPages/CarouselViewGalleryPage.xaml
  • GalleryPages/CarouselViewGalleryPage.xaml.cs
  • CoreGallery.cs (updated)

PR Checklist

  • Tested in all platforms
  • Demo in GalleryPages

@alexrainman alexrainman changed the title CarouselView Pulling CarouselView control into Xamarin.Forms.Core Apr 1, 2017
@StephaneDelcroix
Copy link
Member

Can you explain why you'd want to do this ?

@alexrainman
Copy link
Author

You can talk with Dave Ortinau and Samantha Houts about it.

Copy link
Member

@StephaneDelcroix StephaneDelcroix left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like to understand why we're doing this.

@alexrainman
Copy link
Author

Dave contacted me about their wish to pull my CarouselView into the core. He asked me to follow a Pull Request channel for it. Thanks

@StephaneDelcroix
Copy link
Member

Great. Add that info to the PR description. thanks

@adrianknight89
Copy link
Contributor

So I take it this is not the CarouselView Xamarin was working on? What went wrong with the other one?

@alexrainman
Copy link
Author

No this is not Xamarin's one. I have been maintaining this control for a while and its a really stable piece of code with a big community behind it.

Copy link
Member

@StephaneDelcroix StephaneDelcroix left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've only reviewed the Core part so far, and if this control is considered for inclusion, it should go through the evolution forum so the public API can be discussed.

I've glanced at the renderers implementation and a few things looked weird:

  • I don't think the control reacts at every BP changes, and BP are mutable by nature. e.g. if you change the ItemTemplate, the current views doesn't refresh,
  • the renderers are adding items to the user ItemSource collection

}

// Android and iOS only
public static readonly BindableProperty InterPageSpacingProperty = BindableProperty.Create("InterPageSpacing", typeof(int), typeof(CarouselView), 0);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Platform specifics are usually set with attached BPs in PlatfromSpecifics

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you clarify?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Basically, move these platform specific properties out of the Core implementation and put them in Xamarin.Forms.Core\PlatformConfiguration\AndroidSpecific\CaourselView.cs (for example) and follow the established pattern for Platform Specifics there. Then in your renderer, you will do something like var interPageSpacing = e.NewElement.OnThisPlatform().GetInterPageSpacing() * metrics.Density; to access the values.

set { SetValue(PageIndicatorTintColorProperty, value); }
}

public static readonly BindableProperty CurrentPageIndicatorTintColorProperty = BindableProperty.Create("CurrentPageIndicatorTintColor", typeof(Color), typeof(CarouselView), Color.Gray);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

default is usually Color.Default, and the platform implementation is free to pick gray for default color, or anything else

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why indicators default color cannot be gray?

set { SetValue(ItemTemplateProperty, value); }
}

public static readonly BindableProperty PositionProperty = BindableProperty.Create("Position", typeof(int), typeof(CarouselView), 0, BindingMode.TwoWay);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you do negative values ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't the value be validated, or at least coerced ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do validate position property in platform specific code. Not negative values (collections index start in 0, don't?)


public EventHandler PositionSelected;

public Func<object, int, Task> InsertAction;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's not an easy public API to understand

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

InsertAction is not supposed to be public but, how i implement it in platform specific code then? If i can find a way to use ObservableCollection then this will go away.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Members that are only public because they need to be accessed by the renderer are typically put into ICarouselViewController interface and then implemented explicitly on the element so as to hide them from isense for app developers. We are considering a simpler solution whereby you need only add [EditorBrowsable(EditorBrowsableState.Never)] but that PR is limbo at the moment...

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got your idea but maybe i don't need those methods at all :)

{
public class CarouselViewException : Exception
{
public CarouselViewException()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure CarouselView needs its own exception subclass

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree.

{
get { return (DataTemplate)GetValue(ItemTemplateProperty); }
set { SetValue(ItemTemplateProperty, value); }
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DataTemplate inflation code should be part of the Core, not delegated to renderers

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not possible as Xamarin.Forms Views need to be added to native controls in their native representation.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the templates are inflated into a View, then that view is rendered

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't work like that. I do that exactly but, xamarin.forms view cannot be added to platform specific controls. I need to use native views. Also, the inflation/convertion is done on demand as each control use platform specific virtualization (except for UWP).

/// <summary>
/// CarouselView Interface
/// </summary>
public class CarouselView : View //Layout<View>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should inherit from ItemsView<>

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why? Platform specific controls are Views not collections.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to share the templating logic with ListView

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But why? ListView is a collection, CarouselView is not.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not requiring derivation of ListView certainly allows for a simpler implementation.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kingces95 exactly

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nobody said ListView. I said ItemsView<>. There's nothing in there you do not want.

@alexrainman
Copy link
Author

I will answer all your questions.

@alexrainman
Copy link
Author

alexrainman commented Apr 3, 2017

Stephane, this control is the result of the community collaboration and it's really stable.

  1. I can easily implement ItemTemplate property changed.

  2. Why i should inherit from ItemsView<>? As i mentioned, platform specific controls are not collections, they are Views:

Android: Android.View.Views
iOS: UIView
UWP: UserControl (FrameworkElement)

  1. I tried to use ObservableCollection as ItemsSource (so i don't need InsertAction plus InsertPage), but there's a limitation in Android where, in certain cases, you get an exception if you change the source before updating the adapter and the ViewPager.

I have an idea how i can solve this but, it will mean two things:

  • Only ObservableCollections will be supported as ItemsSource.
  • The source will need to be duplicated in Android.
  1. Sure, CarouselViewException is not needed.

  2. It's not possible to leave DataTemplate inflation to core/abstraction code as Views need to be added to native controls in their native representation.

Believe me, this the best way to do this. I has been working with each platform specific control for a while. By the way, UWP has a lot of limitations comparing to WP.

Thanks

Copy link
Contributor

@hartez hartez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple of minor issues in the Windows section.

{
public static FrameworkElement ConvertFormsToNative(Xamarin.Forms.View view, Rectangle size)
{
//var vRenderer = RendererFactory.GetRenderer (view);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these commented out intentionally? If so, they should just be removed.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Anything commented is intentional and there's a reason for that. The platform has some limitations. What is commented is the way it supposed to be :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add some brief explanation of the limitations and why the code is different for this platform? Something like "normally, we'd do X but on Windows we have to do Y because...". That way future maintainers won't waste time trying to do 'X'.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can do that :)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The biggest limitation i have in UWP is that DataTemplate doesn't support parameters like Xamarin.Forms DataTemplate does.

If UWP DataTemplate can support Func<object> as parameter, i wont need to render all the pages ahead of time. I will use a DataTemplateSelector instead and render the views on demand and use ItemsSource as FlipView source directly.


view.Layout(new Rectangle(0, 0, size.Width, size.Height));

//vRenderer.ContainerElement.Arrange(new Rect(0, 0, size.Width, size.Height));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one, too - is this intentional?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes

{
public static UIView ConvertFormsToNative(Xamarin.Forms.View view, CGRect size)
{
//var vRenderer = RendererFactory.GetRenderer (view);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this intentionally commented out?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. I also have a pending UWP reported issue to solve.

@@ -182,6 +182,12 @@
<Compile Include="..\Xamarin.Forms.Platform.WinRT\LayoutExtensions.cs">
<Link>LayoutExtensions.cs</Link>
</Compile>
<Compile Include="CarouselView\FlipViewControl.xaml.cs">
<DependentUpon>FlipViewControl.xaml</DependentUpon>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new .xaml files will need entries for their .xbf files in the UWP section of Xamarin.Forms.nuspec.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do that in my own .nuspec but i didn't touch Xamarin.Forms.nuspec

else
viewPager.Adapter.NotifyDataSetChanged();

await Task.Delay(100);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This deserves a comment.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok


viewPager.SetCurrentItem(1, Element.AnimateTransition);

await Task.Delay(100);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This deserves a comment.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok


viewPager.SetCurrentItem(newPos, Element.AnimateTransition);

await Task.Delay(100);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This deserves a comment.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will add comments to all my code. It may seems weird in Android but it's the only way to make it work.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alexrainman: In my testing of your control, these Delays were unnecessary and made the whole app hang for many seconds under load testing (i.e., adding thousands of Views to the CarouselView). I removed them and noticed no side effects.

@kingces95
Copy link
Contributor

kingces95 commented Apr 3, 2017

Not requiring CarouselView be abstracted as a IObservableCollection (and instead be a linked list) vastly simplifies the public surface area and the test matrix.

Not requiring the Android/iOS renders use RecylcerView/UICollectionView (and instead used ViewPager/UIPageViewController) vastly simplifies the implementation.

@alexrainman
Copy link
Author

Agree. Anyway, i am testing some code that will allow me to use IObservableCollection as ItemsSource but it will require lot of regression testing in Android.

@kingces95
Copy link
Contributor

Hm. I'd forgo IObservableCollection support.

Copy link
Contributor

@kingces95 kingces95 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please flesh out the test cases and automate the tests.


namespace Xamarin.Forms.Controls
{
public partial class CarouselViewGalleryPage : ContentPage
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's customary to automate the UITests. Please add labels which expose all the bindable properties instead of dumping to the debug log (e.g. position, ItemSource.Length, etc). This will allow you to add assertions in the UITest that the values are as you expect them to be. E.g. that when an item is inserted to the left of the current item that the Position BP is bumped (leaving the current item unchanged) and when to the right is not. In general, UITests should be added for every button given various states of the CarouselView (number of elements/position).

@alexrainman
Copy link
Author

alexrainman commented Apr 4, 2017

@kingces95 to support IObservableCollection (interface that doesn't exists) i have to change ItemsSource BP to ObservableCollection<object> and only that will be supported. I don't have a way to declare a property like ObservableCollection<T> or at least i don't know how.

@StephaneDelcroix
Copy link
Member

@alexrainman ListView supports observables. the ItemsSource is IEnumerable, but if the provided source is observable, we hook the events

@alexrainman
Copy link
Author

Got it.

@alexrainman
Copy link
Author

Can you point me to that implementation?

@kingces95
Copy link
Contributor

I'd vote against supporting ObservableCollection (at least at this moment).

I'm sure @alexrainman could support it and it may not even be that hard (given the use of ViewPager over RecyclerView). However, just because we can do something doesn't mean we should. Or just because we've been doing something we should continue to do it that way. Customers don't seem to miss ObservableCollection support as they're using this implementation now. Jason and Sam (and I) don't seem to care about ObservableCollection support as they've already approved the PR.

And if even if we ultimately decide to support ObservableCollection that doesn't mean it has to be done now. The implementation works as it stands. I'd vote to accept the public API for purposes of this PR and then bolt on additional features as they are requested by customers.

If we ask @alexrainman to do anything more I'd rather he add UITests for the existing surface area than add more features to it.

ObservableCollection<int> _Source;
/// <summary>
/// Images
/// </summary>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alexrainman Are these summaries needed? There are other examples in different files as well. Maybe we need to make them better or completely remove them?

@ghost
Copy link

ghost commented Jan 11, 2018

Does this need to be rebased with the updates included?

@alexrainman
Copy link
Author

Yes, i will include them before end of week.

@rmarinho
Copy link
Member

rmarinho commented Jan 22, 2018

@alexrainman i have created a branch with fixes and updates do you mind we work on that branch ? i will open a new PR with your comments, or you can even open yourself using that branch. This is already rebased on master

https://github.com/xamarin/Xamarin.Forms/tree/feature-carouselview

@alexrainman
Copy link
Author

@rmarinho by fixes and updates you mean thr latest i need to include in the PR?

@rmarinho
Copy link
Member

@alexrainman i rebased your branch on top of master, i m now looking at the code, there's a lot of stuff here that we need to clean up to be able to merge this. i recommend we work in that new branch and we will help improving the code and maybe adding more UITests etc.

@alexrainman
Copy link
Author

@rmarinho first i will update with the latest release of the control. We can start from that.

@rmarinho
Copy link
Member

@alexrainman you have another repo with the control ?

@alexrainman
Copy link
Author

@rmarinho of course. This is just a PR based on my control that has been out for couple of years. @davidortinau asked me to do the PR. You can find it here: https://github.com/alexrainman/CarouselView. Some new issues has been reported which i need to confirm.

@adrianknight89
Copy link
Contributor

adrianknight89 commented Jan 23, 2018

@alexrainman Can you update this PR (or the new branch Rui mentions) to the latest release for now and re-route the issues to XF repository once the control is merged? This way, the Xamarin team can fix the bugs themselves. My concern is that as you fix bugs listed on your repro, more will appear over time and you'll have to fix them too, and the cycle continues.

@andreinitescu
Copy link
Contributor

@hartez @alexrainman @davidortinau @jassmith Why was this PR closed? I am confused. What does it mean, is CarouselView not getting implemented in XF or? There's no comment, no follow up, this was just closed. For someone who needs CarouselView and wants to understand what's happening, this isn't helpful... Can someone please comment?

@alexrainman
Copy link
Author

@andreinitescu this has been moved to a branch. I has been sick and out for a while so that branch is not updated yet.

@alexrainman
Copy link
Author

@rmarinho i wonder why i cannot find that branch when i try to switch from master using sourcetree

@alexrainman
Copy link
Author

@rmarinho found it

@rmarinho
Copy link
Member

rmarinho commented Feb 14, 2018

The new branch will allow more flexibility to XF team and others, so we need to get that branch update with latest changes @alexrainman , instead of PR to master, you PR to that branch, that will also allow us to run the CI etc.. @andreinitescu if you can help we will need to review a lot of code on this pr, remove dead code and comments, and test it.
There's also a point where we need to refactor some code to be done on CarouselView Core and not the platforms, there's some logic there that can be unit tested on core.
So there's a lot of work to get this done, and we appreciate any help with this.

Thanks

@alexrainman
Copy link
Author

@rmarinho i will be done incorporating latest code in the new branch later today. We can start from that

@andreinitescu
Copy link
Contributor

@alexrainman is there a way to get the curent item View? It would be sweet to have something like a View CurrentView property.

@alexrainman
Copy link
Author

@andreinitescu that is not available but i think it is doable.

@andreinitescu
Copy link
Contributor

@alexrainman Thanks. Any way to do it now? I can't see it

@alexrainman
Copy link
Author

@rmarinho i am trying to merge latest code into the branch named "feature-carouselview" and i get this error:

remote: Permission to xamarin/Xamarin.Forms.git denied to alexrainman.
fatal: unable to access 'https://github.com/xamarin/Xamarin.Forms.git/': The requested URL returned error: 403

Any ideas?

@rmarinho
Copy link
Member

@alexrainman make a PR that targets the feature Carouselview branch

@stesvis
Copy link

stesvis commented Mar 20, 2018

When is this control going to be available? Is there an ETA? It would be awesome!

@shoeIT
Copy link

shoeIT commented May 8, 2018

any news on this control? Its not mergedt into XF 3.0 right ? I'm eagerly waiting for some enhancements

@RuddyOne
Copy link

Any update on this?

@alexrainman
Copy link
Author

It seems Xamarin.Forms team has decided not to include my control and build their own from scratch so, i am working on the next release.

@Babych
Copy link

Babych commented Dec 6, 2018

I faced DivideByZeroException in android devices. This issue was described here https://bugzilla.xamarin.com/show_bug.cgi?id=53382

To fix it i had to write a component where I checked if the CarouselView is visible and items source is not null. Also i had to set an ItemTemplate and an ItemsSource in the main thread.

I hope, you will fix this issue in the future.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet