I am fairly new to objective-c and I have ran into an issue that I have had a hard time solving..
I am using ShinobiDataGrid and using their prepareCellForDisplay.
To get text to display I would do this:
if([cell.coordinate.column.title isEqualToString:@"Task"]){
textCell.textField.textAlignment = NSTextAlignmentLeft;
textCell.textField.text = cellDataObj.task;
}
but for a particular cell, I am trying to add a custom button:
if([cell.coordinate.column.title isEqualToString:@"selected"]){
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.frame = CGRectMake(0, 10 , 32, 32);
if(cellDataObj.selected){
[button setImage:[UIImage imageNamed:@"checked-box.png"] forState:UIControlStateNormal];
}else{
[button setImage:[UIImage imageNamed:@"unchecked-box.png"] forState:UIControlStateNormal];
}
button.tag = cell.coordinate.row.rowIndex;
[button addTarget:self action:@selector(CheckBoxPressed:) forControlEvents:UIControlEventTouchUpInside];
[cell addSubview:button];
[button removeFromSuperview];
}
and I first run the app, the checkbox appears. but when I reload my ShinobiDataGrid the checkbox appears again. I tried removing the button from the superview, but that didn't work...any suggestions ? When I reload my ShinobiDataGrid a 3rd time, the checkbox does not appear for a 3rd time, just adds another when I reload the ShinobiDataGrid the 2nd time. Here is the whole method:
- (void)shinobiDataGrid:(ShinobiDataGrid *)grid prepareCellForDisplay:(SDataGridCell *)cell
{
SDataGridTextCell* textCell = (SDataGridTextCell*)cell;
CellData *cellDataObj = [cellHolderDisplay objectAtIndex:cell.coordinate.row.rowIndex];
textCell.textField.textAlignment = NSTextAlignmentCenter;
if([cell.coordinate.column.title isEqualToString:@"selected"]){
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.frame = CGRectMake(0, 10 , 32, 32);
if(cellDataObj.selected){
[button setImage:[UIImage imageNamed:@"checked-box.png"] forState:UIControlStateNormal];
}else{
[button setImage:[UIImage imageNamed:@"unchecked-box.png"] forState:UIControlStateNormal];
}
button.tag = cell.coordinate.row.rowIndex;
[button addTarget:self action:@selector(CheckBoxPressed:) forControlEvents:UIControlEventTouchUpInside];
[cell addSubview:button];
[button removeFromSuperview];
}
if([cell.coordinate.column.title isEqualToString:@"Task"]){
textCell.textField.textAlignment = NSTextAlignmentLeft;
textCell.textField.text = cellDataObj.task;
}
if([cell.coordinate.column.title isEqualToString:@"BLine. Start"]){
textCell.textField.text = cellDataObj.baselineDate;
}
}
Any suggestions ?
Here is the CheckBoxPressed method:
- (void)CheckBoxPressed:(UIButton *)sender
{
CellData *cell = [cellHolder objectAtIndex:sender.tag];
if([cell selected] == YES)
{
[[cell actualDate]setString:@""];
[[cell finishedDate] setString:@""];
[cell setSelected:NO];
}
else
{
if(([[cell actualDate] isEqualToString:@""]) && ([[cell finishedDate] isEqualToString:@""]))
{
[[cell actualDate]setString:[NSString stringWithFormat:@"%@ 8:00:00 AM",[self SetSpecialDateFormat:[NSDate date]]]];
[[cell finishedDate]setString:[NSString stringWithFormat:@"%@ 4:00:00 PM",[self SetSpecialDateFormat:[NSDate date]]]];
}
//actual date not populated but finish date populated
else if(([[cell actualDate]isEqualToString:@""]) && !([[cell finishedDate] isEqualToString:@""]))
{
[[cell actualDate]setString:[cell finishedDate]];
}
//finish date not populated but actual date populated
else if(!([[cell actualDate] isEqualToString:@""]) && ([[cell finishedDate] isEqualToString:@""]))
{
[[cell finishedDate]setString:[cell actualDate]];
}
[cell setSelected:YES];
}
[self UpdateEdittedCells:cell];
[self SetDisplayHolder];
//refresh grid
[gridReference reload];
}
(It's not entirely clear what effect you're after here, so I'm assuming that you would like to have a column filled with checkboxes, which are either checked or un-checked according to your data model)
The problem you are encountering is that the shinobi data grid re-uses cells, in order to optimise the memory usage. Therefore adding a button to a cell will mean that the button will be there as the cell is reused (when the grid is reloaded or scrolled).
You could remove the contents of the cell at the beginning of prepareCellForDisplay:
, and then you'd have an empty cell to which you can add your button:
- (void)shinobiDataGrid:(ShinobiDataGrid *)grid prepareCellForDisplay:(SDataGridCell *)cell
{
if([cell.coordinate.column.title isEqualToString:@"selected"]){
NSArray *cellSubviews = [cell.subviews copy];
for (UIView *subview in subviews) {
[subview removeFromSuperview];
}
// Now safe to add the button
}
}
However, this isn't the best approach.
You'd be much better creating a custom cell subclass for the selected
column. This cell would always have a button, and would therefore make much better use of the cell reuse mechanism.
To do this, create a subclass of SDataGridCell
, and register is with the grid, in the same way as you normally would. Then, when you get a callback in prepareCellForDisplay:
, you know that the type will be your custom one.
You can find specific instructions on achieving this in the ShinobiDataGrid userguide:
https://www.shinobicontrols.com/docs/ShinobiControls/ShinobiGrids/2.8.0/Standard/Normal/docs/markdown_files/DataGridUserGuide.html#How to: Creating custom cells
The example you're looking for is called "Creating custom cells", and is the last of the "How-tos", right at the bottom of the page.
This example is accompanied with a complete working sample, provided in the samples folder in the dmg that you downloaded. The difference with the sample is that it is using the datasource helper. Your code isn't, but it is fairly simple to translate the populateCell
method of the data source helper into the prepareCell
method you are used to using.