-
-
Save rdavisau/20bfa9e46e89cf31d409f8796cc41cf1 to your computer and use it in GitHub Desktop.
| public static class DiffableDataSourceExtensions | |
| { | |
| public static NSDiffableDataSourceSnapshot<IdentifierType<TSection>, IdentifierType<TItem>> | |
| ToDiffableDataSourceSnapshot<TSection, TSectionIdentifier, TItem, TItemIdentifier>( | |
| this IEnumerable<TSection> sections, Func<TSection, TSectionIdentifier> getSectionIdentifier, | |
| Func<TSection, IEnumerable<TItem>> getItems, Func<TItem, TItemIdentifier> getItemIdentifier) | |
| { | |
| var snapshot = new NSDiffableDataSourceSnapshot<IdentifierType<TSection>, IdentifierType<TItem>>(); | |
| foreach (var section in sections) | |
| { | |
| var items = getItems(section); | |
| var sectionIdentifier = IdentifierType.For(section, getSectionIdentifier); | |
| var itemIdentifiers = items.Select(item => IdentifierType.For(item, getItemIdentifier)).ToArray(); | |
| snapshot.AppendSections(new[] { sectionIdentifier }); | |
| snapshot.AppendItems(itemIdentifiers); | |
| } | |
| return snapshot; | |
| } | |
| } |
| public class EasyUITableViewDiffableDataSource<TSection, TSectionIdentifier, TItem, TItemIdentifier> | |
| : UITableViewDiffableDataSource<IdentifierType<TSection>, IdentifierType<TItem>>, IUITableViewDiffableDataSource<TSection> | |
| { | |
| Func<TSection, TSectionIdentifier> _getSectionIdentifier; | |
| Func<TSection, IEnumerable<TItem>> _getSectionItems; | |
| Func<TItem, TItemIdentifier> _getItemIdentifier; | |
| Func<UITableView, int, TSection, string> _titleForHeader; | |
| Func<UITableView, int, TSection, string> _titleForFooter; | |
| NSDiffableDataSourceSnapshot<IdentifierType<TSection>, IdentifierType<TItem>> _snapshot; | |
| public EasyUITableViewDiffableDataSource( | |
| UITableView tableView, | |
| Func<TSection, TSectionIdentifier> getSectionIdentifier, | |
| Func<TSection, IEnumerable<TItem>> getSectionItems, | |
| Func<TItem, TItemIdentifier> getItemIdentifier, | |
| UITableViewDiffableDataSourceCellProvider cellProvider, | |
| Func<UITableView, int, TSection, string> titleForHeader = null, | |
| Func<UITableView, int, TSection, string> titleForFooter = null | |
| ) : base(tableView, cellProvider) | |
| { | |
| _getSectionIdentifier = getSectionIdentifier; | |
| _getSectionItems = getSectionItems; | |
| _getItemIdentifier = getItemIdentifier; | |
| _titleForHeader = titleForHeader; | |
| _titleForFooter = titleForFooter; | |
| } | |
| public void ApplySnapshot(IEnumerable<TSection> sections, bool animatingDifferences) | |
| { | |
| _snapshot = sections.ToDiffableDataSourceSnapshot( | |
| _getSectionIdentifier, _getSectionItems, _getItemIdentifier); | |
| ApplySnapshot(_snapshot, animatingDifferences); | |
| } | |
| public override string TitleForHeader(UITableView tableView, nint section) | |
| => _titleForHeader?.Invoke(tableView, (int)section, _snapshot.SectionIdentifiers[section].Item); | |
| public override string TitleForFooter(UITableView tableView, nint section) | |
| => _titleForFooter?.Invoke(tableView, (int)section, _snapshot.SectionIdentifiers[section].Item); | |
| } |
| public static class EasyUITableViewDiffableDataSource | |
| { | |
| public static IUITableViewDiffableDataSource<TSection> Create<TSection, TSectionIdentifier, TItem, TItemIdentifier>( | |
| UITableView tableView, | |
| List<TSection> items, | |
| Func<TSection, TSectionIdentifier> getSectionIdentifier, | |
| Func<TSection, IEnumerable<TItem>> getSectionItems, | |
| Func<TItem, TItemIdentifier> getItemIdentifier, | |
| Func<UITableView, NSIndexPath, TItem, UITableViewCell> getCell, | |
| Func<UITableView, int, TSection, string> titleForHeader = null, | |
| Func<UITableView, int, TSection, string> titleForFooter = null) | |
| => new EasyUITableViewDiffableDataSource<TSection, TSectionIdentifier, TItem, TItemIdentifier> | |
| ( | |
| tableView, getSectionIdentifier, getSectionItems, getItemIdentifier, | |
| (tv, indexPath, item) => getCell(tv, indexPath, (item as IdentifierType<TItem>).Item), | |
| titleForHeader, titleForFooter | |
| ); | |
| } |
| public class FuncIdentifierType<T,U> : IdentifierType<T> | |
| { | |
| private readonly Func<T, U> _identifierFunc; | |
| public FuncIdentifierType(T item, Func<T,U> identifierFunc) : base(item) | |
| { | |
| _identifierFunc = identifierFunc; | |
| } | |
| // invoke the provided func and hash the result | |
| public override nuint GetNativeHash() | |
| => (nuint)_identifierFunc(Item).GetHashCode(); | |
| public override bool IsEqual(NSObject anObject) | |
| => GetNativeHash() == anObject.GetNativeHash(); | |
| } |
| public static class IdentifierType | |
| { | |
| public static IdentifierType<T> For<T>(T item) => new IdentifierType<T>(item); | |
| public static IdentifierType<T> For<T,U>(T item, Func<T, U> getIdentifier) => new FuncIdentifierType<T,U>(item, getIdentifier); | |
| } | |
| public class IdentifierType<T> : NSObject | |
| { | |
| public readonly T Item; | |
| public IdentifierType(T item) | |
| { | |
| Item = item; | |
| } | |
| // pass-through the .NET hash | |
| public override nuint GetNativeHash() | |
| => (nuint) Item.GetHashCode(); | |
| public override bool IsEqual(NSObject anObject) | |
| => GetNativeHash() == anObject.GetNativeHash(); | |
| } |
| public interface IIdentifier | |
| { | |
| string Identifier { get; } | |
| } | |
| public class IIdentifierType<T> : IdentifierType<T> | |
| where T: IIdentifier | |
| { | |
| public IIdentifierType(T item) : base(item) {} | |
| // read the identifier and take its hash | |
| public override nuint GetNativeHash() | |
| => (System.nuint)Item.Identifier.GetHashCode(); | |
| public override bool IsEqual(NSObject anObject) | |
| => GetNativeHash() == anObject.GetNativeHash(); | |
| } |
| public interface IUITableViewDiffableDataSource<TSection> | |
| { | |
| void ApplySnapshot(IEnumerable<TSection> sections, bool animatingDifferences); | |
| } |
| public static NSDiffableDataSourceSnapshot<IdentifierType<TSection>, IdentifierType<TItem>> | |
| ToDiffableDataSourceSnapshot<TSection, TSectionIdentifier, TItem, TItemIdentifier>( | |
| this IEnumerable<TSection> sections, Func<TSection, TSectionIdentifier> getSectionIdentifier, | |
| Func<TSection, IEnumerable<TItem>> getItems, Func<TItem, TItemIdentifier> getItemIdentifier) | |
| { | |
| var snapshot = new NSDiffableDataSourceSnapshot<IdentifierType<TSection>, IdentifierType<TItem>>(); | |
| foreach (var section in sections) | |
| { | |
| var items = getItems(section); | |
| var sectionIdentifier = IdentifierType.For(section, getSectionIdentifier); | |
| var itemIdentifiers = items.Select(item => IdentifierType.For(item, getItemIdentifier)).ToArray(); | |
| snapshot.AppendSections(new[] { sectionIdentifier }); | |
| snapshot.AppendItems(itemIdentifiers); | |
| } | |
| return snapshot; | |
| } |
| public class IdentifierType<T> : NSObject | |
| { | |
| public readonly T Item; | |
| public IdentifierType(T item) | |
| { | |
| Item = item; | |
| } | |
| // pass-through the .NET hash | |
| public override nuint GetNativeHash() | |
| => (nuint) Item.GetHashCode(); | |
| public override bool IsEqual(NSObject anObject) | |
| => GetNativeHash() == anObject.GetNativeHash(); | |
| } |
| var source = | |
| EasyUITableViewDiffableDataSource.Create( | |
| TableView, | |
| items: Games, // used for type inference, can be null at the time of the call | |
| getSectionIdentifier: game => game.GameName, // return key for section | |
| getSectionItems: game => game.Characters, // return items for section | |
| getItemIdentifier: character => character.CharacterName, // return key for item | |
| getCell: (tv, indexPath, character) => // standard GetCell, but includes typed model parameter (character) | |
| { | |
| // yeah yeah cell reuse | |
| var cell = new UITableViewCell(UITableViewCellStyle.Default, "cell"); | |
| cell.TextLabel.Text = character.CharacterName; | |
| return cell; | |
| }, | |
| titleForHeader: (tv, sectionIndex, section) => section.GameName); |
Thank you for this article
I have error at this line
IdentifierType.For(section, getSectionIdentifier);
What is For méthod? is this an extension?
Do you have a full sample?
Thank you for your help
@am-kh Unfortunately I don't have the sample from the blogpost anymore.
Looks like this gist was missing at least one file which I have just added - IdentifierType.cs. If you add this hopefully you are up and running.
Yes! Thank you a lot.
Tell me, is it possible to have Hot Reload with Xamarin.iOS or the new Microsoft.iOS?
I saw you had it in your videos.
It will be great. Thank you !
@am-kh I added a small ios sample and quick video if it helps. The main issue at the moment is the 'register attribute' hack; since I am doing some Microsoft.iOS work soon I will improve this aspect. I improved that and updated the sample.
The code is super helpful and your article explained the diffable data sources much better than "native" articles about them! Thanks a lot!