[Android, iOS] Fix CarouselView Issues (#7366)

* Fixed CarouselViewGalleries sample on Android

* Protect NRE setting the CurrentItem

* Fixed issue changing the ItemsSource

* Fixed issues with NumberOfSideItems and PeekAreaInsects properties on Android

* Fixed formatting

* Fix ItemSpacing issue on Android

* Fixed vertical peek insets iOS

* Center item after change ItemSpacing
Improve IsSwipeEnabled logic on Android (disable swipe but not touch)

* Update max slider value when item count is updated

* Update CarouselCodeGallery.cs

* NoOfSideItems in test page
This commit is contained in:
Javier Suárez Ruiz 2019-09-04 15:48:51 +02:00 коммит произвёл Rui Marinho
Родитель 656835123b
Коммит 79dd23edcb
19 изменённых файлов: 241 добавлений и 123 удалений

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 520 KiB

Просмотреть файл

@ -163,6 +163,7 @@
<AndroidResource Include="Resources\drawable\booksflyout.png" />
<AndroidResource Include="Resources\drawable\homeflyout.png" />
<AndroidResource Include="Resources\drawable\xamarinlogo.png" />
<AndroidResource Include="Resources\drawable\cardBackground.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\Icon.png" />

Просмотреть файл

@ -8,6 +8,8 @@ namespace Xamarin.Forms.Controls
[Preserve(AllMembers = true)]
internal class CarouselViewCoreGalleryPage : CoreGalleryPage<CarouselView>
{
private object _currentItem;
protected override void InitializeElement(CarouselView element)
{
base.InitializeElement(element);
@ -23,15 +25,19 @@ namespace Xamarin.Forms.Controls
{
base.Build(stackLayout);
var currentItemContainer = new ValueViewContainer<CarouselView>(Test.CarouselView.CurrentItem, new CarouselView { HeightRequest = 250, ItemsSource = GetCarouselItems(), ItemsLayout = GetCarouselLayout(ItemsLayoutOrientation.Horizontal), ItemTemplate = GetCarouselTemplate(), CurrentItem = _currentItem }, "CurrentItem", value => value.ToString());
var isSwipeEnabledContainer = new ValueViewContainer<CarouselView>(Test.CarouselView.IsSwipeEnabled, new CarouselView { IsSwipeEnabled = false, HeightRequest = 250, ItemsSource = GetCarouselItems(), ItemsLayout = GetCarouselLayout(ItemsLayoutOrientation.Horizontal), ItemTemplate = GetCarouselTemplate()}, "IsSwipeEnabled", value => value.ToString());
var isScrollAnimatedContainer = new ValueViewContainer<CarouselView>(Test.CarouselView.IsScrollAnimated, new CarouselView { IsScrollAnimated = false, HeightRequest = 250, ItemsSource = GetCarouselItems(), ItemsLayout = GetCarouselLayout(ItemsLayoutOrientation.Horizontal), ItemTemplate = GetCarouselTemplate() }, "IsScrollAnimated", value => value.ToString());
var numberOfSideItemsContainer = new ValueViewContainer<CarouselView>(Test.CarouselView.NumberOfSideItems, new CarouselView { NumberOfSideItems = 2, HeightRequest = 250, ItemsSource = GetCarouselItems(), ItemsLayout = GetCarouselLayout(ItemsLayoutOrientation.Horizontal), ItemTemplate = GetCarouselTemplate() }, "NumberOfSideItems", value => value.ToString());
var horizontalNumberOfSideItemsContainer = new ValueViewContainer<CarouselView>(Test.CarouselView.NumberOfSideItems, new CarouselView { NumberOfSideItems = 2, HeightRequest = 250, ItemsSource = GetCarouselItems(), ItemsLayout = GetCarouselLayout(ItemsLayoutOrientation.Horizontal), ItemTemplate = GetCarouselTemplate() }, "NumberOfSideItems", value => value.ToString());
var verticalNumberOfSideItemsContainer = new ValueViewContainer<CarouselView>(Test.CarouselView.NumberOfSideItems, new CarouselView { NumberOfSideItems = 2, HeightRequest = 250, ItemsSource = GetCarouselItems(), ItemsLayout = GetCarouselLayout(ItemsLayoutOrientation.Vertical), ItemTemplate = GetCarouselTemplate() }, "NumberOfSideItems", value => value.ToString());
var peekAreaInsetsContainer = new ValueViewContainer<CarouselView>(Test.CarouselView.PeekAreaInsets, new CarouselView { PeekAreaInsets = new Thickness(24, 12, 36, 6), HeightRequest = 250, ItemsSource = GetCarouselItems(), ItemsLayout = GetCarouselLayout(ItemsLayoutOrientation.Horizontal), ItemTemplate = GetCarouselTemplate() }, "PeekAreaInsets", value => value.ToString());
var positionContainer = new ValueViewContainer<CarouselView>(Test.CarouselView.Position, new CarouselView { Position = 2, HeightRequest = 250, ItemsSource = GetCarouselItems(), ItemsLayout = GetCarouselLayout(ItemsLayoutOrientation.Horizontal), ItemTemplate = GetCarouselTemplate() }, "Position", value => value.ToString());
Add(currentItemContainer);
Add(isSwipeEnabledContainer);
Add(isScrollAnimatedContainer);
Add(numberOfSideItemsContainer);
Add(horizontalNumberOfSideItemsContainer);
Add(verticalNumberOfSideItemsContainer);
Add(peekAreaInsetsContainer);
Add(positionContainer);
}
@ -51,6 +57,8 @@ namespace Xamarin.Forms.Controls
});
}
_currentItem = items[5];
return items;
}

