зеркало из https://github.com/DeGsoft/maui-linux.git
Make it easier to create custom renderers for alternate CV layouts on Android (#6990)
Demo of StaggeredGridLayoutManager on Android
This commit is contained in:
Родитель
880f368dda
Коммит
83a244801e
|
@ -0,0 +1,105 @@
|
|||
using System;
|
||||
using Android.Content;
|
||||
using Android.Graphics;
|
||||
using Android.Support.V7.Widget;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.ControlGallery.Android;
|
||||
using Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.AlternateLayoutGalleries;
|
||||
using Xamarin.Forms.Platform.Android;
|
||||
using AView = Android.Views.View;
|
||||
|
||||
[assembly: ExportRenderer(typeof(StaggeredCollectionView), typeof(StaggeredCollectionViewRenderer))]
|
||||
namespace Xamarin.Forms.ControlGallery.Android
|
||||
{
|
||||
public class StaggeredCollectionViewRenderer : CollectionViewRenderer
|
||||
{
|
||||
public StaggeredCollectionViewRenderer(Context context) : base(context) { }
|
||||
|
||||
protected override LayoutManager SelectLayoutManager(IItemsLayout layoutSpecification)
|
||||
{
|
||||
if (layoutSpecification is StaggeredGridItemsLayout staggeredGridLayout)
|
||||
{
|
||||
var manager = new StaggeredGridLayoutManager(staggeredGridLayout.Span,
|
||||
staggeredGridLayout.Orientation == ItemsLayoutOrientation.Horizontal
|
||||
? LinearLayoutManager.Horizontal
|
||||
: LinearLayoutManager.Vertical);
|
||||
|
||||
manager.GapStrategy = StaggeredGridLayoutManager.GapHandlingNone;
|
||||
|
||||
return manager;
|
||||
}
|
||||
|
||||
return base.SelectLayoutManager(layoutSpecification);
|
||||
}
|
||||
|
||||
protected override ItemDecoration CreateSpacingDecoration(IItemsLayout itemsLayout)
|
||||
{
|
||||
return new SpacingItemDecoration(itemsLayout as StaggeredGridItemsLayout);
|
||||
}
|
||||
}
|
||||
|
||||
public class SpacingItemDecoration : RecyclerView.ItemDecoration
|
||||
{
|
||||
ItemsLayoutOrientation _orientation;
|
||||
double _verticalSpacing;
|
||||
double _adjustedVerticalSpacing = -1;
|
||||
double _horizontalSpacing;
|
||||
double _adjustedHorizontalSpacing = -1;
|
||||
int _span = 1;
|
||||
|
||||
public SpacingItemDecoration(StaggeredGridItemsLayout itemsLayout)
|
||||
{
|
||||
if (itemsLayout == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(itemsLayout));
|
||||
}
|
||||
|
||||
switch (itemsLayout)
|
||||
{
|
||||
case StaggeredGridItemsLayout gridItemsLayout:
|
||||
_orientation = gridItemsLayout.Orientation;
|
||||
_horizontalSpacing = gridItemsLayout.HorizontalItemSpacing;
|
||||
_verticalSpacing = gridItemsLayout.VerticalItemSpacing;
|
||||
_span = gridItemsLayout.Span;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void GetItemOffsets(Rect outRect, AView view, RecyclerView parent, RecyclerView.State state)
|
||||
{
|
||||
base.GetItemOffsets(outRect, view, parent, state);
|
||||
|
||||
var position = parent.GetChildAdapterPosition(view);
|
||||
|
||||
if (_adjustedVerticalSpacing == -1)
|
||||
{
|
||||
_adjustedVerticalSpacing = parent.Context.ToPixels(_verticalSpacing);
|
||||
}
|
||||
|
||||
if (_adjustedHorizontalSpacing == -1)
|
||||
{
|
||||
_adjustedHorizontalSpacing = parent.Context.ToPixels(_horizontalSpacing);
|
||||
}
|
||||
|
||||
var spanIndex = 0;
|
||||
|
||||
var layoutParameters = view.LayoutParameters as StaggeredGridLayoutManager.LayoutParams;
|
||||
|
||||
if (layoutParameters != null)
|
||||
{
|
||||
spanIndex = layoutParameters.SpanIndex;
|
||||
}
|
||||
|
||||
if (_orientation == ItemsLayoutOrientation.Vertical)
|
||||
{
|
||||
outRect.Left = spanIndex == 0 ? 0 : (int)_adjustedHorizontalSpacing;
|
||||
outRect.Top = position < _span ? 0 : (int)_adjustedVerticalSpacing;
|
||||
}
|
||||
else
|
||||
{
|
||||
outRect.Left = position < _span ? 0 : (int)_adjustedHorizontalSpacing;
|
||||
outRect.Top = spanIndex == 0 ? 0 : (int)_adjustedVerticalSpacing;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -109,6 +109,7 @@
|
|||
<Compile Include="CustomRenderers.cs" />
|
||||
<Compile Include="ColorPicker.cs" />
|
||||
<Compile Include="SampleNativeControl.cs" />
|
||||
<Compile Include="StaggeredCollectionViewRenderer.cs" />
|
||||
<Compile Include="TestCloudService.cs" />
|
||||
<Compile Include="_1909CustomRenderer.cs" />
|
||||
<Compile Include="_2489CustomRenderer.cs" />
|
||||
|
@ -385,4 +386,4 @@
|
|||
</CreateItem>
|
||||
<Copy SourceFiles="@(MapsKey)" DestinationFiles="Properties\MapsKey.cs" Condition="!Exists('Properties\MapsKey.cs')" />
|
||||
</Target>
|
||||
</Project>
|
||||
</Project>
|
|
@ -0,0 +1,40 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.ScrollModeGalleries;
|
||||
|
||||
namespace Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.AlternateLayoutGalleries
|
||||
{
|
||||
internal class AlternateLayoutGallery : ContentPage
|
||||
{
|
||||
public AlternateLayoutGallery()
|
||||
{
|
||||
var descriptionLabel =
|
||||
new Label { Text = "Alternate Layout Galleries", Margin = new Thickness(2, 2, 2, 2) };
|
||||
|
||||
Title = "Alternate Layout Galleries";
|
||||
|
||||
Content = new ScrollView
|
||||
{
|
||||
Content = new StackLayout
|
||||
{
|
||||
Children =
|
||||
{
|
||||
descriptionLabel,
|
||||
|
||||
GalleryBuilder.NavButton("Staggered Grid [Android only]", () =>
|
||||
new StaggeredLayout(), Navigation),
|
||||
|
||||
GalleryBuilder.NavButton("ScrollTo Item (Staggered Grid, [Android only])", () =>
|
||||
new ScrollToCodeGallery(new StaggeredGridItemsLayout(3, ItemsLayoutOrientation.Vertical),
|
||||
ScrollToMode.Element, ExampleTemplates.RandomSizeTemplate, () => new StaggeredCollectionView()), Navigation),
|
||||
|
||||
GalleryBuilder.NavButton("Scroll Mode (Staggered Grid, [Android only])", () =>
|
||||
new ScrollModeTestGallery(new StaggeredGridItemsLayout(3, ItemsLayoutOrientation.Vertical),
|
||||
ExampleTemplates.RandomSizeTemplate, () => new StaggeredCollectionView()), Navigation)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.AlternateLayoutGalleries"
|
||||
mc:Ignorable="d"
|
||||
x:Class="Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.AlternateLayoutGalleries.StaggeredLayout">
|
||||
<ContentPage.Content>
|
||||
<local:StaggeredCollectionView x:Name="CV">
|
||||
<local:StaggeredCollectionView.ItemsLayout>
|
||||
<local:StaggeredGridItemsLayout Span="3" Orientation="Vertical" HorizontalItemSpacing="5" VerticalItemSpacing="5"></local:StaggeredGridItemsLayout>
|
||||
</local:StaggeredCollectionView.ItemsLayout>
|
||||
</local:StaggeredCollectionView>
|
||||
</ContentPage.Content>
|
||||
</ContentPage>
|
|
@ -0,0 +1,31 @@
|
|||
using Xamarin.Forms.Xaml;
|
||||
|
||||
namespace Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.AlternateLayoutGalleries
|
||||
{
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
public partial class StaggeredLayout : ContentPage
|
||||
{
|
||||
readonly DemoFilteredItemSource _demoFilteredItemSource = new DemoFilteredItemSource();
|
||||
|
||||
public StaggeredLayout()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
CV.ItemTemplate = ExampleTemplates.RandomSizeTemplate();
|
||||
CV.ItemsSource = _demoFilteredItemSource.Items;
|
||||
}
|
||||
}
|
||||
|
||||
public class StaggeredCollectionView : CollectionView { }
|
||||
|
||||
public class StaggeredGridItemsLayout : GridItemsLayout
|
||||
{
|
||||
public StaggeredGridItemsLayout([Parameter("Orientation")] ItemsLayoutOrientation orientation) : base(orientation)
|
||||
{
|
||||
}
|
||||
|
||||
public StaggeredGridItemsLayout(int span, [Parameter("Orientation")] ItemsLayoutOrientation orientation) : base(span, orientation)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
using Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.GroupingGalleries;
|
||||
using Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.SelectionGalleries;
|
||||
using Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.ScrollModeGalleries;
|
||||
using Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.AlternateLayoutGalleries;
|
||||
|
||||
namespace Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries
|
||||
{
|
||||
|
@ -25,6 +26,7 @@ namespace Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries
|
|||
GalleryBuilder.NavButton("Propagation Galleries", () => new PropagationGallery(), Navigation),
|
||||
GalleryBuilder.NavButton("Grouping Galleries", () => new GroupingGallery(), Navigation),
|
||||
GalleryBuilder.NavButton("Scroll Mode Galleries", () => new ScrollModeGallery(), Navigation),
|
||||
GalleryBuilder.NavButton("Alternate Layout Galleries", () => new AlternateLayoutGallery(), Navigation),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries
|
||||
|
@ -302,6 +303,29 @@ namespace Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries
|
|||
});
|
||||
}
|
||||
|
||||
public static DataTemplate RandomSizeTemplate()
|
||||
{
|
||||
var indexHeightConverter = new IndexRequestRandomConverter(50, 150);
|
||||
var indexWidthConverter = new IndexRequestRandomConverter(50, 150);
|
||||
var colorConverter = new IndexColorConverter();
|
||||
|
||||
return new DataTemplate(() =>
|
||||
{
|
||||
var layout = new Frame();
|
||||
|
||||
layout.SetBinding(VisualElement.HeightRequestProperty, new Binding("Index", converter: indexHeightConverter));
|
||||
layout.SetBinding(VisualElement.WidthRequestProperty, new Binding("Index", converter: indexWidthConverter));
|
||||
layout.SetBinding(VisualElement.BackgroundColorProperty, new Binding("Index", converter: colorConverter));
|
||||
|
||||
var label = new Label { FontSize = 30 };
|
||||
label.SetBinding(Label.TextProperty, new Binding("Index"));
|
||||
|
||||
layout.Content = label;
|
||||
|
||||
return layout;
|
||||
});
|
||||
}
|
||||
|
||||
public static DataTemplate DynamicTextTemplate()
|
||||
{
|
||||
return new DataTemplate(() =>
|
||||
|
@ -456,6 +480,34 @@ namespace Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries
|
|||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new NotImplementedException();
|
||||
}
|
||||
|
||||
class IndexRequestRandomConverter : IValueConverter
|
||||
{
|
||||
readonly int _lowValue;
|
||||
readonly int _highValue;
|
||||
readonly Random _random;
|
||||
readonly Dictionary<int, int> _dictionary = new Dictionary<int, int>();
|
||||
|
||||
public IndexRequestRandomConverter(int lowValue, int highValue)
|
||||
{
|
||||
_lowValue = lowValue;
|
||||
_highValue = highValue;
|
||||
_random = new Random(DateTime.UtcNow.Millisecond);
|
||||
}
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
var index = (int)value;
|
||||
if (!_dictionary.ContainsKey(index))
|
||||
{
|
||||
_dictionary[index] = _random.Next(_lowValue, _highValue);
|
||||
}
|
||||
|
||||
return _dictionary[index];
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new NotImplementedException();
|
||||
}
|
||||
|
||||
class IndexColorConverter : IValueConverter
|
||||
{
|
||||
Color[] _colors = new Color[] { Color.Red, Color.Green, Color.Blue, Color.Orange, Color.BlanchedAlmond };
|
||||
|
|
|
@ -22,8 +22,6 @@
|
|||
<Button x:Name="AddItemToEnd" FontSize="10" AutomationId="AddItemToEnd" Text="Add Item To End" Grid.Row="4"
|
||||
HeightRequest="40" Clicked="AddItemToEnd_Clicked" />
|
||||
|
||||
<CollectionView x:Name="CollectionView" Grid.Row="5" />
|
||||
|
||||
</Grid>
|
||||
</ContentPage.Content>
|
||||
</ContentPage>
|
|
@ -13,23 +13,31 @@ namespace Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.ScrollMode
|
|||
public partial class ScrollModeTestGallery : ContentPage
|
||||
{
|
||||
readonly DemoFilteredItemSource _demoFilteredItemSource = new DemoFilteredItemSource(20);
|
||||
CollectionView _collectionView;
|
||||
|
||||
public ScrollModeTestGallery()
|
||||
public ScrollModeTestGallery(IItemsLayout itemsLayout = null, Func<DataTemplate> dataTemplate = null, Func<CollectionView> createCollectionView = null)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
var scrollModeSelector = new EnumSelector<ItemsUpdatingScrollMode>(() => CollectionView.ItemsUpdatingScrollMode,
|
||||
mode => CollectionView.ItemsUpdatingScrollMode = mode, "SelectScrollMode");
|
||||
_collectionView = createCollectionView == null ? new CollectionView() : createCollectionView();
|
||||
_collectionView.ItemsLayout = itemsLayout ?? ListItemsLayout.Vertical;
|
||||
|
||||
var scrollModeSelector = new EnumSelector<ItemsUpdatingScrollMode>(() => _collectionView.ItemsUpdatingScrollMode,
|
||||
mode => _collectionView.ItemsUpdatingScrollMode = mode, "SelectScrollMode");
|
||||
|
||||
Grid.Children.Add(scrollModeSelector);
|
||||
|
||||
CollectionView.ItemTemplate = ExampleTemplates.PhotoTemplate();
|
||||
CollectionView.ItemsSource = _demoFilteredItemSource.Items;
|
||||
|
||||
Grid.Children.Add(_collectionView);
|
||||
Grid.SetRow(_collectionView, 5);
|
||||
|
||||
_collectionView.ItemTemplate = dataTemplate == null ? ExampleTemplates.PhotoTemplate() : dataTemplate();
|
||||
_collectionView.ItemsSource = _demoFilteredItemSource.Items;
|
||||
}
|
||||
|
||||
void ScrollToMiddle_Clicked(object sender, EventArgs e)
|
||||
{
|
||||
CollectionView.ScrollTo(_demoFilteredItemSource.Items.Count / 2, position: ScrollToPosition.Start, animate: false);
|
||||
_collectionView.ScrollTo(_demoFilteredItemSource.Items.Count / 2, position: ScrollToPosition.Start, animate: false);
|
||||
}
|
||||
|
||||
void AddItemAbove_Clicked(object sender, EventArgs e)
|
||||
|
|
|
@ -4,8 +4,10 @@ namespace Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries
|
|||
{
|
||||
internal class ScrollToCodeGallery : ContentPage
|
||||
{
|
||||
public ScrollToCodeGallery(IItemsLayout itemsLayout, ScrollToMode mode = ScrollToMode.Position, Func<DataTemplate> dataTemplate = null)
|
||||
public ScrollToCodeGallery(IItemsLayout itemsLayout, ScrollToMode mode = ScrollToMode.Position, Func<DataTemplate> dataTemplate = null, Func<CollectionView> createCollectionView = null)
|
||||
{
|
||||
createCollectionView = createCollectionView ?? (() => new CollectionView());
|
||||
|
||||
Title = $"ScrollTo (Code, {itemsLayout})";
|
||||
|
||||
var layout = new Grid
|
||||
|
@ -20,11 +22,10 @@ namespace Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries
|
|||
|
||||
var itemTemplate = dataTemplate == null ? ExampleTemplates.ScrollToIndexTemplate() : dataTemplate();
|
||||
|
||||
var collectionView = new CollectionView
|
||||
{
|
||||
ItemsLayout = itemsLayout,
|
||||
ItemTemplate = itemTemplate,
|
||||
};
|
||||
var collectionView = createCollectionView();
|
||||
|
||||
collectionView.ItemsLayout = itemsLayout;
|
||||
collectionView.ItemTemplate = itemTemplate;
|
||||
|
||||
var generator = new ItemsSourceGenerator(collectionView, initialItems: 50);
|
||||
layout.Children.Add(generator);
|
||||
|
|
|
@ -315,7 +315,7 @@ namespace Xamarin.Forms.Platform.Android
|
|||
AddOnScrollListener(_recyclerViewScrollListener);
|
||||
}
|
||||
|
||||
void UpdateVerticalScrollBarVisibility()
|
||||
protected virtual void UpdateVerticalScrollBarVisibility()
|
||||
{
|
||||
if (_defaultVerticalScrollVisibility == ScrollBarVisibility.Default)
|
||||
_defaultVerticalScrollVisibility = VerticalScrollBarEnabled ? ScrollBarVisibility.Always : ScrollBarVisibility.Never;
|
||||
|
@ -328,7 +328,7 @@ namespace Xamarin.Forms.Platform.Android
|
|||
VerticalScrollBarEnabled = newVerticalScrollVisibility == ScrollBarVisibility.Always;
|
||||
}
|
||||
|
||||
void UpdateHorizontalScrollBarVisibility()
|
||||
protected virtual void UpdateHorizontalScrollBarVisibility()
|
||||
{
|
||||
if (_defaultHorizontalScrollVisibility == ScrollBarVisibility.Default)
|
||||
_defaultHorizontalScrollVisibility =
|
||||
|
@ -520,7 +520,7 @@ namespace Xamarin.Forms.Platform.Android
|
|||
}
|
||||
}
|
||||
|
||||
protected virtual int DeterminePosition(ScrollToRequestEventArgs args)
|
||||
protected virtual int DetermineTargetPosition(ScrollToRequestEventArgs args)
|
||||
{
|
||||
if (args.Mode == ScrollToMode.Position)
|
||||
{
|
||||
|
@ -543,10 +543,15 @@ namespace Xamarin.Forms.Platform.Android
|
|||
RemoveItemDecoration(_itemDecoration);
|
||||
}
|
||||
|
||||
_itemDecoration = new SpacingItemDecoration(_layout);
|
||||
_itemDecoration = CreateSpacingDecoration(_layout);
|
||||
AddItemDecoration(_itemDecoration);
|
||||
}
|
||||
|
||||
protected virtual ItemDecoration CreateSpacingDecoration(IItemsLayout itemsLayout)
|
||||
{
|
||||
return new SpacingItemDecoration(itemsLayout);
|
||||
}
|
||||
|
||||
void ScrollToRequested(object sender, ScrollToRequestEventArgs args)
|
||||
{
|
||||
ScrollTo(args);
|
||||
|
@ -554,7 +559,7 @@ namespace Xamarin.Forms.Platform.Android
|
|||
|
||||
protected virtual void ScrollTo(ScrollToRequestEventArgs args)
|
||||
{
|
||||
var position = DeterminePosition(args);
|
||||
var position = DetermineTargetPosition(args);
|
||||
|
||||
if (args.IsAnimated)
|
||||
{
|
||||
|
|
|
@ -29,7 +29,6 @@ namespace Xamarin.Forms.Platform.Android
|
|||
if (!_maintainingScrollOffsets)
|
||||
{
|
||||
_maintainingScrollOffsets = true;
|
||||
//_recyclerView.ScrollChange += ScrollChange;
|
||||
_recyclerView.AddOnScrollListener(this);
|
||||
}
|
||||
|
||||
|
|
|
@ -49,11 +49,6 @@ namespace Xamarin.Forms.Platform.Android
|
|||
|
||||
var position = parent.GetChildAdapterPosition(view);
|
||||
|
||||
if (position == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_adjustedVerticalSpacing == -1)
|
||||
{
|
||||
_adjustedVerticalSpacing = parent.Context.ToPixels(_verticalSpacing);
|
||||
|
@ -61,7 +56,7 @@ namespace Xamarin.Forms.Platform.Android
|
|||
|
||||
if (_adjustedHorizontalSpacing == -1)
|
||||
{
|
||||
_adjustedHorizontalSpacing = parent.Context.ToPixels(_horizontalSpacing);
|
||||
_adjustedHorizontalSpacing = parent.Context.ToPixels(_horizontalSpacing);
|
||||
}
|
||||
|
||||
var firstInRow = false;
|
||||
|
|
Загрузка…
Ссылка в новой задаче