Saturday, September 3, 2011

iOS - Getting onto the same view

One of the biggest and best changes I made to the Android app was to not have a separate answers display screen. It's much more intuitive to just highlight the correct answer in green, and the wrong answer in red, if a wrong answer was chosen. The answer view has interesting but not critical information, such as running score, number right, etc. So, what we're going to figure out first is - how to get the view to return to itself? So, at this point we're back into the navigation logic. Let's see if we can figure out what's going on with it. Here's the QuestionController logic that does the transfer:

#pragma mark UITableViewDelegate - (void)tableView:(UITableView *)tvdidSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
QuizAppDelegate *delegate = (QuizAppDelegate *)[[UIApplication sharedApplication] delegate];
AnswersController *answersController = [[ AnswersController alloc] initWithIndexPath:indexPath];
[ delegate.navController pushViewController:answersController animated:YES];
[ answersController release];
[tv deselectRowAtIndexPath:indexPath animated:YES];}


So, what would happen if we just commented out the transfer, and the deselect row to leave the row highlighted? In fact, just commented out the whole method? Well, it doesn't like something about the change, because it crashes. But even when I back out the change - it still crashes:


- (NSMutableArray *) getAnswerArray : (AppState *) appState { NSDictionary *questionHash = [appState questionDict];
NSArray *tempArray = [questionHash allKeys];
int size = [tempArray count];
// create array
NSMutableArray *answers = [[NSMutableArray alloc] init];
for (int i = 0; i < 4 ; i++) {
// for (int i = 1; i <= [answerHash count]; i++) {
// Get random value between 0 and number of questions
int rand = arc4random() % (size - 1);
// starts at zero, not 1
rand++; // between 1 and size
NSNumber *key = [NSNumber numberWithInt:rand];
Question *question = [questionHash objectForKey:key]; NSString *answer = [question hiragana]; NSLog(@"answer is: %@", answer);
[answers addObject:answer];
}
return answers;}


Answer is nil, but question isn't. Did I botch the change on the move hiragana to kanji? It was working before. I guess that was the problem. I must've been fiddling with the code and didn't test it:

question.number = cntr_question; question.hiragana = hiragana; // <=== restored
if ([question.questionTxt length] == 0)
{
question.questionTxt = hiragana;
}
question.english = english;


You can see where I restored the missing code. Let's try again to make sure; and we're back in business. Now, let's comment out that method again.And, as I suspected, it just leave it sitting there, nicely highlighted blue.


But, what I would really like to do is sort of go back to itself. Let's do an NSLog to make sure it's *not* doing that.Hmm, maybe the answer is at this url:http://iphonedevelopertips.com/cocoa/understanding-reload-repaint-and-re-layout-for-uitableview.html



The first step is to understand the various concepts related to updating UIViews. Repaint and Re-Layout are concepts that are available at the UIView level and manifest themselves as follows:

[myView setNeedsDisplay]; // repaint
[myView setNeedsLayout]; // re-layout

NOTE A call to setNeedsLayout will only have an effect if your UIView overrides the layoutSubviews method. This would be the case if you had a UITableViewCell that had multiple subviews that you manually layout.

In most cases, I find that it is sufficient to call setNeedsDisplay. A good example of this is when a UIImageView is rendered with one image; and while it is still on screen, you change the image to something else. In this case, just changing the image will not always trigger a repaint of the view, for that to occur you need to make a call to setNeedsDisplay.


So, perhaps all we need to do is call the "setNeedsDisplay", i.e. repaint? The question is, how do we know it repainted? We really need to figure out how to highlight a row...According to SO, this might do the trick:

[tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];

Ok, further browsing reveals this code should do the trick:



NSIndexPath *myIP = [NSIndexPath indexPathForRow:0 inSection:0];

[tv selectRowAtIndexPath:myIP animated:NO scrollPosition:UITableViewScrollPositionNone];



And it does - no need to repaint the display, either. Swell!

Ok, now, how do we repaint it to a different color?

A post on SO says this is the way to do it for plain, "ungrouped" tables:



// Customize the appearance of table view cells.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

static NSString *CellIdentifier = @"myCellId";

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

if (cell == nil) {

cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];

UIView *v = [[[UIView alloc] init] autorelease];

v.backgroundColor = [UIColor redColor];

cell.selectedBackgroundView = v;

}

// Set up the cell...

cell.textLabel.text = @"foo";

return cell;
}


Hmmm...there's a big thread on SO that talks about this. http://stackoverflow.com/questions/281515/how-to-customize-the-background-color-of-a-uitableviewcellBut, the problem is that it focuses on the willDisplayCell:forRowAtIndexPath method:


- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {

cell.backgroundColor = [UIColor redColor];

}


Actually, that may be ok - I just need to check the index path, and if it's the one I'm looking for, change the color. Let's throw this out there and see what happens. Yep, it worked, check it out:



However, our problem is not yet solved. We only want to highlight one, and only if it's in "answer" mode. So, that sounds like something we can set in tableView:didSelectRowAtIndexPath



answerMode = true;



And then check in the willDisplayCell method.



- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {

if (answerMode){

cell.backgroundColor = [UIColor redColor];

}}


Ah - maybe we do need the repaint, after all. Back to this url:

http://iphonedevelopertips.com/cocoa/understanding-reload-repaint-and-re-layout-for-uitableview.html

We'll tackle this one in the upcoming posts.

No comments:

Post a Comment