Просмотреть файл

@ -1,10 +1,11 @@
using System.Collections;
using Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.SpacingGalleries;
using Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.SpacingGalleries;
using Xamarin.Forms.Internals;
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
namespace Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.CarouselViewGalleries
{
[Preserve(AllMembers = true)]
internal class CarouselCodeGallery : ContentPage
{
readonly Label _scrollInfoLabel = new Label();
@ -46,13 +47,17 @@ namespace Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.CarouselVi
ItemsLayout = itemsLayout,
ItemTemplate = itemTemplate,
Position = 2,
// NumberOfSideItems = 1,
//NumberOfSideItems = 1,
Margin = new Thickness(0,10,0,40),
PeekAreaInsets = new Thickness(30,0,30,0),
BackgroundColor = Color.LightGray,
AutomationId = "TheCarouselView"
};
if (orientation == ItemsLayoutOrientation.Horizontal)
carouselView.PeekAreaInsets = new Thickness(30, 0, 30, 0);
else
carouselView.PeekAreaInsets = new Thickness(0, 30, 0, 30);
carouselView.Scrolled += CarouselView_Scrolled;
layout.Children.Add(carouselView);
@ -78,12 +83,18 @@ namespace Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.CarouselVi
{
Maximum = 100,
Minimum = 0,
Value = 30
Value = 30,
WidthRequest = 100,
BackgroundColor = Color.Pink
};
padi.ValueChanged += (s, e) => {
var peek = padi.Value;
carouselView.PeekAreaInsets = new Thickness(peek, 0, peek, 0);
if (orientation == ItemsLayoutOrientation.Horizontal)
carouselView.PeekAreaInsets = new Thickness(peek, 0, peek, 0);
else
carouselView.PeekAreaInsets = new Thickness(0, peek, 0, peek);
};
stckPeek.Children.Add(padi);
@ -107,7 +118,8 @@ namespace Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.CarouselVi
{
_scrollInfoLabel.Text = $"First item: {e.FirstVisibleItemIndex}, Last item: {e.LastVisibleItemIndex}";
double delta = 0, offset = 0;
double delta;
double offset;
if (_orientation == ItemsLayoutOrientation.Horizontal)
{

Просмотреть файл

@ -1,5 +1,8 @@
namespace Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.CarouselViewGalleries
using Xamarin.Forms.Internals;
namespace Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.CarouselViewGalleries
{
[Preserve(AllMembers = true)]
internal class CarouselViewGallery : ContentPage
{
public CarouselViewGallery()

Просмотреть файл

@ -1,5 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns:gallery="clr-namespace:Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.CarouselViewGalleries" xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.CarouselViewGalleries.CarouselXamlGallery">
<ContentPage
xmlns:gallery="clr-namespace:Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.CarouselViewGalleries" xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.CarouselViewGalleries.CarouselXamlGallery"
Title="CarouselView Xaml">
<Grid Margin="0,50,00,0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />

Просмотреть файл

@ -1,10 +1,10 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Xamarin.Forms;
using Xamarin.Forms.Internals;
namespace Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.CarouselViewGalleries
{
[Preserve(AllMembers = true)]
public partial class CarouselXamlGallery : ContentPage
{
public CarouselXamlGallery()
@ -15,12 +15,14 @@ namespace Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.CarouselVi
}
}
[Preserve(AllMembers = true)]
public enum CarouselXamlSampleType
{
Normal,
Peek
}
[Preserve(AllMembers = true)]
internal class CarouselViewModel : ViewModelBase2
{
int _count;
@ -76,6 +78,7 @@ namespace Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.CarouselVi
}
}
[Preserve(AllMembers = true)]
internal class CarouselItem
{
public CarouselItem(int index, string image = null)

Просмотреть файл

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Grid Padding="10,0,10,0" xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.CarouselViewGalleries.ExampleTemplateCarousel">
<Grid Padding="10,0,10,0" xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.CarouselViewGalleries.ExampleTemplateCarousel">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CarouselViewStates">
<VisualState x:Name="CurrentItem">
@ -29,7 +30,7 @@
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Frame x:Name="frame" HasShadow="True" Padding="0" HorizontalOptions="Center" VerticalOptions="Center">
<Frame x:Name="frame" HasShadow="True" Padding="0" HorizontalOptions="Center" VerticalOptions="Center" BackgroundColor="Yellow">
<Image Source="{Binding FeaturedImage}" InputTransparent="true" Aspect="AspectFit" />
</Frame>
</Grid>

Просмотреть файл

@ -1,16 +1,16 @@
using System;
using System.Collections.Generic;
using Xamarin.Forms;
using Xamarin.Forms.Internals;
namespace Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.CarouselViewGalleries
{
public partial class ExampleTemplateCarousel
[Preserve(AllMembers = true)]
public partial class ExampleTemplateCarousel : Grid
{
double initialY = -1;
bool delete;
double maxYScroll = 300;
double diffYScroll = -150;
double minYScroll = -30;
double _initialY = -1;
bool _delete;
readonly double _maxYScroll = 300;
readonly double _diffYScroll = -150;
readonly double _minYScroll = -30;
public ExampleTemplateCarousel()
{
@ -22,41 +22,41 @@ namespace Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.CarouselVi
{
if (e.StatusType == GestureStatus.Started)
{
initialY = Y;
_initialY = Y;
}
if (e.StatusType == GestureStatus.Running)
{
if (e.TotalY < minYScroll)
if (e.TotalY < _minYScroll)
{
var scaledValue = 1 - (Math.Abs(e.TotalY) / maxYScroll);
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)
if (e.TotalY < _diffYScroll)
{
delete = true;
_delete = true;
}
}
if (e.StatusType == GestureStatus.Completed || e.StatusType == GestureStatus.Canceled)
{
if (delete)
if (_delete)
{
this.FadeTo(0.1);
this.TranslateTo(X, Y - 1000);
MessagingCenter.Send<ExampleTemplateCarousel>(this, "remove");
MessagingCenter.Send(this, "remove");
}
else
{
this.ScaleTo(1);
this.FadeTo(1);
this.TranslateTo(X, initialY);
this.TranslateTo(X, _initialY);
}
}
};
GestureRecognizers.Add(gesture);
}
}
}
}

Просмотреть файл

@ -20,8 +20,11 @@ namespace Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries
readonly ItemsView _cv;
private readonly ItemsSourceType _itemsSourceType;
readonly Entry _entry;
readonly Entry _entrySideItems;
int _count = 0;
CarouselView carousel => _cv as CarouselView;
public int Count => _count;
public ItemsSourceGenerator(ItemsView cv, int initialItems = 1000,
ItemsSourceType itemsSourceType = ItemsSourceType.List)
@ -36,11 +39,15 @@ namespace Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries
};
var button = new Button { Text = "Update", AutomationId = "btnUpdate" };
var label = new Label { Text = "Item count:", VerticalTextAlignment = TextAlignment.Center };
_entry = new Entry { Keyboard = Keyboard.Numeric, Text = initialItems.ToString(), WidthRequest = 200, AutomationId = "entryUpdate" };
var label = new Label { Text = "Items:", VerticalTextAlignment = TextAlignment.Center };
var labelSideItems = new Label { Text = "Side items:", VerticalTextAlignment = TextAlignment.Center };
_entry = new Entry { Keyboard = Keyboard.Numeric, Text = initialItems.ToString(), WidthRequest = 100, AutomationId = "entryUpdate" };
_entrySideItems = new Entry { Keyboard = Keyboard.Numeric, Text = carousel?.NumberOfSideItems.ToString(), WidthRequest = 100, AutomationId = "entrySideItemsUpdate" };
layout.Children.Add(label);
layout.Children.Add(_entry);
layout.Children.Add(labelSideItems);
layout.Children.Add(_entrySideItems);
layout.Children.Add(button);
button.Clicked += GenerateItems;
@ -108,14 +115,15 @@ namespace Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries
}
_obsCollection = new ObservableCollection<CollectionViewGalleryTestItem>(items);
_obsCollection.CollectionChanged += ObsItemsSource_CollectionChanged;
_count = _obsCollection.Count;
CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
_cv.ItemsSource = _obsCollection;
}
}
void ObsItemsSource_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
_count = _obsCollection.Count;
CollectionChanged?.Invoke(sender, e);
}
@ -157,6 +165,12 @@ namespace Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries
void GenerateItems(object sender, EventArgs e)
{
GenerateItems();
if (carousel == null)
return;
if (int.TryParse(_entrySideItems.Text, out int count))
carousel.NumberOfSideItems = count;
}
}
}

