Skip to content

Commit e8ec7cb

Browse files
committed
Add context actions support for CollectionView
Introduce `PJ.ContextActions.Maui` namespace with `AppBuilderExtensions` to configure custom handlers for `CollectionView`. Implement `PJCollectionViewHandler` and `PJViewAdapter` to manage context menus and item interactions. Add `ItemContextMenuListener` and `MenuItemClickListener` for handling context menu creation and item clicks.
1 parent 120d32b commit e8ec7cb

File tree

2 files changed

+155
-0
lines changed

2 files changed

+155
-0
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
namespace PJ.ContextActions.Maui;
2+
public static class AppBuilderExtensions
3+
{
4+
public static MauiAppBuilder UseContextActions(this MauiAppBuilder builder)
5+
{
6+
builder.ConfigureMauiHandlers(h =>
7+
{
8+
h.AddHandler(typeof(CollectionView), typeof(PJCollectionViewHandler));
9+
});
10+
11+
return builder;
12+
}
13+
}
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
using Android.Content;
2+
using Android.Views;
3+
using AndroidX.RecyclerView.Widget;
4+
using Microsoft.Maui.Controls.Handlers.Items;
5+
6+
namespace PJ.ContextActions.Maui;
7+
8+
sealed class PJCollectionViewHandler : CollectionViewHandler
9+
{
10+
protected override ReorderableItemsViewAdapter<ReorderableItemsView, IGroupableItemsViewSource> CreateAdapter()
11+
{
12+
return new PJViewAdapter(VirtualView);
13+
}
14+
}
15+
16+
17+
sealed class PJViewAdapter : ReorderableItemsViewAdapter<ReorderableItemsView, IGroupableItemsViewSource>
18+
{
19+
IGroupableItemsViewSource itemsSource = default!;
20+
ReorderableItemsView collectionView;
21+
22+
internal static MenuItem[]? MenuItems;
23+
public PJViewAdapter(ReorderableItemsView reorderableItemsView, Func<global::Android.Views.View, Context, ItemContentView>? createView = null) : base(reorderableItemsView, createView)
24+
{
25+
collectionView = reorderableItemsView;
26+
}
27+
28+
protected override IGroupableItemsViewSource CreateItemsSource()
29+
{
30+
return ItemsSource = base.CreateItemsSource();
31+
}
32+
33+
public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position)
34+
{
35+
base.OnBindViewHolder(holder, position);
36+
37+
if (collectionView is not CollectionView cv)
38+
{
39+
return;
40+
}
41+
42+
var contextActions = ContextActions.GetContextActions(cv);
43+
44+
if (contextActions.Count is 0)
45+
{
46+
return;
47+
}
48+
49+
if (MenuItems is null)
50+
{
51+
MenuItems = new MenuItem[contextActions.Count];
52+
53+
foreach (var (index, item) in contextActions.Index())
54+
{
55+
item.BindingContext = cv.BindingContext;
56+
MenuItems[index] = item;
57+
}
58+
}
59+
60+
position -= itemsSource.HasHeader ? 1 : 0;
61+
62+
var size = itemsSource.Count - (itemsSource.HasHeader ? 1 : 0) - (itemsSource.HasHeader ? 1 : 0);
63+
64+
if (position >= 0 && position < size)
65+
{
66+
var element = itemsSource.GetItem(position + 1);
67+
68+
}
69+
}
70+
71+
public override void OnViewRecycled(Java.Lang.Object holder)
72+
{
73+
base.OnViewRecycled(holder);
74+
75+
if (holder is RecyclerView.ViewHolder viewHolder)
76+
{
77+
viewHolder.ItemView.SetOnCreateContextMenuListener(null);
78+
}
79+
}
80+
}
81+
82+
sealed class ItemContextMenuListener : Java.Lang.Object, global::Android.Views.View.IOnCreateContextMenuListener
83+
{
84+
readonly object element;
85+
86+
public ItemContextMenuListener(object element)
87+
{
88+
this.element = element;
89+
}
90+
91+
public void OnCreateContextMenu(IContextMenu? menu, Android.Views.View? v, IContextMenuContextMenuInfo? menuInfo)
92+
{
93+
if (menu is null || v is null)
94+
{
95+
return;
96+
}
97+
98+
if (PJViewAdapter.MenuItems is null)
99+
{
100+
return;
101+
}
102+
103+
var menuItems = PJViewAdapter.MenuItems;
104+
105+
foreach (var (index, item) in menuItems.Index())
106+
{
107+
var mItem = menu.Add(0, index + 1, index, item.Text);
108+
Assert(mItem is not null);
109+
mItem.SetOnMenuItemClickListener(new MenuItemClickListener(new(element, item)));
110+
}
111+
}
112+
}
113+
114+
sealed class MenuItemClickListener : Java.Lang.Object, IMenuItemOnMenuItemClickListener
115+
{
116+
readonly CommandBag bag;
117+
118+
public MenuItemClickListener(CommandBag bag)
119+
{
120+
this.bag = bag;
121+
}
122+
123+
public bool OnMenuItemClick(IMenuItem item)
124+
{
125+
if (item is null)
126+
{
127+
return false;
128+
}
129+
130+
var menuItem = bag.item;
131+
var element = bag.cvItem;
132+
133+
menuItem.FireClicked(element);
134+
135+
if (menuItem.Command?.CanExecute(element) is true)
136+
{
137+
menuItem.Command.Execute(element);
138+
}
139+
140+
return true;
141+
}
142+
}

0 commit comments

Comments
 (0)