Skip to content

Commit 7734fd2

Browse files
committed
Add bindable ListView and ScrollView elements.
1 parent aa83ab4 commit 7734fd2

File tree

11 files changed

+312
-0
lines changed

11 files changed

+312
-0
lines changed

src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Common/Interfaces.meta

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
using System;
2+
3+
namespace UnityMvvmToolkit.Common.Interfaces
4+
{
5+
public interface ICollectionItemData
6+
{
7+
Guid Id { get; }
8+
}
9+
}

src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/Common/Interfaces/ICollectionItemData.cs.meta

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
using System;
2+
using System.Collections.ObjectModel;
3+
using System.Collections.Specialized;
4+
using System.Runtime.CompilerServices;
5+
using UnityEngine.UIElements;
6+
using UnityMvvmToolkit.Core.Interfaces;
7+
using UnityMvvmToolkit.UI.BindableUIElements;
8+
9+
namespace UnityMvvmToolkit.UI.BindableUIElementWrappers
10+
{
11+
public abstract class BindableListViewWrapper<TItem, TData> : IBindableElement, IInitializable, IDisposable
12+
{
13+
private readonly BindableListView _listView;
14+
private readonly VisualTreeAsset _itemAsset;
15+
private readonly IReadOnlyProperty<ObservableCollection<TData>> _itemsCollectionProperty;
16+
17+
private ObservableCollection<TData> _itemsCollection;
18+
19+
protected BindableListViewWrapper(BindableListView listView, VisualTreeAsset itemAsset,
20+
IObjectProvider objectProvider)
21+
{
22+
_listView = listView;
23+
_itemAsset = itemAsset;
24+
_itemsCollectionProperty =
25+
objectProvider.GetReadOnlyProperty<ObservableCollection<TData>>(listView.BindingItemsSourcePath,
26+
ReadOnlyMemory<char>.Empty);
27+
}
28+
29+
public bool CanInitialize => _itemsCollectionProperty != null;
30+
31+
protected BindableListView ListView => _listView;
32+
protected ObservableCollection<TData> ItemsCollection => _itemsCollection;
33+
34+
public virtual void Initialize()
35+
{
36+
_itemsCollection = _itemsCollectionProperty.Value;
37+
_itemsCollection.CollectionChanged += OnItemsCollectionChanged;
38+
39+
_listView.itemsSource = _itemsCollection;
40+
_listView.makeItem += MakeItem;
41+
_listView.bindItem += BindItem;
42+
}
43+
44+
public virtual void Dispose()
45+
{
46+
_itemsCollection.CollectionChanged -= OnItemsCollectionChanged;
47+
48+
_listView.makeItem -= MakeItem;
49+
_listView.bindItem -= BindItem;
50+
}
51+
52+
protected virtual VisualElement MakeItem()
53+
{
54+
var itemAsset = _itemAsset.Instantiate();
55+
itemAsset.userData = OnMakeItem(itemAsset);
56+
57+
return itemAsset;
58+
}
59+
60+
protected virtual void BindItem(VisualElement itemAsset, int index)
61+
{
62+
if (index >= 0 && index < _itemsCollection.Count)
63+
{
64+
OnBindItem((TItem) itemAsset.userData, _itemsCollection[index]);
65+
}
66+
}
67+
68+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
69+
protected abstract TItem OnMakeItem(VisualElement itemAsset);
70+
71+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
72+
protected abstract void OnBindItem(TItem item, TData data);
73+
74+
protected virtual void OnItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
75+
{
76+
_listView.RefreshItems();
77+
}
78+
}
79+
}

