[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:
Родитель
656835123b
Коммит
79dd23edcb
Двоичные данные
Xamarin.Forms.ControlGallery.Android/Resources/drawable/cardBackground.png
Normal file
Двоичные данные
Xamarin.Forms.ControlGallery.Android/Resources/drawable/cardBackground.png
Normal file
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 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
|
||||
{
|
||||
|
|
Загрузка…
Ссылка в новой задаче