scrollToRowAtIndexPath stopped working in iOS 7 - ?UITableViewCellScrollView? Change in UITableViewCell hierarchy - uitableview

I upgraded to Xcode 5 and my app to target iOS 7 and my app no longer responded to scrollToIndexPath to scroll the appropiate tableviewcell out of the way of the keyboard
My set up is i had a custom tableview cell, with textfield on it, and was using it to generate multiple tableview cells to display and edit parts of an address.
Tapping on a textfield on a cell triggers
- (void)textFieldDidBeginEditing:(UITextField *)textField
And the code to make it scroll to the top , out of the way of the keyboard was as follows
UITableViewCell *cell = (UITableViewCell*) textField.superview.superview;
[self scrollToRowAtIndexPath:[self indexPathForCell:cell] atScrollPosition:UITableViewScrollPositionTop animated:YES];
This worked fine in iOS 6 but doesn't work in iOS 7. It also does not generate any error.

The solution here is a simple one
It appears that there has been a change in the hierarchy of tableviewCells
So adding an extra .superview
UITableViewCell *cell = (UITableViewCell*) textField.superview.superview;
Becomes
UITableViewCell *cell = (UITableViewCell*) textField.superview.superview.superview;
and it works targeting iOS 7.
The textField.superview.superview used to be an object of class UITableViewCell (or more specifically my custom UITableViewCell)
Now it's an object of class UITableViewCellScrollView and you need to get that its superview.
UITableViewCellScrollView is a private subclass that apparently enables the the slide left to reveal the delete button
After working this out i found this blogpost which illustrates it nicely
Hope this stops a few of you pulling your hair out :)
Simon

As the previous answer said, the view hierarchy of a UITableViewCell changed in iOS 7. Instead of using:
UITableViewCell *cell = (UITableViewCell*) textField.superview.superview;
Define the following method:
- (UITableViewCell *)cellForSubview:(UIView *)subview
{
UIView *view = subview;
while (view != nil && ![view isKindOfClass:[UITableViewCell class]]) {
view = [view superview];
}
return view;
}
Then use it as follows:
UITableViewCell *cell = [self cellForSubview:textField];
This should work in iOS 6 and 7.

Related

xcode and storyboard: how build an user profile view

how can i build an user profile view like this (Periscope but is similar to many other apps).
It's a tableviewcontroller? If it is, how can i put the image of the user with background (it's in the first cell or above the tableview?)
I'd build it this way:
UIViewController with UITableView + custom UIView on top.
If you want to use already implemented libraries, check this out :
MGSpotyViewController
jcbannerView
Facade
They have pretty similar logic that's described in your question.
It is a custom tableviewcontroller. Everything is a cell but it is hard to create only using storyboard. you create a dynamic table view and ad 3 prototype cell for it (1: Blue cell, 2:Grey empty cell, 3: Option Cell). And create a controller and manage the cell with it like:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if(indexpath.row== 0)
{
HeaderCell *cell = [tableView dequeueReusableCellWithIdentifier:#"headerCell" forIndexPath:indexPath];
cell.name = "foo";
....
}
else if(indexpath.row ==1 || indexpath.row ==3)
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"blankCell" forIndexPath:indexPath];
[cell setBackgroundColor:[UIColor greyColor]];
}else{
....
}
}
Looks like above is a header view, and below a table view.
If the above part scrolls off it is the table view's tableHeaderView. In this case you can use a UITableViewController.
Otherwise you will have to use a UIViewController with a UIView as the header and a UITableView below it, and you have to declare the table view delegate and datasource yourself.
You can achieved same UI with help of bringing UITableView and add UIView with blue background as tableHeaderView like as below.
UIView *headerView = [[UIView alloc] init...];
tableView.tableHeaderView = headerView;

UITableView didSelectRowAtIndexPath not working after upgrade to iOS8

