I have table with cells; each cell contain label with phone number. When i tap on the label, UIMenuController appears.
Is there a main way to find indexPath of cell, which contain selected label? (didSelectRowAtIndexPath: should not be called)
I can imagine many dirty hacks, but i looking for a main/good solution.
upd
I have reference to selected label.
Edit:
This is a better way.
- (IBAction)someMethod:(id)sender {
CGPoint hitPoint = [sender convertPoint:CGPointZero toView:self.tableView];
NSIndexPath *hitIndex = [self.tableView indexPathForRowAtPoint:hitPoint];
}
From your label, search for the cell object in the label's hierarchy:
-(UITableViewCell*) cellContainingView:(UIView*)view
{
UIView* currentView = view;
while (currentView)
{
if ([currentView isKindOfClass:[UITableViewCell class]])
{
return (UITableViewCell*)currentView;
}
currentView = currentView.superview;
}
return nil;
}
Once you have the cell, call [tableView indexPathForCell:cell]
The use of this method instead of hard coding view.superview.superview makes your code stronger because it handle possible changes in cell's view hierarchy through system's versions.
You could go:
NSMutableArray *cells = [[NSMutableArray alloc] init];
for (NSInteger j = 0; j < [tableView numberOfSections]; ++j)
{
for (NSInteger i = 0; i < [tableView numberOfRowsInSection:j]; ++i)
{
[cells addObject:[tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:j]]];
}
}
for (UITableViewCell *cell in cells){
for (UILabel *label in cell.subviews){
if (label == yourLabel)
indexPath = [tableView indexPathForCell: cell];
}
}
Related
I'm creating a custom UITableView with expand / collapse functionality. When the user taps in a table section, new rows are inserted using this code:
[self.tableView beginUpdates];
NSMutableArray *arrIP = [NSMutableArray new];
for (NSInteger i=0; i<[rows count]; i++){
#autoreleasepool {
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:i inSection:section];
[arrIP addObject:indexPath];
}
}
[self.tableView insertRowsAtIndexPaths:arrIP withRowAnimation:UITableViewRowAnimationNone];
[self.tableView endUpdates];
Everything works fine but sometimes the tableView don't fit well to their content size. My problem is according to some cells that are drawn behind the expanded section that are touched when I'm scrolling up.
Here's the code to draw sections:
- (UIView *)tableView:(UITableView *)theTableView viewForHeaderInSection:(NSInteger)section {
id sectionKey = [_dataSource objectAtIndex:section][#"section"];
CGFloat sectionHeight = [[_dataSource objectAtIndex:section][#"header_height"] floatValue];
if ([sectionKey isKindOfClass:[NSString class]] && [sectionKey isEqualToString:#"info"]){
OptionCell *cell = [theTableView dequeueReusableCellWithIdentifier:OptionCell.cellIdentifier];
if (cell == nil){
cell = [[OptionCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:OptionCell.cellIdentifier];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
}
return cell;
}else if ([sectionKey isKindOfClass:[NSString class]] && [sectionKey isEqualToString:#"history"]){
NSArray *nibArray = [[NSBundle mainBundle] loadNibNamed:#"ExpandedHeader" owner:self options:nil];
ExpandedHeader *headerView = [nibArray objectAtIndex:0];
headerView.BTN_loadData.tag = section;
[headerView.BTN_loadData addTarget:self action:#selector(loadData:) forControlEvents:UIControlEventTouchUpInside];
[headerView setFrame:CGRectMake(0, 0, self.tableView.frame.size.width, sectionHeight)];
return headerView;
}
}
I don't understand what I'm doing wrong.
Thanks in advance!
I have a custom UITableView with UITextFields inside. In cellForRow... I made the textFields delegate to self. (In my main VC class.) The way I get the text from the textField is at textFieldDidEndEditing, and I add it to a mutableArray.
I then have different cell ids that get added when a button gets selected:
- (IBAction)addRow:(id)sender
{
NSInteger row = [self.rowArray cound];
[self.rowArray insertObject:#"anotherCell" atIndex:row];
NSIndexPath *indexPath = [NSindexPath indexPathForRow:row inSection:0];
[self.myTableView insertRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}
(There is a textField in that cellID and I set the delegate to self.)
In textFieldDidEndEditing, I made an NSLog of textField.text, and when that method gets called from a textField that was there initially, it works as expected.
But when textFieldDidEndEditing gets called from the textField that's in the cell of anotherCell (the added cell), then the whole simulator freezes.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *cellID = [self.rowArray objectAtIndex:[indexPath row]];
customCell *cell = [tableView dequeuereusablecellwithidentifier:cellID forIndexPath:indexPath];
cell.name.delegate = self; // From cell that is initially there
cell.phoneNumber.delegate = self; // From the added cell
return cell;
}
(If this is confusing, or if you need more code, just let me know in the comments. Thanks)
Edit
- (void)textFieldDidEndEditing:(UITextField *)textField
{
if (textField.tag <= 9)
{
NSLog(#"%#", textField.text); // This works
}
UIView *superview = textField.superview;
while (![superview isMemberOfClass:[UITableViewCell class]]) {
superview = superview.superview;
}
CustomCellClass *cell = (CustomCellClass *)superview;
NSIndexPath *indexPath = [self.myTableView indexPathForCell:cell];
if (textField.tag >= 12)
{
if ([self.inputArray count] > indexPath.row) // So I won't get the error message of [__NSArrayM objectAtIndex:]: index 1 beyond bounds for empty array'
{
for (NSUInteger i = [self.inputArray count]; i < indexPath.row; i++) {
[self.inputArray insertObject:#"" atIndex:i];
NSLog(#"%lu", (unsigned long)i);
}
}
NSLog(#"%#", self.inputArray);
}
}
Your code is stuck in an infinite loop here:
while (![superview isMemberOfClass:[UITableViewCell class]]) {
superview = superview.superview;
}
because isMemberOfClass will return true only if the superview class is UITableViewCell, but NOT if it is a subclass of UITableViewCell. If you change isMemberOfClass to isKindOfClass, it should work. Check the Apple docs here.
I am able to add a 'line separator' above my uitableviewcells manually (out-of-box iOS isn't cutting it for this). So I have created an array of UIViews, called _separatorLines, I add one UIView from each index to the uitableviewcells' contentView in my 'cellForRowAtIndexPath' with
UIView *v = [_separatorLines objectAtIndex:indexPath.row];
[cell.contentView addSubview:v];
however when i select a cell, i would like all other cells' line separators to turn red.
in 'didSelectRowAtIndexPath' I have:
{
for(unsigned int i = 0; i < _rowsInSection-1; i ++)
{
//make all other rows have a red content view
if(i != indexPath.row)
{
NSIndexPath *I = [NSIndexPath indexPathForRow:i inSection:1];
UITableViewCell *cell = [self tableView:tableView cellForRowAtIndexPath:I];
UIView *separatingLineView = [_separatorLines objectAtIndex:I.row+1];
separatingLineView.backgroundColor = [UIColor redColor];
[cell.contentView bringSubviewToFront:separatingLineView];
[separatingLineView setNeedsDisplay];
[cell setNeedsDisplay];
[cell.contentView setNeedsDisplay];
}
}
[self setNeedsDisplay];
Instead I do not see the contentView of the uitableviewcells changing.
For me I think the issue was the line
NSIndexPath *I = [NSIndexPath indexPathForRow:i inSection:1];
UITableView starts on section '0' (just like the rows start on '0').
And also because my UITableView is the delegate, I stopped using
[self tableView:tableView cellForRowAtIndexPath:I];
and replaced it with
[self cellForRowAtIndexPath:I];
Not sure if that had anything to do with it
I'm working on the TableView, and I have used the label on the TableViewCell and on the button click I want to hide the label from all cells in my table,
In the label I have set the tag:
label.tag = indexPath.row+1;
And on the button click I am using the code like this:
for (int i = 0; i < Array.count; i++)
{
[[self.view viewWithTag:i+1] setHidden:YES];
}
But from my code the label is hiding only from the last cell not all the others.
You can simply do this with another way.
First you need to declare a BOOL in your class
#property(assign,nonatomic) BOOL hideLabels;
Next in your button action handler method, set this YES
In your cellForRowAtIndexPath, check whether hideLabels is YES, if yes, the hide labels using code.
cell.yourLabel.hidden = hideLabels;
Now reload the table after setting hideLabels as YES
[self.tableView reloadData];
for(id object in tableView.subviews)
{
if([object isKindOfClass:[UILabel class]])
{
UILabel *label = (UILabel *) object;
[[label setHidden:YES];
}
}
In your ViewController.h
BOOL isLabelHidden;
in ViewController.m
- (void)viewDidLoad
{
isLabelHidden = FALSE;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"TableCell";
UILabel *lbl;
UITableViewCell *cell = (UITableViewCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
cell = nil;
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
if(isLabelHidden)
[lbl setHidden:YES];
else
[lbl setHidden:NO];
}
in you button clicked method
- (void)buttonClicked
{
isLabelHidden = TRUE;
[tableView reloadData];
}
You should first get the reference to the UITableViewCell and then you can remove the labels in them.
First of all get the reference to all the cells in your tableview as follows:
NSMutableArray *cells = [[NSMutableArray alloc] init];
for (NSInteger j = 0; j < [tableView numberOfSections]; ++j)
{
for (NSInteger i = 0; i < [tableView numberOfRowsInSection:j]; ++i)
{
[cells addObject:[tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:j]]];
}
}
And now iterate through those cells in cells Array to hide the label view,
for (int i = 0; i < cells.count; i++)
{
[[[cells objectAtIndex:i] viewWithTag:i+1] setHidden:YES];
}
Source:How can I loop through UITableView's cells?
My question is clear,
I have a UITableView and UIMapView with annotations, when an annotation is tapped on the map, it will be found on the table and be selected since the user can recognize it.
But, if i try something it is only in visible cells, i am not able to do as i expected.
- (void)annotationTapped:(UITapGestureRecognizer *)recognizer{
if ( recognizer.state == UIGestureRecognizerStateEnded ) {
//NSLog(#"%#",[recognizer.view subviews]);
UIImageView *temp = (UIImageView*)[recognizer.view viewWithTag:1000];
UILabel *temp2 = (UILabel*)[temp viewWithTag:1001];
NSArray *tapAndFind;
if(isFiltered)
{
tapAndFind = filteredListContent;
}
else
{
tapAndFind = eczaneler;
}
for(int i=0;i<tapAndFind.count;i++)
{
Pharma *tempPharm = [tapAndFind objectAtIndex:i];
if([tempPharm.CustomerIndex isEqualToString:temp2.text])
{
EczaneCell *cell = (EczaneCell*)[tableView1 cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]];
for(EczaneCell * cell2 in [tableView1 visibleCells])
{
cell2.selected = NO;
}
cell.selected = YES;
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:[tableView1 indexPathForCell:cell].row
inSection:[tableView1 indexPathForCell:cell].section];
[tableView1 scrollToRowAtIndexPath:indexPath
atScrollPosition:UITableViewScrollPositionTop animated:YES];
}
}
}
}
This is because your UITableView is just a presentation of your data, not a data itself. So, when you tap on annotation, you should somehow find a correspondence with a data, the position of your annotation data in collection. Then you may calculate/find out the index of row in table, and then you can perform UITableView's scrollToRowAtIndexPath:atScrollPosition. Alternatively, you can mark the cell to make it distinguishable.
In your code
EczaneCell *cell = (EczaneCell*)[tableView1 cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]];
can return nil for cell when the cell for given index path is invisible. That's why you should check against data, not table cells.