My table cells don't highlight immediately when touched - iphone

In my app, I have a table view that has about eight cells. There is a navigation bar at the top. When a user touches a cell, nothing happens for about 1/2 second. Then the touched cell highlights blue and immediately the new view slides into position.
The problem is that there is no feedback to the user about which cell he touched until just before the new view slides into position.
For example, when I explore the tables in the iPhone's Settings application, when you touch a cell, the cell immediately turns blue, and then there is a 1/2 second delay, and then you see the new view.
How do I get my table's feedback of highlighting the cells to happen immediately? I am using tableView didSelectRowAtIndexPath:, and each cell has an accessory button.
Thanks for any insight.

are you using a custom-drawn cell (with a drawRect override) or something like that?
if you have a custom drawRect method, you'll need to do something like this (based off the code for tweetie, found here):
//default colors for cell
UIColor *backgroundColor = [UIColor whiteColor];
UIColor *textColor = [UIColor blackColor];
//on highlight, swap colors
if(self.highlighted){
backgroundColor = [UIColor clearColor];
textColor = [UIColor whiteColor];
}
that should give you the default behavior.

It sounds like the screen is refreshing after the new slide has been processed. You need to refresh the screen before rendering the new slide view.

a few things:
it's probably best to have a property in beforeViewController so it can set its own title on load (instead of setting it from the parent class).
second, why are you setting the back button for the current class? youre also leaking that (you alloc the UIBarButtonItem but dont release it).
NewViewController *newViewController = [[[NewViewController alloc]
initWithNibName:#"New" bundle:nil] autorelease];
newViewController.name = [self.listData objectAtIndex:indexPath.row];
[self.navigationController pushViewController:beforeAfterViewController animated:YES];
then in NewViewController, you have
- (void) viewDidLoad{
self.title = self.name;
}
re: your secondary question: if you pop the child controller using [self.navigationController popViewControllerAnimated:YES], the parent view should auto-deselect the row that was previously selected. it shoulnt stay selected unless you are forcing it to stay that way.
you don't need to do anything like [self.tableView deselectRowAtIndexPath:] unless you are not pushing child views (and doing something like checkmarking a cell that the user tapped).

You may put these 2 lines of code at the beginning of the didSelectRowAtIndexPath method:
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
[cell setSelected:YES animated:YES];
it should first highlight the cell before processing other program logic.

Related

UIImageView still visible after hiding/removing from superview

i hope you will find a solution for my problem, cause i don't have any ideas anymore.
I have a tableview, which has several cells. some cells have another view as subview on their contentView.
This additional view has 2 subviews: 1 UIImageView and 1 UILabel.
Now when i tap an UIButton the UIImageView should be hidden/removed and the UILabel changes it's textColor to white(black before).
The UILabel changes it's textColor but the UIImageView is still visible, even after removing the UIImageView from it's superview.
The Code looks like this.
_adsc_dot_view is the UIImageView
_adsc_text_label is the UILabel
- (void)mc_set_selected:(BOOL)selected {
if (selected) {
_adsc_dot_view.hidden = YES;
_adsc_text_label.textColor = [UIColor whiteColor];
}
else {
_adsc_dot_view.hidden = NO;
_adsc_text_label.textColor = [UIColor blackColor];
}
}
Some check you might find useful for this issue:
1) make sure you create once your UIImageView which referenced as _adsc_dot_view
2) do a debug, mark mc_set_selected with a breakpoint and in the log check the view hierarchy, whether you have the needed number of UIImageView and not more
po [[UIWindow keyWindow] recursiveDescription]
or check this advanced SO answer: I need to inspect the view hierarchy on an iPhone program
3) if you use Interface Builder make sure you have proper type (and not UIImage) and proper reference
You are using UITableView and you add UIImageView and UILabel as a subview in UITableViewCell. So, I think you should reload UITabeView using [self.tableView reloadData]; or [YourTableName reloadData]; after your hide and show UIImageView method. Otherwise you should hide and show UIImageView using UIImageView tag or using UITableViewCell index path.
is the target device on iOS 7? If yes then do try to layoutsubviews of the cell. I had a similar issue where the cell wasn't refreshing on ios 7.
Just reload table view cell after Remove/Hide ImageView.