src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UI/BindableUIElementWrappers/BindableListViewWrapper.cs.meta

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Collections.ObjectModel;
4+
using System.Collections.Specialized;
5+
using System.Runtime.CompilerServices;
6+
using UnityEngine.Pool;
7+
using UnityEngine.UIElements;
8+
using UnityMvvmToolkit.Common.Interfaces;
9+
using UnityMvvmToolkit.Core.Interfaces;
10+
using UnityMvvmToolkit.UI.BindableUIElements;
11+
12+
namespace UnityMvvmToolkit.UI.BindableUIElementWrappers
13+
{
14+
public abstract class BindableScrollViewWrapper<TItem, TData> : IBindableElement, IInitializable, IDisposable
15+
where TData : ICollectionItemData
16+
{
17+
private readonly BindableScrollView _scrollView;
18+
private readonly VisualTreeAsset _itemAsset;
19+
private readonly IReadOnlyProperty<ObservableCollection<TData>> _itemsCollectionProperty;
20+
21+
private ObservableCollection<TData> _itemsCollection;
22+
private ObjectPool<VisualElement> _itemAssetsPool;
23+
private Dictionary<Guid, VisualElement> _itemAssets;
24+
25+
protected BindableScrollViewWrapper(BindableScrollView scrollView, VisualTreeAsset itemAsset,
26+
IObjectProvider objectProvider)
27+
{
28+
_scrollView = scrollView;
29+
_itemAsset = itemAsset;
30+
31+
_itemsCollectionProperty =
32+
objectProvider.GetReadOnlyProperty<ObservableCollection<TData>>(scrollView.BindingItemsSourcePath,
33+
ReadOnlyMemory<char>.Empty);
34+
}
35+
36+
public bool CanInitialize => _itemsCollectionProperty != null;
37+
38+
protected BindableScrollView ScrollView => _scrollView;
39+
protected ObservableCollection<TData> ItemsCollection => _itemsCollection;
40+
41+
public virtual void Initialize()
42+
{
43+
_itemAssets = new Dictionary<Guid, VisualElement>();
44+
_itemAssetsPool = new ObjectPool<VisualElement>(createFunc: OnAssetsPoolCreateItem,
45+
actionOnRelease: OnAssetsPoolReleaseItem, actionOnDestroy: OnAssetsPoolDestroyItem);
46+
47+
_itemsCollection = _itemsCollectionProperty.Value;
48+
_itemsCollection.CollectionChanged += OnItemsCollectionChanged;
49+
50+
AddItems(_itemsCollection);
51+
}
52+
53+
public virtual void Dispose()
54+
{
55+
_itemAssets.Clear();
56+
_itemAssetsPool.Dispose();
57+
_itemsCollection.CollectionChanged -= OnItemsCollectionChanged;
58+
}
59+
60+
protected virtual VisualElement MakeItem(out TItem item)
61+
{
62+
var itemAsset = _itemAssetsPool.Get();
63+
if (itemAsset.userData != null)
64+
{
65+
item = (TItem) itemAsset.userData;
66+
return itemAsset;
67+
}
68+
69+
item = OnMakeItem(itemAsset);
70+
itemAsset.userData = item;
71+
72+
return itemAsset;
73+
}
74+
75+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
76+
protected abstract TItem OnMakeItem(VisualElement itemAsset);
77+
78+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
79+
protected abstract void OnBindItem(TItem item, TData data);
80+
81+
protected virtual void OnItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
82+
{
83+
if (e.Action == NotifyCollectionChangedAction.Add)
84+
{
85+
foreach (var newItem in e.NewItems)
86+
{
87+
AddItem((TData) newItem);
88+
}
89+
}
90+
else if (e.Action == NotifyCollectionChangedAction.Remove)
91+
{
92+
foreach (var oldItem in e.OldItems)
93+
{
94+
RemoveItem((TData) oldItem);
95+
}
96+
}
97+
}
98+
99+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
100+
private void AddItems(IEnumerable<TData> items)
101+
{
102+
foreach (var itemData in items)
103+
{
104+
AddItem(itemData);
105+
}
106+
}
107+
108+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
109+
private void AddItem(TData itemData)
110+
{
111+
var itemAsset = MakeItem(out var item);
112+
113+
_itemAssets.Add(itemData.Id, itemAsset);
114+
_scrollView.contentContainer.Add(itemAsset);
115+
116+
OnBindItem(item, itemData);
117+
}
118+
119+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
120+
private void RemoveItems(IEnumerable<TData> items)
121+
{
122+
foreach (var itemData in items)
123+
{
124+
RemoveItem(itemData);
125+
}
126+
}
127+
128+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
129+
private void RemoveItem(TData itemData)
130+
{
131+
_itemAssetsPool.Release(_itemAssets[itemData.Id]);
132+
}
133+
134+
private VisualElement OnAssetsPoolCreateItem()
135+
{
136+
return _itemAsset.Instantiate();
137+
}
138+
139+
private void OnAssetsPoolReleaseItem(VisualElement itemAsset)
140+
{
141+
itemAsset.RemoveFromHierarchy();
142+
}
143+
144+
private void OnAssetsPoolDestroyItem(VisualElement itemAsset)
145+
{
146+
if (itemAsset.userData is IDisposable disposable)
147+
{
148+
disposable.Dispose();
149+
}
150+
}
151+
}
152+
}

src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UI/BindableUIElementWrappers/BindableScrollViewWrapper.cs.meta

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using UnityEngine.UIElements;
2+
using UnityMvvmToolkit.Core.Interfaces;
3+
4+
namespace UnityMvvmToolkit.UI.BindableUIElements
5+
{
6+
public class BindableListView : ListView, IBindableUIElement
7+
{
8+
public string BindingItemsSourcePath { get; set; }
9+
10+
public new class UxmlFactory : UxmlFactory<BindableListView, UxmlTraits>
11+
{
12+
}
13+
14+
public new class UxmlTraits : ListView.UxmlTraits
15+
{
16+
private readonly UxmlStringAttributeDescription _bindingItemsSourceAttribute = new()
17+
{ name = "binding-items-source-path", defaultValue = "" };
18+
19+
public override void Init(VisualElement visualElement, IUxmlAttributes bag, CreationContext context)
20+
{
21+
base.Init(visualElement, bag, context);
22+
((BindableListView) visualElement).BindingItemsSourcePath =
23+
_bindingItemsSourceAttribute.GetValueFromBag(bag, context);
24+
}
25+
}
26+
}
27+
}

src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UI/BindableUIElements/BindableListView.cs.meta

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using UnityEngine.UIElements;
2+
using UnityMvvmToolkit.Core.Interfaces;
3+
4+
namespace UnityMvvmToolkit.UI.BindableUIElements
5+
{
6+
public class BindableScrollView : ScrollView, IBindableUIElement
7+
{
8+
public string BindingItemsSourcePath { get; set; }
9+
10+
public new class UxmlFactory : UxmlFactory<BindableScrollView, UxmlTraits>
11+
{
12+
}
13+
14+
public new class UxmlTraits : ScrollView.UxmlTraits
15+
{
16+
private readonly UxmlStringAttributeDescription _bindingItemsSourceAttribute = new()
17+
{ name = "binding-items-source-path", defaultValue = "" };
18+
19+
public override void Init(VisualElement visualElement, IUxmlAttributes bag, CreationContext context)
20+
{
21+
base.Init(visualElement, bag, context);
22+
((BindableScrollView) visualElement).BindingItemsSourcePath =
23+
_bindingItemsSourceAttribute.GetValueFromBag(bag, context);
24+
}
25+
}
26+
}
27+
}

0 commit comments

Comments
 (0)