I have an iOS app with several UITableViews in them all of which worked as intended
. I upgrade the app to handle iOS8
since then I had a problem with loading a custom cell into the table view who's nib had the box in the ib checked 'use auto layout'. I then uncheck all of these on my custom cell and since then the cells of all my UITableViews not only don't call didSelectRowAtIndex path method but are not highlighted on touch.
I have check that all the cells are active by adding
if(cell.userInteractionEnabled){NSLog(#"is enabled");}else{NSLog(#"is not enabled");}
all of the loaded cells write 'is enabled' to the log
I am setting the delegate and data source via the ib in the storyboard and all of this was working prior to me changing the 'use auto layout' and upgrade to run on iOS 8.
what have i missed?
here is my code to create the cells
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"TableCellWithNumberCellIdentifier";
if( events.count>indexPath.row &&[[[events objectAtIndex:indexPath.row] objectForKey:#"tag"] integerValue] == -1)
{
EventsMonthSeparator *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell.translatesAutoresizingMaskIntoConstraints=NO;
cell = (EventsMonthSeparator *)[EventsMonthSeparator cellFromNibNamed:#"EventsMonthSeparator"];
cell.date.text=[[events objectAtIndex:indexPath.row] objectForKey:#"date"];
[Functions setFontFamily:#"Neutra Display" forView:cell andSubView:YES];
if(cell.userInteractionEnabled){NSLog(#"is enabled");}else{NSLog(#"is not enabled");}
}
return cell;
}else
{
eventsRow *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell.translatesAutoresizingMaskIntoConstraints=NO;
cell = (eventsRow *)[eventsRow cellFromNibNamed:#"eventsRow"];
cell.description.text=[[events objectAtIndex:indexPath.row] objectForKey:#"name"];
cell.timedate.text=[[events objectAtIndex:indexPath.row]objectForKey:#"date"];
cell.image.image=[UIImage imageNamed:#"tiledrinks"];
cell.status.text=[Functions statusForIndex:[[[events objectAtIndex:indexPath.row] objectForKey:#"booked"] intValue]];
[Functions setFontFamily:#"Neutra Display" forView:cell andSubView:YES];
cell.tag=1;
[cell setSelectionStyle:UITableViewCellSelectionStyleBlue];
if(cell.userInteractionEnabled){NSLog(#"is enabled");}else{NSLog(#"is not enabled");}
}
return cell;
}
}
Please Do check that Auto-Layout is OFF (Non selected tickMark) in your Custom cell's xib Also.
And in Your TableView check this default setting,
As attached in below image
I have same issue once, where I have give NO Selection in selection property of TableView's attribute inspector.
If you have done same then give Single selection there.
Hope this will help you !
If you have selected auto layout, cell.translatesAutoresizingMaskIntoConstraints=NO; will negate the auto layout that Xcode provides.
Also, could you check if all your tableViews' delegates are intact? If your delegate isn't set, the tapping on table view cell will not invoke the 'didSelectRow' method.
You can select "in single selection During Editing" in TableView,
for example:

iOS 8: -[UITableViewWrapperView textField]: unrecognized selector sent to instance

Hello: I've been testing my app on iOS 6, 7, and now 8 (beta 5). My UITableView with custom UITableViewCells is working fine on 6 and 7. However, on iOS 8, I'm getting a crash when I attempt to access a subview (text field) of a cell.
I am aware of the fact that there's another view in the cell's hierarchy in iOS 7. Strangely, it appears that this isn't the case in iOS 8. Here's the code I'm using:
//Get the cell
CustomCell *cell = nil;
//NOTE: GradingTableViewCell > UITableViewCellScrollView (iOS 7+ ONLY) > UITableViewCellContentView > UIButton (sender)
if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_6_1) {
cell = (CustomCell *)sender.superview.superview;
} else {
cell = (CustomCell *)sender.superview.superview.superview;
}
//Get the cell's index path
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
//etc.
NSLog(#"%#", cell.textField); //<---Crashes here
So, as you can see, I'm accounting for the extra view in iOS 7. After adding some breakpoints and taking a closer look at the variables, I see that cell exists, but all the subviews it has in the interface file (which are linked up) - including textField - are nil. At the line specified, I'm receiving the following crash log:
-[UITableViewWrapperView textField]: unrecognized selector sent to instance 0x12c651430
I looked into this further, and I found this:
Changing the else statement to be identical to the preceding line gets rid of the crash, and the app works fine (using sender.superview.superview like in iOS 6).
This makes no sense to me. Did Apple revert the hierarchy of UITableViewCells to that of iOS 6's, or am I missing something? Thanks!
I've encountered the same issue. Here's a more reliable method:
UITextField* textField = (UITextField*)sender;
NSIndexPath* indexPath = [self.tableView indexPathForRowAtPoint:[self.tableView convertPoint:textField.center fromView:textField.superview]];
This will work regardless of the underlying view hierarchy of UITableViewCell.
Different iOs versions have different implementations of UITableViewor UITableViewController, as an easy fix you'll have to iterate through superviews until you found the desired view class instead of relying it being the N-th superview.
I also had the same issue on iOS8 with getting UITableViewCell via superview from a child view. This is what I came up with for both iOS7 and iOS8 support.
-(void)thumbTapped:(UITapGestureRecognizer*)recognizer {
NSLog(#"Image inside a tableview cell is tapped.");
UIImageView *mediaThumb = (UIImageView*)recognizer.view;
UITableViewCell* cell;
// get the index of container cell's row
// bug with ios7 vs ios8 with superview level!! :(
/*** For your situation the level of superview will depend on the design structure ***/
// The rule of thumb is for ios7 it need an extra superview
if (SYSTEM_VERSION_LESS_THAN(#"8.0")) { // iOS 7
cell = (UITableViewCell*)mediaThumb.superview.superview.superview.superview;
} else { // iOS 8
cell = (UITableViewCell*)mediaThumb.superview.superview.superview;
}
}
Just to clarify, in cellForRowAtIndexPath I assigned the tap gesture recognizer. The original design is very complex in Storyboard with many subviews, buttons.. etc.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"MediaCell" forIndexPath:indexPath];
.......
UIImageView *mediaImage = ............
.....................................
UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(thumbTapped:)];
[mediaImage addGestureRecognizer:tapGestureRecognizer];
return cell;
}

Custom buttons in XIB used as Custom UITableViewCell don't respond to taps (ios7)

So here I am upgrading a working ios6 app to ios7, and now I can't receive taps or other actions on custom buttons (or other subviews) inside my tableviewcells.
Edit:
My code:
Here is where I deploy my PlaceCell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = #"PlaceCell";
PlaceCell *cell = [tableView dequeueReusableCellWithIdentifier: cellIdentifier];
if (!cell) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"PlaceCell" owner:self options:nil];
cell = [nib lastObject];
cell.reuseIdentifier = cellIdentifier;
}
[cell configureCellWithPlace: [self.places objectAtIndex:indexPath.row]];
cell.delegate = self;
cell.userInteractionEnabled = YES;
return cell;
}
And then it is a normal custom cell with buttons which are connected to some actions by the interface.
It works perfectly with iOS6, but it does nothing with iOS7.
Thank you for your help.
Solved with:
[cell.contentView setUserInteractionEnabled: NO];
Put your button into cell's contentView.
This happens when your Cell's view in xib file is not a UITableViewCell, but only a UIView. Make sure that that the xib's top view is a UITableViewCell.
You can easily check it by looking into the first child of the main view inside the interface builder. If the first subview is not "Content View" then you should rebuild the cell with UITableViewCell on the top.
Also make sure that button is a subview of the "Content View".
I had a similar problem. I had dragged a UIView into the xib to use as my UITableViewCell. Even though I changed the classname to a subclass of a UITableViewCell in Interface Builder, the events on my buttons still didn't fire. Since it was originally a UIView, IB never knew about contentView and didn't add my controls to it.
Dragging a "real" UITableViewCell into the xib, changing its class to the one I wanted, and then rewiring up the IBOutlets fixed everything. Didn't need to mess with delaysContentTouches or other properties either.
Moral of the story: drag the right thing onto your xibs.
It seems to be that when you use interface builder to customize a cell subclass all the views added are added below the contentView. This is why setting userInteractionEnabled = NO on the content view works, because touch events are allow to pass through.
I used po [view recursiveDescription] with lldb to determine this.

iOS) HIding Keyboard in a cell in UITableView

-(void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"searchCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
searchField = (UITextField *)[cell viewWithTag:10000];
[searchField resignFirstResponder];
}
Okay, I have a cell with a identifier name of "searchCell". This cell contains one single UITextField with tag 10000 that pops up a keyboard on the bottom of the screen. When a user touches another cell, the keyboard must be hidden so that the user can have larger space to scroll up and down.
However, when a keyboard has popped up and a user touches(select) a cell, the code above is called but not working... :( It seems like the assigned UITableViewCell is not the one that the user is currently using. What am I doing wrong here?
Make your class a delegate of UITextField
Go to the Storyboard file, click on the text field and go to connections inspector
Under outlets, connect the delegate to the View Controller
Run it in simulator. It will work

Resources