How to switch a UITableViewCell from "normal" view to transparent, and back again

I have a table view which flips back and forth between view mode and edit mode. I have one cell which I would like to be transparent in view mode, and look like a "normal" cell in edit mode (i.e. white background, rounded rectangle outline). Basically, the same thing you see the name cell do in the contacts app as you switch in & out of edit mode.
I used the solution in How to create a UITableViewCell with a transparent background to get a transparent background, but I can't figure out how to get the original background back.
Currently, I create two background views in viewDidLoad:
nameCellDefaultBackview = [[UIView alloc] initWithFrame:CGRectZero];
nameCellDefaultBackview.backgroundColor = [UIColor clearColor];
nameCellEditBackview = [[UIView alloc] initWithFrame:CGRectZero];
nameCellEditBackview.backgroundColor = [UIColor whiteColor];
I then give my cell the default background view:
nameCell.backgroundView = nameCellDefaultBackview;
In setEditing:animated: I set the background of the cell depending on the editing mode:
if (editing) {
nameCell.backgroundView = nameCellEditBackview;
} else {
nameCell.backgroundView = nameCellDefaultBackview;
}
The problem is, in editing mode I get a white rectangle instead of something that looks like a cell - which is precisely what I asked for, but not what I want :). I've tried a couple of other things, like setting backgroundView to nil (which seems to = no change), and saving the 'initial' background view in viewDidLoad (that didn't seem to work, and looking in the debugger the variable was 0x0 when I tried to assign it to the cell in setEditing).
So what I want is to look like this in normal mode:
And like this in edit mode:
But what I currently get in edit mode is:
So how do I get the white background/border/rounded corners back?
If you want to use back the original cell in edit mode, you should consider showing and hiding the cell instead of setting the background view. The background view is added as a subview behind all other views, thus, setting it to transparent has no effect. Reference: Apple Doc.
To hide or show a table cell, see this post
for editing mode, dont set the backgroundView. Just call [tableView reloadData] when you enter editing mode and set the backgroundView in cellForRowAtIndexPath like this:
if (!editing) {
nameCell.backgroundView = nameCellDefaultBackview;
}
//if it is editing, then it will take the default style.
hope this helps.
I've decided to change my approach a bit, and this is now working:
Instead of trying to show/hide the background of one cell, I now have two cells:
IBOutlet UITableViewCell *nameCellViewMode;
IBOutlet UITableViewCell *nameCellEditMode;
In viewDidLoad: I change the background of nameCellViewMode to make it transparent:
UIView *clearBackgroundView = [[UIView alloc] initWithFrame:CGRectZero];
clearBackgroundView.backgroundColor = [UIColor clearColor];
nameCellViewMode.backgroundView = clearBackgroundView;
In following with KDaker's suggestion I now just do a tableView reloadData in setEditing:animated:, and then in cellForRowAtIndexPath I do this:
if (self.editing)
{
return nameCellEditMode;
}
else
{
return nameCellViewMode;
}

iPhone: Add background button to view when UITableView has no cells