Просмотреть файл

@ -73,7 +73,8 @@ namespace Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries
public void UpdatePositionCount(int itemsCount)
{
_slider.Maximum = itemsCount - 1;
if (itemsCount > 0)
_slider.Maximum = itemsCount - 1;
}
}

Просмотреть файл

@ -72,7 +72,7 @@ namespace Xamarin.Forms
}
public static readonly BindableProperty CurrentItemProperty =
BindableProperty.Create(nameof(CurrentItem), typeof(object), typeof(CarouselView), default(object),
BindableProperty.Create(nameof(CurrentItem), typeof(object), typeof(CarouselView), default, BindingMode.TwoWay,
propertyChanged: CurrentItemPropertyChanged);
public static readonly BindableProperty CurrentItemChangedCommandProperty =
@ -124,7 +124,6 @@ namespace Xamarin.Forms
carouselView.OnCurrentItemChanged(args);
}
public static readonly BindableProperty PositionProperty =
BindableProperty.Create(nameof(Position), typeof(int), typeof(CarouselView), default(int), BindingMode.TwoWay,
propertyChanged: PositionPropertyChanged);
@ -205,9 +204,9 @@ namespace Xamarin.Forms
static int GetPositionForItem(CarouselView carouselView, object item)
{
var itemSource = carouselView.ItemsSource as IList;
var itemSource = carouselView?.ItemsSource as IList;
for (int n = 0; n < itemSource.Count; n++)
for (int n = 0; n < itemSource?.Count; n++)
{
if (itemSource[n] == item)
{

Просмотреть файл

@ -862,6 +862,7 @@ namespace Xamarin.Forms.CustomAttributes
public enum CarouselView
{
CurrentItem,
IsSwipeEnabled,
IsScrollAnimated,
NumberOfSideItems,

Просмотреть файл

@ -7,37 +7,71 @@ namespace Xamarin.Forms.Platform.Android
{
internal class CarouselSpacingItemDecoration : RecyclerView.ItemDecoration
{
readonly IItemsLayout _itemsLayout;
readonly Func<int> _getWidth;
readonly Func<int> _getHeight;
readonly ItemsLayoutOrientation _orientation;
readonly double _verticalSpacing;
double _adjustedVerticalSpacing = -1;
readonly double _horizontalSpacing;
double _adjustedHorizontalSpacing = -1;
public CarouselSpacingItemDecoration(IItemsLayout itemsLayout, Func<int> getWidth, Func<int> getHeight)
public CarouselSpacingItemDecoration(IItemsLayout itemsLayout)
{
_itemsLayout = itemsLayout;
_getWidth = getWidth;
_getHeight = getHeight;
var layout = itemsLayout ?? throw new ArgumentNullException(nameof(itemsLayout));
switch (layout)
{
case GridItemsLayout gridItemsLayout:
_orientation = gridItemsLayout.Orientation;
_horizontalSpacing = gridItemsLayout.HorizontalItemSpacing;
_verticalSpacing = gridItemsLayout.VerticalItemSpacing;
break;
case ListItemsLayout listItemsLayout:
_orientation = listItemsLayout.Orientation;
if (_orientation == ItemsLayoutOrientation.Horizontal)
_horizontalSpacing = listItemsLayout.ItemSpacing;
else
_verticalSpacing = listItemsLayout.ItemSpacing;
break;
}
}
public override void OnDraw(Canvas c, RecyclerView parent, RecyclerView.State state)
{
base.OnDraw(c, parent, state);
}
public override void GetItemOffsets(Rect outRect, AView view, RecyclerView parent, RecyclerView.State state)
{
base.GetItemOffsets(outRect, view, parent, state);
if (Math.Abs(_adjustedVerticalSpacing - (-1)) < double.Epsilon)
{
_adjustedVerticalSpacing = parent.Context.ToPixels(_verticalSpacing);
}
if (Math.Abs(_adjustedHorizontalSpacing - (-1)) < double.Epsilon)
{
_adjustedHorizontalSpacing = parent.Context.ToPixels(_horizontalSpacing);
}
int position = parent.GetChildAdapterPosition(view);
int itemCount = state.ItemCount;
int width = _getWidth();
if (position == RecyclerView.NoPosition || itemCount == 0)
return;
// this is the first and last item , we need to give them some inset
if (position == 0)
outRect.Left = width / itemCount;
if (_orientation == ItemsLayoutOrientation.Vertical)
{
outRect.Left = position == 0 ? 0 : (int)_adjustedHorizontalSpacing;
outRect.Bottom = (int)(_adjustedVerticalSpacing - (_verticalSpacing * 2));
outRect.Top = (int)(_adjustedVerticalSpacing - (_verticalSpacing * 2));
}
if (position == itemCount - 1)
outRect.Right = width;
if (position == itemCount)
outRect.Left = width;
if (_orientation == ItemsLayoutOrientation.Horizontal)
{
outRect.Top = position == 0 ? 0 : (int)_adjustedVerticalSpacing;
outRect.Right = (int)(_adjustedHorizontalSpacing - (_horizontalSpacing * 2));
outRect.Left = (int)(_adjustedHorizontalSpacing - (_horizontalSpacing * 2));
}
}
}
}

Просмотреть файл

@ -1,31 +1,37 @@
using System;
using System.ComponentModel;
using Android.Content;
using Android.Support.V7.Widget;
using Android.Views;
using FormsCollectionView = Xamarin.Forms.CollectionView;
namespace Xamarin.Forms.Platform.Android
{
public class CarouselViewRenderer : ItemsViewRenderer<ItemsView, ItemsViewAdapter<ItemsView, IItemsViewSource>, IItemsViewSource>
{
readonly Context _context;
protected CarouselView Carousel;
IItemsLayout _layout;
ItemDecoration _itemDecoration;
bool _isSwipeEnabled;
bool _isUpdatingPositionFromForms;
int _oldPosition;
int _initialPosition;
bool _scrollingToInitialPosition = true;
public CarouselViewRenderer(Context context) : base(context)
{
_context = context;
FormsCollectionView.VerifyCollectionViewFlagEnabled(nameof(CarouselViewRenderer));
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (_itemDecoration != null)
{
_itemDecoration.Dispose();
_itemDecoration = null;
}
_layout = null;
}
base.Dispose(disposing);
@ -42,9 +48,11 @@ namespace Xamarin.Forms.Platform.Android
}
Carousel = newElement as CarouselView;
_layout = ItemsView.ItemsLayout;
UpdateIsSwipeEnabled();
UpdateInitialPosition();
UpdateItemSpacing();
}
protected override void UpdateItemsSource()
@ -52,47 +60,42 @@ namespace Xamarin.Forms.Platform.Android
// By default the CollectionViewAdapter creates the items at whatever size the template calls for
// But for the Carousel, we want it to create the items to fit the width/height of the viewport
// So we give it an alternate delegate for creating the views
ItemsViewAdapter = new ItemsViewAdapter<ItemsView, IItemsViewSource>(ItemsView,
(view, context) => new SizedItemContentView(context, () => Width, () => Height));
ItemsViewAdapter = new ItemsViewAdapter<ItemsView, IItemsViewSource>(ItemsView,
(view, context) => new SizedItemContentView(Context, GetItemWidth, GetItemHeight));
SwapAdapter(ItemsViewAdapter, false);
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs changedProperty)
{
if (e.Is(CarouselView.IsSwipeEnabledProperty))
if (changedProperty.Is(CarouselView.PeekAreaInsetsProperty))
Tracker?.UpdateLayout();
else if (changedProperty.Is(CarouselView.IsSwipeEnabledProperty))
UpdateIsSwipeEnabled();
else if (e.Is(CarouselView.IsBounceEnabledProperty))
else if (changedProperty.Is(CarouselView.IsBounceEnabledProperty))
UpdateIsBounceEnabled();
else if (changedProperty.Is(ListItemsLayout.ItemSpacingProperty))
UpdateItemSpacing();
}
public override bool OnTouchEvent(MotionEvent e)
public override bool OnInterceptTouchEvent(MotionEvent ev)
{
//TODO: this doesn't work because we need to interact with the Views
if (!_isSwipeEnabled)
{
return false;
}
return base.OnTouchEvent(e);
return base.OnInterceptTouchEvent(ev);
}
public override void OnScrollStateChanged(int state)
{
base.OnScrollStateChanged(state);
System.Diagnostics.Debug.WriteLine($"State {state}");
if (_isSwipeEnabled)
{
if (state == ScrollStateDragging)
{
Carousel.SetIsDragging(true);
}
else
{
Carousel.SetIsDragging(false);
}
}
}
@ -105,7 +108,59 @@ namespace Xamarin.Forms.Platform.Android
protected override ItemDecoration CreateSpacingDecoration(IItemsLayout itemsLayout)
{
return new CarouselSpacingItemDecoration(itemsLayout, GetItemWidth, GetItemHeight);
return new CarouselSpacingItemDecoration(itemsLayout);
}
protected override void UpdateItemSpacing()
{
if (_layout == null)
{
return;
}
if (_itemDecoration != null)
{
RemoveItemDecoration(_itemDecoration);
}
_itemDecoration = CreateSpacingDecoration(_layout);
AddItemDecoration(_itemDecoration);
var adapter = GetAdapter();
if (adapter != null)
{
adapter.NotifyItemChanged(_oldPosition);
Carousel.ScrollTo(_oldPosition, position: Xamarin.Forms.ScrollToPosition.Center);
}
base.UpdateItemSpacing();
}
int GetItemWidth()
{
var itemWidth = Width;
if (_layout is ListItemsLayout listItemsLayout && listItemsLayout.Orientation == ItemsLayoutOrientation.Horizontal)
{
var numberOfVisibleItems = Carousel.NumberOfSideItems * 2 + 1;
itemWidth = (int)(Width - Carousel.PeekAreaInsets.Left - Carousel.PeekAreaInsets.Right - Context?.ToPixels(listItemsLayout.ItemSpacing)) / numberOfVisibleItems;
}
return itemWidth;
}
int GetItemHeight()
{
var itemHeight = Height;
if (_layout is ListItemsLayout listItemsLayout && listItemsLayout.Orientation == ItemsLayoutOrientation.Vertical)
{
var numberOfVisibleItems = Carousel.NumberOfSideItems * 2 + 1;
itemHeight = (int)(Height - Carousel.PeekAreaInsets.Top - Carousel.PeekAreaInsets.Bottom - Context?.ToPixels(listItemsLayout.ItemSpacing)) / numberOfVisibleItems;
}
return itemHeight;
}
void UpdateIsSwipeEnabled()
@ -118,12 +173,12 @@ namespace Xamarin.Forms.Platform.Android
if (position == -1 || _isUpdatingPositionFromForms)
return;
var context = ItemsViewAdapter?.ItemsSource.GetItem(position);
var item = ItemsViewAdapter?.ItemsSource.GetItem(position);
if (context == null)
if (item == null)
throw new InvalidOperationException("Visible item not found");
Carousel.SetCurrentItem(context);
Carousel.SetCurrentItem(item);
}
void UpdateIsBounceEnabled()
@ -131,26 +186,6 @@ namespace Xamarin.Forms.Platform.Android
OverScrollMode = Carousel.IsBounceEnabled ? OverScrollMode.Always : OverScrollMode.Never;
}
int GetItemWidth()
{
var numberofSideItems = (Element as CarouselView).NumberOfSideItems;
var numberOfItems = numberofSideItems * 2 + 1;
int spacingWidth = 0;
if (Carousel.ItemsLayout is ListItemsLayout listItemsLayout && numberofSideItems > 0)
spacingWidth = (int)listItemsLayout.ItemSpacing * (numberOfItems - 1);
var itemWidth = (Width - (int)Context.ToPixels(spacingWidth)) / numberOfItems;
return itemWidth;
}
int GetItemHeight()
{
//TODO: Calculate item height.
return Height;
}
void UpdatePositionFromScroll()
{
var snapHelper = GetSnapManager()?.GetCurrentSnapHelper();
@ -165,12 +200,7 @@ namespace Xamarin.Forms.Platform.Android
if (snapView != null)
{
int middleCenterPosition = layoutManager.GetPosition(snapView);
if (_scrollingToInitialPosition)
{
_scrollingToInitialPosition = !(_initialPosition == middleCenterPosition);
return;
}
if (_oldPosition != middleCenterPosition)
{
_oldPosition = middleCenterPosition;
@ -182,8 +212,9 @@ namespace Xamarin.Forms.Platform.Android
void UpdateInitialPosition()
{
_isUpdatingPositionFromForms = true;
//Goto to the Correct Position
// Goto to the Correct Position
_initialPosition = Carousel.Position;
_oldPosition = _initialPosition;
Carousel.ScrollTo(_initialPosition, position: Xamarin.Forms.ScrollToPosition.Center);
_isUpdatingPositionFromForms = false;
}

Просмотреть файл

@ -13,7 +13,7 @@ namespace Xamarin.Forms.Platform.Android
{
protected readonly TItemsView ItemsView;
readonly Func<View, Context, ItemContentView> _createItemContentView;
internal readonly TItemsViewSource ItemsSource;
internal TItemsViewSource ItemsSource;
bool _disposed;
Size? _size;
@ -49,7 +49,11 @@ namespace Xamarin.Forms.Platform.Android
protected virtual void ItemsViewPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs property)
{
if (property.Is(Xamarin.Forms.ItemsView.HeaderProperty))
if (property.Is(Xamarin.Forms.ItemsView.ItemsSourceProperty))
{
UpdateItemsSource();
}
else if (property.Is(Xamarin.Forms.ItemsView.HeaderProperty))
{
UpdateHasHeader();
}
@ -126,7 +130,8 @@ namespace Xamarin.Forms.Platform.Android
return new TextViewHolder(view);
}
var itemContentView = new ItemContentView(context);
var itemContentView = _createItemContentView.Invoke(ItemsView, context);
return new TemplatedItemViewHolder(itemContentView, ItemsView.ItemTemplate);
}
@ -186,6 +191,13 @@ namespace Xamarin.Forms.Platform.Android
}
}
void UpdateItemsSource()
{
ItemsSource?.Dispose();
ItemsSource = CreateItemsSource();
}
void SetStaticSize(Size size)
{
_size = size;

Просмотреть файл

@ -7,10 +7,10 @@ namespace Xamarin.Forms.Platform.Android
{
internal class SpacingItemDecoration : RecyclerView.ItemDecoration
{
ItemsLayoutOrientation _orientation;
double _verticalSpacing;
readonly ItemsLayoutOrientation _orientation;
readonly double _verticalSpacing;
double _adjustedVerticalSpacing = -1;
double _horizontalSpacing;
readonly double _horizontalSpacing;
double _adjustedHorizontalSpacing = -1;
public SpacingItemDecoration(IItemsLayout itemsLayout)
@ -30,13 +30,9 @@ namespace Xamarin.Forms.Platform.Android
case ListItemsLayout listItemsLayout:
_orientation = listItemsLayout.Orientation;
if (_orientation == ItemsLayoutOrientation.Horizontal)
{
_horizontalSpacing = listItemsLayout.ItemSpacing;
}
else
{
_verticalSpacing = listItemsLayout.ItemSpacing;
}
break;
}
}

Просмотреть файл

@ -32,7 +32,7 @@ namespace Xamarin.Forms.Platform.iOS
var aspectRatio = size.Width / size.Height;
var numberOfVisibleItems = _carouselView.NumberOfSideItems * 2 + 1;
var width = (size.Width - _carouselView.PeekAreaInsets.Left - _carouselView.PeekAreaInsets.Right) / numberOfVisibleItems;
var height = size.Height / numberOfVisibleItems;
var height = (size.Height - _carouselView.PeekAreaInsets.Top - _carouselView.PeekAreaInsets.Bottom) / numberOfVisibleItems;
if (ScrollDirection == UICollectionViewScrollDirection.Horizontal)
{

Просмотреть файл

@ -1,5 +1,4 @@
using System;
using System.ComponentModel;
using System.ComponentModel;
namespace Xamarin.Forms.Platform.iOS
{