ListView: Grouping

ListView may be set up to display items in groups divided visually by section headers and footers.
There are two ways to implement grouping with TKListView - manually implementing the required methods of the TKListViewDataSource delegate or using TKDataSource and let it do the dirty work for you.

Displaying grouped data using TKDataSource

In case you need more flexibility you may implement grouping manualy as follows.

@implementation ListViewDocsGroups
{
    TKDataSource *dataSource;
    NSMutableArray *_items;
    NSArray *_groups;
}

- (void) viewDidLoad
{
    [super viewDidLoad];

    _groups= @[@[@"John",@"Abby"],@[@"Smith",@"Peter",@"Paula"]];

    _items = [NSMutableArray new];
    [_items addObject:[[DataSourceItem alloc] initWithName:@"John" value:50 group:@"A"]];
    [_items addObject:[[DataSourceItem alloc] initWithName:@"Abby" value:33 group:@"A"]];
    [_items addObject:[[DataSourceItem alloc] initWithName:@"Smith" value:42 group:@"B"]];
    [_items addObject:[[DataSourceItem alloc] initWithName:@"Peter" value:28 group:@"B"]];
    [_items addObject:[[DataSourceItem alloc] initWithName:@"Paula" value:25 group:@"B"]];

    dataSource = [TKDataSource new];
    dataSource.itemSource = _items;
    dataSource.groupItemSourceKey = @"name";
    [dataSource groupWithKey:@"group"];

    TKListView *_listView = [[TKListView alloc] initWithFrame: CGRectMake(20, 20, self.view.bounds.size.width-40,self.view.bounds.size.height-40)];

    _listView.dataSource = dataSource;
    TKListViewLinearLayout *layout = (TKListViewLinearLayout*)_listView.layout;
    layout.headerReferenceSize = CGSizeMake(200, 22);

    [self.view addSubview:_listView];
}

@end
class ListViewDocsGroups: UIViewController {

    var dataSource: TKDataSource?
    var items = [DataSourceItem]()

    override func viewDidLoad() {
        super.viewDidLoad()

        items.append(DataSourceItem(name: "John", value: 50, group: "A"))
        items.append(DataSourceItem(name: "Abby", value: 33, group: "A"))
        items.append(DataSourceItem(name: "Smith", value: 42, group: "B"))
        items.append(DataSourceItem(name: "Peter", value: 28, group: "B"))
        items.append(DataSourceItem(name: "Paula", value: 25, group: "B"))

        dataSource = TKDataSource()
        dataSource?.itemSource = items
        dataSource?.group(withKey: "group")
        dataSource?.displayKey = "name"
        let listView = TKListView(frame: CGRect(x: 20, y: 20, width: self.view.bounds.size.width-40,height: self.view.bounds.size.height-40))

        listView.dataSource = dataSource
        let layout = listView.layout as! TKListViewLinearLayout
        layout.headerReferenceSize = CGSize(width: 200, height: 22)
        self.view.addSubview(listView)
    }
}
NSMutableArray items = new NSMutableArray ();
items.Add (new DataSourceItem ("John", 50f, "A"));
items.Add (new DataSourceItem ("Abby", 33f, "A"));
items.Add (new DataSourceItem ("Smith", 42f, "B"));
items.Add (new DataSourceItem ("Peter", 28f, "B"));
items.Add (new DataSourceItem ("Paula", 25f, "B"));

this.dataSource = new TKDataSource ();
this.dataSource.ItemSource = items;
this.dataSource.GroupWithKey ("Group");
dataSource.DisplayKey = "Name";

TKListView listView = new TKListView (new CGRect (20, 20, this.View.Bounds.Size.Width - 40, this.View.Bounds.Size.Height - 40));
listView.WeakDataSource = dataSource;
this.View.AddSubview (listView);

var layout = listView.Layout as TKListViewLinearLayout;
layout.HeaderReferenceSize = new CGSize (200, 22);

Displaying grouped data using a TKListViewDataSource delegate methods

@implementation ListViewDocsGroupsDelegate
{
    NSMutableArray *_items;
    NSArray *_groups;
}

- (void) viewDidLoad
{
    [super viewDidLoad];

    _groups= @[@[@"John",@"Abby"],@[@"Smith",@"Peter",@"Paula"]];

    _items = [NSMutableArray new];
    [_items addObject:[[DataSourceItem alloc] initWithName:@"John" value:50 group:@"A"]];
    [_items addObject:[[DataSourceItem alloc] initWithName:@"Abby" value:33 group:@"A"]];
    [_items addObject:[[DataSourceItem alloc] initWithName:@"Smith" value:42 group:@"B"]];
    [_items addObject:[[DataSourceItem alloc] initWithName:@"Peter" value:28 group:@"B"]];
    [_items addObject:[[DataSourceItem alloc] initWithName:@"Paula" value:25 group:@"B"]];

    TKListView *_listView = [[TKListView alloc] initWithFrame: CGRectMake(20, 20, self.view.bounds.size.width-40,self.view.bounds.size.height-40)];

    [_listView registerClass:[TKListViewCell class] forCellWithReuseIdentifier:@"cell"];

    [_listView registerClass:[TKListViewHeaderCell class] forSupplementaryViewOfKind:TKListViewElementKindSectionHeader withReuseIdentifier:@"header"];

    _listView.dataSource = self;
    TKListViewLinearLayout *layout = (TKListViewLinearLayout*)_listView.layout;
    layout.headerReferenceSize = CGSizeMake(200, 22);

    [self.view addSubview:_listView];
}

