TKDataSource
works well with data enabled controls and provides an easy way to shape and present your data. The currently supported UI controls are:
This article describes how to bind TKDataSource
and customize those controls.
Setting the dataSource
property is enough in order to present data in UITableView
. TKDataSource
will take care of the implementation of all methods in UITableViewDataSource
protocol:
self.dataSource = [[TKDataSource alloc] initWithArray:@[ @10, @5, @12, @7, @44 ]];
UITableView *tableView = [[UITableView alloc] initWithFrame:self.view.bounds];
tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
tableView.dataSource = self.dataSource;
[self.view addSubview:tableView];
let dataSource = TKDataSource(array: [ 10, 5, 12, 13, 7, 44 ])
let tableView = UITableView(frame: self.view.bounds.insetBy(dx: 0, dy: 30))
tableView.autoresizingMask = UIViewAutoresizing(rawValue: UIViewAutoresizing.flexibleWidth.rawValue | UIViewAutoresizing.flexibleHeight.rawValue)
tableView.dataSource = dataSource
self.view.addSubview(tableView)
NSObject[] array = new NSObject[] {
NSObject.FromObject (10),
NSObject.FromObject (5),
NSObject.FromObject (12),
NSObject.FromObject (13),
NSObject.FromObject (7),
NSObject.FromObject (44)
};
this.dataSource = new TKDataSource (array);
CGRect rect = this.View.Bounds;
rect.Inflate (0, -30);
UITableView table = new UITableView (rect);
table.AutoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight;
table.DataSource = this.dataSource;
this.View.AddSubview (table);
You can specify displayKey
and valueKey
properties to specify what to display in table view cells:
NSMutableArray *items = [NSMutableArray new];
[items addObject:[[DSItem alloc] initWithName:@"John" value:50 group:@"A"]];
[items addObject:[[DSItem alloc] initWithName:@"Abby" value:33 group:@"A"]];
[items addObject:[[DSItem alloc] initWithName:@"Smith" value:42 group:@"B"]];
[items addObject:[[DSItem alloc] initWithName:@"Peter" value:28 group:@"B"]];
[items addObject:[[DSItem alloc] initWithName:@"Paula" value:25 group:@"B"]];
dataSource = [TKDataSource new];
dataSource.itemSource = items;
dataSource.displayKey = @"name";
var items = [DataSourceItem]()
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.itemSource = items
dataSource.displayKey = "name"
NSMutableArray items = new NSMutableArray();
items.Add (new DSItem () { Name = "John", Value = 50, Group = "A" });
items.Add (new DSItem () { Name = "Abby", Value = 33, Group = "A" });
items.Add (new DSItem () { Name = "Smith", Value = 42, Group = "B" });
items.Add (new DSItem () { Name = "Peter", Value = 28, Group = "B" });
items.Add (new DSItem () { Name = "Paula", Value = 25, Group = "B" });
this.dataSource = new TKDataSource ();
this.dataSource.ItemSource = items;
this.dataSource.DisplayKey = "Name";
In the majority of the scenarios you will also need to customize the cells. In this case you can implement the initCell
block from TKDataSourceTableViewSettings
class:
[self.dataSource.settings.tableView initCell:^(UITableView *tableView, NSIndexPath *indexPath, UITableViewCell *cell, id item) {
cell.textLabel.text = @"Item:";
cell.detailTextLabel.text = [self.dataSource textFromItem:item inGroup:nil];
}];
dataSource.settings.tableView .initCell({ (tableView, indexPath, cell, item) -> Void in
cell.textLabel?.text = "Item:"
cell.detailTextLabel?.text = dataSource.text(fromItem: item, in: nil)
});
this.dataSource.Settings.TableView.InitCell ((UITableView tableView, NSIndexPath indexPath, UITableViewCell cell, NSObject item) => {
cell.TextLabel.Text = "Item:";
cell.DetailTextLabel.Text = this.dataSource.TextFromItem(item, null);
});
If this is not enough to achieve to look you want, you can create your custom cells by using the createCell
block function:
[self.dataSource.settings.tableView createCell:^UITableViewCell *(UITableView *tableView, NSIndexPath *indexPath, id item) {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:@"cell"];
}
return cell;
}];
dataSource.settings.tableView.createCell { (tableView, indexPath, item) -> UITableViewCell in
var cell = tableView.dequeueReusableCell(withIdentifier: "cell")
if cell == nil {
cell = UITableViewCell(style:UITableViewCellStyle.value1, reuseIdentifier:"cell")
}
return cell!
}
this.dataSource.Settings.TableView.CreateCell ((UITableView tableView, NSIndexPath indexPath, NSObject item) => {
UITableViewCell cell = tableView.DequeueReusableCell("cell");
if (cell == null) {
cell = new UITableViewCell(UITableViewCellStyle.Value1, "cell");
}
return cell;
});
TKDataSource
will take care of everything and no code is necessary even when your data is grouped:
[self.dataSource group:^id(id item) {
return @([item intValue] % 2 == 0);
}];
dataSource.group({ (item: Any) -> Any in
return ((item as! NSNumber).int32Value % 2 == 0);
})
this.dataSource.Group ((NSObject item) => {
return NSObject.FromObject(((NSNumber)item).Int32Value % 2 == 0);
});
TKDataSource
integrates well with UICollectionView
. Just set the dataSource
property and prepare the collection view:
UICollectionViewFlowLayout *layout = [UICollectionViewFlowLayout new];
layout.itemSize = CGSizeMake(140, 140);
UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:CGRectInset(self.view.bounds, 0, 30) collectionViewLayout:layout];
collectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
collectionView.dataSource = self.dataSource;
collectionView.backgroundColor = [UIColor whiteColor];
[self.view addSubview:collectionView];
let layout = UICollectionViewFlowLayout()
layout.itemSize = CGSize(width: 140, height: 140)
let collectionView = UICollectionView(frame:self.view.bounds.insetBy(dx: 0, dy: 30), collectionViewLayout:layout)
collectionView.autoresizingMask = UIViewAutoresizing(rawValue: UIViewAutoresizing.flexibleWidth.rawValue | UIViewAutoresizing.flexibleHeight.rawValue)
collectionView.dataSource = dataSource
collectionView.backgroundColor = UIColor.white
self.view.addSubview(collectionView)
var layout = new UICollectionViewFlowLayout();
layout.ItemSize = new CGSize (140, 140);
CGRect rect = this.View.Bounds;
rect.Inflate (0, -30);
var collectionView = new UICollectionView (rect, layout);
collectionView.AutoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight;
collectionView.DataSource = this.dataSource;
collectionView.BackgroundColor = UIColor.White;
this.View.AddSubview(collectionView);
Use the collection view settings class and its initCell
in case you want to customize the cell appearance:
[self.dataSource.settings.collectionView initCell:^(UICollectionView *collectionView, NSIndexPath *indexPath, UICollectionViewCell *cell, id item) {
TKCollectionViewCell *tkcell = (TKCollectionViewCell*)cell;
tkcell.label.text = [self.dataSource textFromItem:item inGroup:nil];
tkcell.backgroundColor = [UIColor yellowColor];
}];
dataSource.settings.collectionView.initCell({ (collectionView, indexPath,
cell, item) -> Void in
let tkCell = cell as! TKCollectionViewCell
tkCell.label.text = dataSource.text(fromItem: item, in: nil)
});
this.dataSource.Settings.CollectionView.InitCell ((UICollectionView collection, NSIndexPath indexPath, UICollectionViewCell cell, NSObject item) => {
var tkCell = cell as TKCollectionViewCell;
tkCell.Label.Text = this.dataSource.TextFromItem(item, null);
tkCell.BackgroundColor = UIColor.Yellow;
});
You can also easily use TKListView
with TKDataSource
:
TKListView *listView = [[TKListView alloc] initWithFrame:CGRectInset(self.view.bounds, 0, 30)];
listView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
listView.dataSource = self.dataSource;
[self.view addSubview:listView];
let listView = TKListView(frame:self.view.bounds.insetBy(dx: 0, dy: 30))
listView.autoresizingMask = UIViewAutoresizing(rawValue: UIViewAutoresizing.flexibleWidth.rawValue | UIViewAutoresizing.flexibleHeight.rawValue)
listView.dataSource = dataSource
self.view.addSubview(listView)
CGRect rect = this.View.Bounds;
rect.Inflate (0, -30);
var listView = new TKListView (rect);
listView.AutoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight;
this.dataSource.SetDataSourceFor (listView);
this.View.AddSubview (listView);
The initCell
and createCell
methods can be used to customize the cell appearance:
[self.dataSource.settings.listView createCell:^TKListViewCell *(TKListView *listView, NSIndexPath *indexPath, id item) {
return [listView dequeueReusableCellWithReuseIdentifier:@"myCustomCell" forIndexPath:indexPath];
}];
[self.dataSource.settings.listView initCell:^(TKListView *listView, NSIndexPath *indexPath, TKListViewCell *cell, id item) {
cell.textLabel.text = [self.dataSource textFromItem:item inGroup:nil];
((TKView*)cell.backgroundView).fill = [TKSolidFill solidFillWithColor:[UIColor colorWithWhite:0.1 alpha:0.1]];
}];
dataSource.settings.listView.createCell({ (listView, indexPath, item) -> TKListViewCell! in
return listView.dequeueReusableCell(withReuseIdentifier: "myCustomCell", for:indexPath) as! TKListViewCell
})
dataSource.settings.listView.initCell({ (listView, indexPath, cell, item) -> Void in
cell.textLabel.text = dataSource.text(fromItem: item, in:nil)
(cell.backgroundView as! TKView).fill = TKSolidFill(color: UIColor(white: 0.1, alpha: 0.1))
})
this.dataSource.Settings.ListView.CreateCell ((TKListView list1, NSIndexPath indexPath, NSObject item) => {
return list1.DequeueReusableCell("myCustomCell", indexPath) as TKListViewCell;
});
this.dataSource.Settings.ListView.InitCell ((TKListView list2, NSIndexPath indexPath, TKListViewCell cell, NSObject item) => {
cell.TextLabel.Text = this.dataSource.TextFromItem(item, null);
(cell.BackgroundView as TKView).Fill = new TKSolidFill(new UIColor(0.1f, 0.1f, 0.1f, 0.1f));
});
In order to present data in TKChart
, you need to set the displayKey
and valueKey
properties. The displayKey
defines the x-axis values, and the valueKey
defines the y-axis values:
NSMutableArray *items = [NSMutableArray new];
[items addObject:[[DSItem alloc] initWithName:@"John" value:50 group:@"A"]];
[items addObject:[[DSItem alloc] initWithName:@"Abby" value:33 group:@"A"]];
[items addObject:[[DSItem alloc] initWithName:@"Paula" value:33 group:@"A"]];
[items addObject:[[DSItem alloc] initWithName:@"John" value:42 group:@"B"]];
[items addObject:[[DSItem alloc] initWithName:@"Abby" value:28 group:@"B"]];
[items addObject:[[DSItem alloc] initWithName:@"Paula" value:25 group:@"B"]];
self.dataSource.displayKey = @"name";
self.dataSource.valueKey = @"value";
self.dataSource.itemSource = items;
TKChart *chart = [[TKChart alloc] initWithFrame:self.view.bounds];
chart.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
chart.dataSource = self.dataSource;
[self.view addSubview:chart];
var items:Array<DataSourceItem> = []
items.append(DataSourceItem(name: "John", value: 50, group:"A"))
items.append(DataSourceItem(name: "Abby", value: 33, group:"A"))
items.append(DataSourceItem(name: "Paula", value: 33, group:"A"))
items.append(DataSourceItem(name: "John", value: 42, group:"B"))
items.append(DataSourceItem(name: "Abby", value: 28, group:"B"))
items.append(DataSourceItem(name: "Paula", value: 25, group:"B"))
dataSource.displayKey = "name"
dataSource.valueKey = "value"
dataSource.itemSource = items
let chart = TKChart(frame:self.view.bounds)
chart.autoresizingMask = UIViewAutoresizing(rawValue: UIViewAutoresizing.flexibleWidth.rawValue | UIViewAutoresizing.flexibleHeight.rawValue)
chart.dataSource = dataSource
self.view.addSubview(chart)
NSMutableArray items = new NSMutableArray ();
items.Add (new DSItem () { Name = "John", Value = 50, Group = "A" });
items.Add (new DSItem () { Name = "Abby", Value = 33, Group = "A" });
items.Add (new DSItem () { Name = "Paula", Value = 33, Group = "A" });
items.Add (new DSItem () { Name = "John", Value = 42, Group = "B" });
items.Add (new DSItem () { Name = "Abby", Value = 28, Group = "B" });
items.Add (new DSItem () { Name = "Paula", Value = 25, Group = "B" });
this.dataSource.DisplayKey = "Name";
this.dataSource.ValueKey = "Value";
this.dataSource.ItemSource = items;
var chart = new TKChart(this.View.Bounds);
chart.AutoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight;
chart.DataSource = this.dataSource;
this.View.AddSubview(chart);
In order to present different series the data should be grouped. When this is done the createSeries
method can be used to customize the series that should be created:
[self.dataSource groupWithKey:@"group"];
[self.dataSource.settings.chart createSeries:^TKChartSeries *(TKDataSourceGroup *group) {
TKChartColumnSeries *series = [TKChartColumnSeries new];
return series;
}];
dataSource.group(withKey: "group")
dataSource.settings.chart.createSeries({ (group) -> TKChartSeries! in
let series = TKChartColumnSeries()
return series
})
this.dataSource.GroupWithKey ("Group");
this.dataSource.Settings.Chart.CreateSeries ((TKDataSourceGroup group) => {
var series = new TKChartColumnSeries();
return series;
});
TKDataSource
is able to represent your data as calendar events. In this scenario you should set the startDateKey
and endDateKey
properties:
self.dataSource.displayKey = @"name";
self.dataSource.settings.calendar.startDateKey = @"startDate";
self.dataSource.settings.calendar.endDateKey = @"endDate";
self.dataSource.settings.calendar.defaultEventColor = [UIColor redColor];
self.dataSource.itemSource = items;
TKCalendar *calendar = [[TKCalendar alloc] initWithFrame:CGRectInset(self.view.bounds, 0, 30)];
calendar.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
calendar.dataSource = self.dataSource;
[self.view addSubview:calendar];
dataSource.displayKey = "name"
dataSource.settings.calendar.startDateKey = "startDate"
dataSource.settings.calendar.endDateKey = "endDate"
dataSource.settings.calendar.defaultEventColor = UIColor.red
dataSource.itemSource = items
let calendar = TKCalendar(frame:self.view.bounds.insetBy(dx: 0, dy: 30))
calendar.autoresizingMask = UIViewAutoresizing(rawValue: UIViewAutoresizing.flexibleWidth.rawValue | UIViewAutoresizing.flexibleHeight.rawValue)
calendar.dataSource = dataSource
self.view.addSubview(calendar)
this.dataSource.DisplayKey = "Name";
this.dataSource.Settings.Calendar.StartDateKey = "StartDate";
this.dataSource.Settings.Calendar.EndDateKey = "EndDate";
this.dataSource.Settings.Calendar.DefaultEventColor = UIColor.Red;
this.dataSource.ItemSource = items;
var calendar = new TKCalendar (this.View.Bounds);
calendar.AutoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight;
this.dataSource.SetDataSourceFor (calendar);
this.View.AddSubview (calendar);