I have a UITableViewController, when there is no data to populate the UITableView, I want to add a button, which uses an image. So, rather than the user seeing a tableview with no records, they will see an image that says, "No records have been added, Tap to add one", then they click and we create a new one.
I assumed I would just hide the UITableView, then create the button, but I never see the button. Here I am using:
if ([[fetchedResultsController sections] count] == 0) {
self.tableView.hidden = YES;
// Create button w/ image
UIButton * btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
btn.frame = CGRectMake(0, 0, 100, 50);
[btn setImage:[UIImage imageNamed:#"no-rides.png"] forState:UIControlStateNormal];
[self.view addSubview:btn];
}
Ideas on why I would never see the button? When I show this view, it seems to have a transparent background for a second, then changes white...
I am not sure if it works but you can try this:
If your view controller is not a UITableViewController and it contains a UITableView
[self.tableView removeFromSuperview]; then [self.view addSubview];
If your view controller is a UITableViewController, you may need to consider to set the first row to contain the image and text. Then, you can handle the event: tableView:didSelectRowAtIndexPath: and if user click on the first cell, you trigger the method handle the button event
In a UITableViewController, self.view could be self.tableView in which case hiding the table would also hide the button. Try using a custom UIViewController and creating either the table or the button as a subview of self.view instead.
Alternately, when there is no data, you can create a single custom cell containing your button and use that instead of normal cells.
I believe you can add the button to the table footer, as the table footer is shown even when there are no cells. (Note, this is different to a section footer.)
By default the tableFooterView property of the UITableView is nil. So just create your button, and then do:
self.tableView.tableFooterview = btn;
For all future travelers, I simply set .userInteraction = true (Swift) and it worked like a charm. All in all:
tableView.backgroundView = constructMyViewWithButtons()
tableView.backgroundView!.userInteraction = true

UITableViewCellSeparatorStyleNone does not hide blue separator line when selecting in UITableView

Before describing the problem, let me first point out that this is a distinct issue from this question.
The Problem
This screenshot was taken with a break set at tableView:didSelectRowAtIndexPath:, and as you can see in the simulator (far right of the image), there's a single-pixel blue line at the bottom of the selected cell. This is not the design asked for by the client, nor is it how this app used to behave: there should be no separator, even on selection.
How I Got Here
I'd initially designed this table view using custom UITableViewCell classes with corresponding nib (.xib) files and had no trouble with selections: the separator was hidden as desired. Predictably, scrolling was sluggish due to all the overhead from the view hierarchy, so I reworked the custom cells to use Loren Brichter's fast scrolling solution. Now scrolling is much faster, but I can't get rid of the separator for the life of me.
What I've tried
At the time of the screenshot above...
the table view has "Separator [None]" in IB.
the UIViewController that contains the table view has this line in viewDid Load: self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
As you can see in the screenshot, I inserted some unused lines to prove that separatorStyle is set as desired. Other testing confirms that tableView and self.tableView are equivalent pointers at that same breakpoint.
I've also tried setting tableView.separatorColor to black and to clear, all with the same result: the cells look right until a selection is made.
Manjunath: Here's the code I'm using to draw alternate backgrounds depending on whether the cell's been touched or not. You can see the difference—which is less subtle when animated—in the screenshot.
if(self.highlighted) {
textColor = [UIColor blackColor];
UIImage *bg = [UIImage imageNamed:#"image-cell-background_highlighted.png"];
[bg drawAtPoint:CGPointMake(0.0, 1.0)];
}
else {
UIImage *bg = [UIImage imageNamed:#"image-cell-background.png"];
[bg drawAtPoint:CGPointMake(0.0, 0.0)];
}
This gets called in UIImageCell.m in drawContentView:, a method inherited from Mr. Brichter's ABTableViewCell super class.
Chris,
Delving into ABTableViewCell, I see:
- (void)setFrame:(CGRect)f
{
[super setFrame:f];
CGRect b = [self bounds];
b.size.height -= 1; // leave room for the seperator line
[contentView setFrame:b];
}
Since the height of the cell is one pixel shorter than the actual cell, when the cell gets selected, that one-pixel line will bleed through in the color of the selection color. It may look like it's the separator, but it is actually the selection color.
To test, try to change that line above to be two pixels or more shorter to see what happens.
Update:
By making this change to the FastScrollingExample project's -rootViewController:
- (void)viewDidLoad
{
self.title = #"Fast Scrolling Example";
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
[super viewDidLoad];
}
and commenting out:
// if(self.selected)
// {
// backgroundColor = [UIColor clearColor];
// textColor = [UIColor whiteColor];
// }
//
in -drawContentView to mimic what would happen if you didn't have the selection color showing through, then I get a screen shot like this:
alt text http://files.me.com/mahboud/7k656q
Look familiar?
How would you get around this? If you don't need to select cells, then disable cell selection. Otherwise, if you are selecting cells, then you should make the rect larger so the default selection color doesn't show through when you paint with your own selection color in -drawConentRect.
Try this:
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = NSLocalizedString(#"Cell",#"");
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (nil == cell)
{
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
}
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
return cell;
}

After moving a UITableView row, then selecting it, it only turns blue at the edges

I have a UITableView with reorderable rows and I'm using the standard UITableViewCell.text property to display text. When I tap Edit, move a row, tap Done, then tap the row, the built-in UILabel turns completely white (text and background) and opaque, and the blue shade to the cell doesn't show behind it. What gives? Is there something I should be doing that I'm not? I have a hacky fix, but I want the real McCoy.
Here is how to reproduce it:
Starting with the standard "Navigation-Based Application" template in the iPhone OS 2.2.1 SDK:
Open RootViewController.m
Uncomment viewDidLoad, and enable the Edit button:
- (void)viewDidLoad {
[super viewDidLoad];
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
Specify that the table has a few cells:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 4;
}
In tableView:cellForRowAtIndexPath:, add a line to set the text property of a cell, and therefore to use the built-in UILabel subview:
// Set up the cell...
cell.text = #"Test";
To enable reordering, uncomment tableView:moveRowAtIndexPath:toIndexPath:. The default implementation is blank, which is fine in this case since the template doesn't include a data model.
Configure the project for the Simulator, OS 2.2.1, Build and Go. When the app comes up, tap Edit, then slide any row to a new position, tap Done, and then tap each row one at a time. Usually a tap will select a row, turn it blue, and turn its text white. But a tap on the row that you just moved does that and leaves the UILabel's background color as white. The result is a confusing white open space with blue strips on the edges. Oddly enough, after the first bogus tap, another tap appears to correct the problem.
So far I have found a hack that fixes it, but I'm not happy with it. It works by ensuring that the built-in UILabel is non-opaque and that it has no background color, immediately upon selection.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// hacky bugfix: when a row is reordered and then selected, the UILabel displays all crappy
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
for (UIView *view in cell.contentView.subviews) {
if ([[view class] isSubclassOfClass:[UILabel class]]) {
((UILabel *) view).backgroundColor = nil;
view.opaque = NO;
}
}
// regular stuff: only flash the selection, don't leave it blue forever
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
This appears to work, but I don't expect it to be a good idea forever. What is the Right Way to fix this?
This looks like a bug in UITableView's rendering, and you should file a Radar bug report on it. It's like the cells don't get refreshed properly after the move.
One way to work around this for now is to not use the built-in label, but roll your own in the cell:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
CGRect frame = cell.contentView.bounds;
frame.origin.x = frame.origin.x + 10.0f;
UILabel *textLabel = [[UILabel alloc] initWithFrame:frame];
[textLabel setAutoresizingMask:UIViewAutoresizingFlexibleRightMargin];
textLabel.tag = 1;
textLabel.textAlignment = UITextAlignmentLeft;
textLabel.backgroundColor = [UIColor clearColor];
textLabel.textColor = [UIColor blackColor];
textLabel.font = [UIFont boldSystemFontOfSize:20.0];
textLabel.numberOfLines = 1;
textLabel.highlightedTextColor = [UIColor whiteColor];
[cell.contentView addSubview:textLabel];
[textLabel release];
}
UILabel *textLabel = (UILabel *)[cell viewWithTag:1];
textLabel.text = #"Test";
return cell;
}
I tried this, and it doesn't exhibit the same sort of white blank rectangle you see with the built-in label. However, adding another non-opaque view to the table cell might not be the best for overall rendering performance.
I don't know how major of a glitch this is, because Apple doesn't want you to persist a selection highlight on a table row (they've been enforcing this lately during the review process). You're supposed to place a checkmark or move on to the next level in the navigation hierarchy with a selection, at which point this white box would only be on the screen for a fraction of a second.
The trick in the solution from Brad appears to be:
textLabel.backgroundColor = [UIColor clearColor];
If you leave the background as the default you still get the problem even when you roll your own cells UITableViewCells.
The reason I left it as the default is because the documentation says it is less computationally costly to use opaque backgrounds. Ideally I wouldn't want to use [UIColor clearColor] to fix this bug.
Maybe a completely custom painted cell would somehow fix it. I haven't tried those before though.
Does anyone else have a solution for this?
Thanks for the info, I was searching how to erase the background color from a UILabel.
I used the following line:
textLabel.backgroundColor = [UIColor clearColor];
and worked perfectly!!!
thanks
Alejandra :)
Selections aren't meant to be shown for extended periods! (We got knocked on this for several of our apps)
??? That means Apple would not approve their own Calendar app on iPhone! When you go to edit the start and end times of the event, the start time is selected indefinitely, it only changes once the user taps to the next field.