-(NSInteger) numberOfSectionsInListView:(TKListView *)listView
{
    return _groups.count;
}

-(NSInteger) listView:(TKListView *)listView numberOfItemsInSection:(NSInteger)section
{
    return ((NSArray*)_groups[section]).count;
}

-(TKListViewCell*) listView:(TKListView *)listView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    TKListViewCell *cell = [listView dequeueReusableCellWithReuseIdentifier:@"cell" forIndexPath:indexPath];
    cell.textLabel.text = _groups[indexPath.section][indexPath.row];

    return cell;
}

-(TKListViewReusableCell*) listView:(TKListView *)listView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
    TKListViewReusableCell *headerCell = [listView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:@"header" forIndexPath:indexPath];
    headerCell.textLabel.text = [NSString stringWithFormat:@"Group %li",indexPath.section];
    return headerCell;
}

@end
class ListViewDocsGroupsDelegate: UIViewController, TKListViewDataSource {
    var items = [DataSourceItem]()
    let groups = [["John","Abby"],["Smith","Peter","Paula"]]

    override func viewDidLoad() {
        super.viewDidLoad()

        items.append(DataSourceItem(name: "John", value: 50, group: "A"))
        items.append(DataSourceItem(name: "Abby", value: 33, group: "A"))
        items.append(DataSourceItem(name: "Smith", value: 42, group: "B"))
        items.append(DataSourceItem(name: "Peter", value: 28, group: "B"))
        items.append(DataSourceItem(name: "Paula", value: 25, group: "B"))

        let listView = TKListView(frame: CGRect(x: 20, y: 20, width: self.view.bounds.size.width-40,height: self.view.bounds.size.height-40))
        listView.register(TKListViewCell.self, forCellWithReuseIdentifier: "cell")
        listView.register(TKListViewHeaderCell.self, forSupplementaryViewOfKind: TKListViewElementKindSectionHeader, withReuseIdentifier: "header")
        listView.dataSource = self
        let layout = listView.layout as! TKListViewLinearLayout
        layout.headerReferenceSize = CGSize(width: 200, height: 22)
        self.view.addSubview(listView)
    }

    func numberOfSections(in listView: TKListView) -> Int {
        return groups.count
    }

    func listView(_ listView: TKListView, numberOfItemsInSection section: Int) -> Int {
        return groups[section].count
    }

    func listView(_ listView: TKListView, cellForItemAt indexPath: IndexPath) -> TKListViewCell? {
        let cell = listView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! TKListViewCell
        cell.textLabel.text = groups[(indexPath as NSIndexPath).section][(indexPath as NSIndexPath).row]

        return cell
    }

    func listView(_ listView: TKListView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> TKListViewReusableCell? {
        let headerCell = listView.dequeueReusableSupplementaryView(ofKind: TKListViewElementKindSectionHeader, withReuseIdentifier: "header", for: indexPath) as! TKListViewHeaderCell
        headerCell.textLabel.text = "Group \((indexPath as NSIndexPath).section)"

        return headerCell
    }
}
public class ListViewDocsGroupsDelegate : XamarinExampleViewController
{
    public NSMutableArray groups;

    public ListViewDocsGroupsDelegate ()
    {
    }

    public override void ViewDidLoad ()
    {
        base.ViewDidLoad ();
        groups = new NSMutableArray ();
        groups.Add (NSArray.FromStrings (new string[] { "John", "Abby" }));
        groups.Add(NSArray.FromStrings (new string[] { "Smith", "Peter", "Paula" }));

        TKListView listView = new TKListView (new CGRect (20, 20, this.View.Bounds.Size.Width - 40, this.View.Bounds.Size.Height - 40));
        listView.RegisterClassForCell (new Class (typeof(TKListViewCell)), "cell");

        listView.RegisterClassForSupplementaryView (new Class (typeof(TKListViewHeaderCell)), TKListViewElementKindSectionKey.Header, new NSString("header"));
        listView.DataSource = new ListViewDataSource (this);
        TKListViewLinearLayout layout = (TKListViewLinearLayout)listView.Layout;
        layout.HeaderReferenceSize = new CGSize (200, 22);

        this.View.AddSubview (listView);
    }
}

class ListViewDataSource : TKListViewDataSource
{
    ListViewDocsGroupsDelegate owner;

    public ListViewDataSource (ListViewDocsGroupsDelegate owner)
    {
        this.owner = owner;
    }

    public override int NumberOfSectionsInListView (TKListView listView)
    {
        return (int)this.owner.groups.Count;
    }

    public override int NumberOfItemsInSection (TKListView listView, int section)
    {
        return (int)this.owner.groups.GetItem<NSArray>((uint)section).Count;
    }

    public override TKListViewCell CellForItem (TKListView listView, NSIndexPath indexPath)
    {
        TKListViewCell cell = listView.DequeueReusableCell("cell", indexPath) as TKListViewCell;
        cell.TextLabel.Text = this.owner.groups.GetItem<NSArray> ((uint)indexPath.Section).GetItem<NSString> ((uint)indexPath.Row);
        return cell;
    }

    public override TKListViewReusableCell ViewForSupplementaryElementOfKind (TKListView listView, NSString kind, NSIndexPath indexPath)
    {
        TKListViewReusableCell headerCell = listView.DequeueReusableSupplementaryView(kind, "header", indexPath) as TKListViewReusableCell;
        headerCell.TextLabel.Text = String.Format ("Group {0}", indexPath.Section);
        return headerCell;
    }
}