UILongPressGestureRecognizer *longPressGesture = [[[UILongPressGestureRecognizer alloc] initWithTarget: self action: @selector(longPress:)] autorelease]; [self addGestureRecognizer: longPressGesture]; NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; [center addObserver: self selector: @selector(unselectSelf:) name: UIMenuControllerWillHideMenuNotification object: nil]; - (void) unselectSelf: (NSNotification *) notification { self.selected = NO; } // unselectSelfIn the long press handler, check the state (to prevent multiple firings of the gesture recognizer from making the menus spaz out), and then set up the menu thing.
- (void) longPress: (UILongPressGestureRecognizer *) recognizer { if (recognizer.state != UIGestureRecognizerStateBegan) return; Put the stuff from Adding a pop up menu thingie here self.selected = YES; // Highlight to make it doubly-obvious what's being menu'd } // longPress
UITableViewCell *cell = ...; cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;The delegate method (accessoryTypeForRowWithIndexPath) has been deprecated, so don't use that.
Use UITableViewCellAccessoryCheckmark
for a checkmark.
Use UITableViewCellAccessoryNone
to remove the checkmark.
And then override these. In this case, I split up an array into an array of arrays, each sub-array being the contents of a section that corresponds to a string to display in the index. _tableIndex
is an array of strings for display of the index.
- (NSArray *) sectionIndexTitlesForTableView: (UITableView *) tableView { return _tableIndex; } // sectionIndexTitles - (NSInteger) tableView: (UITableView *) tableView sectionForSectionIndexTitle: (NSString *) title atIndex: (NSInteger) index { return index; } // sectionForSectionIndexTitle
if (someProperty) cell.textLabel.textColor = [UIColor grayColor]; else cell.textLabel.textColor = [UIColor blackColor];
- (BOOL) tableView: (UITableView *) tableView canMoveRowAtIndexPath: (NSIndexPath *) indexPath { if (indexPath.row == 0) return NO; else if (indexPath.row == _cues.count - 1) return NO; else return YES; } // canMoveRowAtIndexPathAnd then prevent rows from being dragged to the first and last position:
- (NSIndexPath *) tableView: (UITableView *) tableView targetIndexPathForMoveFromRowAtIndexPath: (NSIndexPath *) source toProposedIndexPath: (NSIndexPath *) destination { if (destination.row > 0 && destination.row < _cues.count - 1) { // No violence necessary. return destination; } NSIndexPath *indexPath = nil; // If your table can have <= 2 items, you might want to robusticize the index math. if (destination.row == 0) { indexPath = [NSIndexPath indexPathForRow: 1 inSection: 0]; } else { indexPath = [NSIndexPath indexPathForRow: _cues.count - 2 inSection: 0]; } return indexPath; } // targetIndexPathForMoveFromRowAtIndexPathPleaseOHaiThanksForMovingKthxBai
NSIndexPath *indexPath = [NSIndexPath indexPathForRow: row inSection: 0];
willSelectRowAtIndexPath
, return nil to reject the selection, return the passed-in indexPath to use as-is, or return your choice of selected cells.
- (NSIndexPath *) tableView: (UITableView *) tableView willSelectRowAtIndexPath: (NSIndexPath *) indexPath { // don't select the top row sort control. if (indexPath.row == 0) return nil; else return indexPath; } // willSelectRowAtIndexPath
- (IBAction) elaborateType: (id) sender { if (![sender isKindOfClass: [UIButton class]]) return; // be paranoid UITableViewCell *cell = (UITableViewCell *)[sender superview]; if (![cell isKindOfClass: [UITableViewCell class]]) return; // be paranoid NSIndexPath *indexPath = [self.kindPickerTableView indexPathForCell: cell]; // do something with indexPath.row and/or indexPath.section. } // elaborateType
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow]; if (indexPath != nil) [self doStuff];
- (void) tableView: (UITableView *) tableView commitEditingStyle: (UITableViewCellEditingStyle) editingStyle forRowAtIndexPath: (NSIndexPath *) indexPath { if (editingStyle == UITableViewCellEditingStyleDelete) { [_cues removeObjectAtIndex: indexPath.row]; // manipulate your data structure. [tableView deleteRowsAtIndexPaths: [NSArray arrayWithObject: indexPath] withRowAnimation: UITableViewRowAnimationFade]; [self updateUI]; // Do whatever other UI updating you need to do. } } // commitEditingStyle
-reloadData
, but don't. That's an awfully big hammer. Instead just reload a row
NSIndexPath *indexPath = [NSIndexPath indexPathForRow: row inSection: 0]; NSArray *array = [NSArray arrayWithObject: indexPath]; [_playlistTableView reloadRowsAtIndexPaths: array withRowAnimation: UITableViewRowAnimationNone];
layoutSubviews
in your UITableViewCell subclass. Any view position changes will automatically be animated.
- (void) layoutSubviews { // skootch stuff over if (self.editing && !self.showingDeleteConfirmation) { #define MARGIN 40.0 CGRect frame = CGRectMake (MARGIN + 4.0, 4.0, 70.0, 46.0); _profileView.frame = frame; frame = CGRectMake (MARGIN + 80.0, 0, 240.0 - MARGIN, 55.0); _titleLabel.frame = frame; // layout normally } else { CGRect frame = CGRectMake (4.0, 4.0, 70.0, 46.0); _profileView.frame = frame; frame = CGRectMake (80.0, 0, 240.0, 55.0); _titleLabel.frame = frame; } [super layoutSubviews]; } // layoutSubviewsThe
showingDeleteConfirmation
test is so you don't move things around if the user does the "swipe-right to show delete button" thing.-canEditRowAtIndexPath:
- (BOOL) tableView: (UITableView *) tableView canEditRowAtIndexPath: (NSIndexPath *) indexPath { if (indexPath.row == 0) return NO; else return YES; } // canEditRowAtIndexPath
[self.cuesTableView setEditing: YES animated: YES];
- (void) tableView: (UITableView *) tableView moveRowAtIndexPath: (NSIndexPath *) from toIndexPath: (NSIndexPath *) to { // How to rearrange stuff if you're backed by an NSMutableArray: GRCue *cue = [_cues objectAtIndex: from.row]; [cue retain]; // Let it survive being removed from the array. [_cues removeObjectAtIndex: from.row]; [_cues insertObject: cue atIndex: to.row]; [cue release]; } // moveRowAtIndexPath
- (void)tableView: (UITableView *) tableView didSelectRowAtIndexPath: (NSIndexPath *) indexPath { // Do something logical with indexPath.row, etc. } // didSelectRowAtIndexPath
NSIndexPath *someRow = [NSIndexPath indexPathForRow: random() % blah.count inSection: 0]; [self.cuesTableView scrollToRowAtIndexPath: someRow atScrollPosition: UITableViewScrollPositionBottom animated: YES];You can also scroll to PositionTop and PositionMiddle. If you crash, make sure you've done a
-reloadData
on the table view prior to trying to scroll.NSIndexPath *indexPath = [NSIndexPath indexPathForRow: index inSection: 0]; [self.tableView reloadData]; // necessary if selecting row in -viewDidLoad [self.tableView selectRowAtIndexPath: indexPath animated: YES scrollPosition: UITableViewScrollPositionNone];
cell.textLabel.backgroundColor = [UIColor redColor]; cell.contentView.backgroundColor = [UIColor redColor];
UIImage *image = [_assets iconAtIndex: indexPath.row]; if (image) cell.imageView.image = image;
// Optional - (NSInteger) numberOfSectionsInTableView: (UITableView *) tableView { return 1; } // numberOfSectionsInTableView - (NSInteger) tableView: (UITableView *) tableView numberOfRowsInSection: (NSInteger) section { return dataArray.count; } // numberOfRowsInSection - (UITableViewCell *) tableView: (UITableView *) tableView cellForRowAtIndexPath: (NSIndexPath *) indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: @"BlahTableViewCell"]; if (!cell) { cell = [[UITableViewCell alloc] initWithStyle: UITableViewCellStyleDefault reuseIdentifier: @"BlahTableViewCell"]; [cell autorelease]; // Delete for ARC } cell.textLabel.text = [dataArray objectAtIndex: indexPath.row]; return cell; } // cellForRowAtIndexPath
Make the cell with UITableViewCellStyleSubtitle
:
cell = [[[UITableViewCell alloc] initWithStyle: UITableViewCellStyleSubtitle reuseIdentifier: @"UITableViewCell"] autorelease];and set the label values:
cell.textLabel.text = @"somewhere"; cell.detailTextLabel.text = @"over the rainbow";
_tableView.scrollEnabled = NO;
- (NSString *) tableView: (UITableView *) tableview titleForHeaderInSection: (NSInteger) section { NSArray *sections = [BWTermStorage sections]; return [sections objectAtIndex: section]; } // titleForHeaderInSectionYou can return a title for a footer.
You can also return a view:
- (UIView *) tableView: (UITableView *) tableView viewForHeaderInSection: (NSInteger) section;
The appropriate constants are
UITableViewCellStyleDefault
, UITableViewCellStyleValue1
, UITableViewCellStyleValue2
, and UITableViewCellStyleSubtitle
, and settable properties include imageView
, textLabel
, and detailTextLabe
l.
1) Make a nib with a single object at the top, a UITableViewCell
. Lay it out as you wish. I use view tags to get to the objects contained therein.
enum { kTermLabelTag = 1, kDetailLabelTag = 2 };
2) Register the nib for a cell reuse identifier. I do it in my -viewDidLoad
.
static NSString *g_cellReuseIdentifier = @"BWLookupCellReuseIdentifier"; // file global ... UINib *nib = [UINib nibWithNibName: @"BWLookupTableViewCell" bundle: nil]; [self.resultsView registerNib: nib forCellReuseIdentifier: g_cellReuseIdentifier];3) Dequeue the cell as usual
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: g_cellReuseIdentifier]; if (!cell) { cell = [[UITableViewCell alloc] initWithStyle: UITableViewCellStyleSubtitle reuseIdentifier: g_cellReuseIdentifier]; }4) Dig into the cell with the tags, and go nuts
UILabel *termLabel = (UILabel *)[cell viewWithTag: kTermLabelTag]; UILabel *detailLabel = (UILabel *)[cell viewWithTag: kDetailLabelTag]; termLabel.text = termString; detailLabel.text = definition;
Or you can hack it by setting the cell's indent to 1. That scoots the whole cell contents over by 10 pixels, letting you miss the rounded corners. Really handy if you're prototyping, want something to look non-horrible, but don't want to go the full-blown correct solution.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) { guard let selectedRow = self.tableView.indexPathForSelectedRow else { return } guard let vc = segue.destination as? InfographicViewController else { return } let counter = counters[selectedRow.row] let stats = counter.currentTextStats vc.stats = stats }
@IBOutlet var sessionsTableView : UITableView! let cellReuseIdentifier = "Cell" ... override func viewDidLoad() { super.viewDidLoad() self.sessionsTableView.register(UITableViewCell.self, forCellReuseIdentifier: cellReuseIdentifier) } ... extension ViewController : UITableViewDataSource { func numberOfSections(in tableView: UITableView) -> Int { return 1 } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return 10 } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier, for: indexPath) as UITableViewCell cell.textLabel?.text = "Spork (indexPath.row)" return cell } }