I'm trying to create a Settings for our app. I'm not sure what is happening here. I have a UITableViewSyleGrouped and in each section of the table, there is 1 row. For my particular row, it shows the person's name. If you click on it, then it pushes to a new tableView that has the list of people to choose from, then when you pop back, the label gets updated, but the label is truncated when I go from a smaller name to a bigger name. I'm trying to create a Settings for our app. Some of the fields look like:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSUInteger row = [indexPath row];
if (tableView == _settingsTableView) {
UITableViewCell *cell = nil;
NSNumber *aSection = [_tableArray objectAtIndex:indexPath.section];
if ([aSection integerValue] == SOUNDS)
{
cell = [tableView dequeueReusableCellWithIdentifier:#"SwitchCell"];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"SwitchCell"] autorelease];
}
cell.textLabel.text = #"Sounds";
cell.selectionStyle = UITableViewCellSelectionStyleNone;
UISwitch *switchView = [[UISwitch alloc] initWithFrame:CGRectZero];
cell.accessoryView = switchView;
[switchView setOn:[[Settings sharedInstance] playSounds] animated:NO]; // initialize value from Settings
[switchView addTarget:self action:#selector(switchChanged:) forControlEvents:UIControlEventValueChanged];
[switchView release];
}
else if ([aSection integerValue] == PERSON) {
cell = [tableView dequeueReusableCellWithIdentifier:#"PersonCell"];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:#"PersonCell"] autorelease];
}
Person *p = [_personArray objectAtIndex:row];
cell.textLabel.text = [NSString stringWithFormat:#"%# %#", p.firstName, p.lastName];
NSLog(#"cL: %#", NSStringFromCGRect(cell.textLabel.frame));
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
return cell;
}
My PERSON section gives the user the ability to change People. That code in didSelectRowAtIndexPath is
else {
Person *p = [_personArray objectAtIndex:row];
NSUInteger oldRow = [_lastIndexPath row];
if (oldRow != row) {
dmgr.currentPerson = p;
// Put checkmark on newly selected cell
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.accessoryType = UITableViewCellAccessoryCheckmark;
// Remove checkmark on old cell
UITableViewCell *oldCell = [tableView cellForRowAtIndexPath:_lastIndexPath];
oldCell.accessoryType = UITableViewCellAccessoryNone;
[_settingsTableView deselectRowAtIndexPath:_lastIndexPath animated:YES];
self.LastIndexPath = indexPath;
// Update the cell
NSIndexPath *path = [NSIndexPath indexPathForRow:0 PERSON];
UITableViewCell *theCell = [_settingsTableView path];
theCell.textLabel.text = [NSString stringWithFormat:#"%# %#", p.firstName, p.lastName];
[theCell setNeedsDisplay];
NSLog(#"ceLL: %#", NSStringFromCGRect(theCell.textLabel.frame));
}
}
What happens is the label is truncated until I click on the label. (e.g. John D... instead of John Doe). Why does the label not get updated?
I tried looking at the frames, and I'm not sure if that has something to do with it or not. My output is:
cL: {{0, 0}, {0, 0}}
ceLL: {{10, 11}, {76, 21}}
The textLabel field of a UITableViewCell is a regular UILabel. You can set this property to cause it to scale down the text to fit:
theCell.textLabel.adjustsFontSizeToFitWidth = YES;
You can also set a minimum font size
theCell.textLabel.minimumFontSize = whatever
Take a look at the Documentation on UILabel it will help you a lot.
Related
I have a UItableView where every UITableViewCell is containing a UISwitch .Now my question is when i will click in one switch then how can i OFF other switches of the UITableViewCell
In my code i have already made the view and i can ON/OFF the switches.But i want to OFF all other switches except my selected switch.
Please some help me by giving an example or source code example.
With Best Regards
Edit
My Code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
switchview = [[UISwitch alloc] initWithFrame:CGRectZero];
cell.accessoryView = switchview;
switchCondition = NO;
[switchview setOn:NO animated:YES];
[switchview addTarget:self action:#selector(updateSwitchAtIndexPath:) forControlEvents:UIControlEventValueChanged];
[switchview release];
}
if(switchCondition == YES){
[switchview setOn:YES animated:YES];
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.contentView.backgroundColor = [UIColor clearColor];
cell.textLabel.text = [NSString stringWithFormat:#"%#",[cellValueArray objectAtIndex:indexPath.row]];
return cell;
}
- (void)updateSwitchAtIndexPath:(UISwitch*)sender {
if(sender.on){
switchCondition = YES;
[table reloadData];
}
}
Update your data model used by the table's data source, then reload the table (or at least the visible rows). This will cause each row to reload and each switch will get updated with the latest data.
Edit: Here's an updated version of your code:
You need an instance variable to track the state of each switch. Create an array to hold the YES and NO values. In the code below I will assume there is an instance variable named switchConditions of type NSMutableArray that has been setup with NSNumber objects representing the YES and NO values for each row. This is similar to your cellValueArray. You should also get rid of your switchView and switchCondition instance variables.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
UISwitchView *switch = [[UISwitch alloc] initWithFrame:CGRectZero];
cell.accessoryView = switch;
[switchview addTarget:self action:#selector(updateSwitchAtIndexPath:) forControlEvents:UIControlEventValueChanged];
[switch release];
}
UISwitchView *switch = (UISwitchView *)cell.accessoryView;
switch.tag = indexPath.row; // This only works if you can't insert or delete rows without a call to reloadData
BOOL switchState = [switchConditions[indexPath.row] boolValue];
switch.on = switchState; // this shouldn't be animated
cell.contentView.backgroundColor = [UIColor clearColor];
cell.textLabel.text = cellValueArray[indexPath.row];
return cell;
}
- (void)updateSwitchAtIndexPath:(UISwitch*)switch {
NSInteger row = switch.tag;
if (switch.on){
// This switch is on, turn all of the rest off
for (NSUInteger i = 0; i < switchConditions.count; i++) {
switchConditions[i] = #NO;
}
switchConditions[row] = #YES;
[self.tableView reloadData];
} else {
switchConditions[row] = #YES;
}
}
I have a tableview with the accessoryview of a toggle switch. I specify the section and the row and am having a difficult time determining which row was toggled. I used the toggleSwitch.tag to grab the indexRow but as my indexRow is part of an indexPath.section I am not sure how to tell which row I toggled.
Here is the code:
- (UITableViewCell *)tableAlert:(SBTableAlert *)tableAlert cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell;
Category *cat = [allCategories objectAtIndex:indexPath.section];
Subject *sub = [cat.subjects objectAtIndex:indexPath.row];
cell = [[[SBTableAlertCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil] autorelease];
UISwitch *toggleSwitch = [[UISwitch alloc] init];
cell.accessoryView = [[UIView alloc] initWithFrame:toggleSwitch.frame];
[cell.accessoryView addSubview:toggleSwitch];
cell.textLabel.text =sub.title;
cell.detailTextLabel.text = sub.category_title;
if (sub.active==1){
[toggleSwitch setOn:YES];
} else {
[toggleSwitch setOn:NO];
}
toggleSwitch.tag = indexPath.row;
[toggleSwitch addTarget:self action:#selector(viewButtonPushed:) forControlEvents:UIControlEventValueChanged];
[toggleSwitch release];
return cell;
}
- (void)viewButtonPushed:(id)sender {
UIButton *button = (UIButton *)sender;
UITableViewCell *cell = button.superview; // adjust according to your UITableViewCell-subclass' view hierarchy
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
Category *cat = [allCategories objectAtIndex:indexPath.section];
Subject *sub = [cat.subjects objectAtIndex:indexPath.row];
selectedSubject = sub;
UISwitch* switchControl = sender;
NSLog( #"The switch is %#", switchControl.on ? #"ON" : #"OFF" );
if(switchControl.on){
[sub setActive:1];
NSLog(#"%# is being set to ACTIVE", selectedSubject.title);
}else{
[sub setActive:0];
NSLog(#"%# is being set to INACTIVE", selectedSubject.title);
}
[sub setIsDirty:YES];
[cat.subjects replaceObjectAtIndex:indexPath.row withObject:sub];
[sub autorelease];
[cat autorelease];
}
Here is my didSelectRowAtIndexPath. Do I need to have any reference to the toggleSwitch here?
- (void)tableAlert:(SBTableAlert *)tableAlert didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
Category *cat = [allCategories objectAtIndex:indexPath.section];
Subject *sub = [cat.subjects objectAtIndex:indexPath.row];
selectedSubject = sub;
NSLog(#"selectedSubject = %#", selectedSubject.title);
if (tableAlert.type == SBTableAlertTypeMultipleSelct) {
UITableViewCell *cell = [tableAlert.tableView cellForRowAtIndexPath:indexPath];
if (cell.accessoryType == UITableViewCellAccessoryNone)
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
else
[cell setAccessoryType:UITableViewCellAccessoryNone];
[tableAlert.tableView deselectRowAtIndexPath:indexPath animated:YES];
}
}
I have found that you need to go to the superview of the superview of the item in the cell (assuming that the button or control is right off the root of the cell) in order to get the pointer to the cell.
Try this instead:
UITableViewCell *cell = button.superview.superview;
and see if the results are any better. Check out my blog post on this for more information:
Two superviews are better than one
I am creating my cells from an array. The last object in my area gets created differently, as I want to add a new UILabel to the contentView of the cell. (So that it shows a total number of records in a UILabel in the last cell).
For some reason, my last cell that adds the UILabel to the contentView keeps getting duplicated. It will show up on other cells, screw up their display, etc. I have a feeling this has to do with cell reuse, but I am not sure how to fix it.
Here is my method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *kCellID = #"cellID";
// Bounds
CGRect bounds = [[UIScreen mainScreen] bounds];
Person *person = nil;
if (tableView == self.searchDisplayController.searchResultsTableView) {
person = [people objectAtIndex:indexPath.row];
}
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kCellID];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:kCellID] autorelease];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
// Check if it is the first cell
if (person == [people lastObject]) {
cell.accessoryType = UITableViewCellAccessoryNone;
cell.userInteractionEnabled = NO;
UILabel *count = [[UILabel alloc] initWithFrame:CGRectMake(-4, 11, bounds.size.width - 10, 20)];
count.autoresizingMask = UIViewAutoresizingFlexibleWidth;
count.textColor = [UIColor darkGrayColor];
count.font = [UIFont systemFontOfSize:16];
count.textAlignment = UITextAlignmentCenter;
count.text = person.nameFirst;
cell.textLabel.text = nil;
cell.detailTextLabel.text = nil;
[cell.contentView addSubview:count];
return cell;
}
}//end
cell.textLabel.text = [NSString stringWithFormat:#"%#, %#", person.nameLast, person.nameFirst];
// Check if they are faculty staff
if ([person.status isEqualToString:#"Staff/Faculty"]) {
cell.detailTextLabel.text = [NSString stringWithFormat:#"%#: %#", person.status, person.department];
} else {
cell.detailTextLabel.text = person.status;
}//end
return cell;
}
Can someone help me understand how I can get this working correctly so that my UILabel doesn't get created on different cells?
I have adjusted your method below. Basically, you need to dequeue cells and perform any cell wide settings (disclosure, etc.) when you create the cell. Any individual cell changes should be done after the cell has been dequeued.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *kCellID = #"cellID";
static NSString *lastCellID = #"lastcellID";
// Bounds
CGRect bounds = [[UIScreen mainScreen] bounds];
Person *person = nil;
if (tableView == self.searchDisplayController.searchResultsTableView) {
person = [people objectAtIndex:indexPath.row];
}
UITableViewCell *cell;
if (person != [people lastObject]) {
cell = [tableView dequeueReusableCellWithIdentifier:kCellID];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:kCellID] autorelease];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
cell.textLabel.text = [NSString stringWithFormat:#"%#, %#", person.nameLast, person.nameFirst];
// Check if they are faculty staff
if ([person.status isEqualToString:#"Staff/Faculty"]) {
cell.detailTextLabel.text = [NSString stringWithFormat:#"%#: %#", person.status, person.department];
} else {
cell.detailTextLabel.text = person.status;
}//end
} else {
cell = [tableView dequeueReusableCellWithIdentifier:lastCellID];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:lastCellID] autorelease];
cell.accessoryType = UITableViewCellAccessoryNone;
cell.userInteractionEnabled = NO;
UILabel *count = [[UILabel alloc] initWithFrame:CGRectMake(-4, 11, bounds.size.width - 10, 20)];
count.autoresizingMask = UIViewAutoresizingFlexibleWidth;
count.textColor = [UIColor darkGrayColor];
count.font = [UIFont systemFontOfSize:16];
count.textAlignment = UITextAlignmentCenter;
count.tag = 1;
[cell.contentView addSubview:count];
}
UILabel *count = (UILabel *)[cell viewWithTag:1];
count.text = person.nameFirst;
//cell.textLabel.text = nil;
//cell.detailTextLabel.text = nil;
}//end
return cell;
}
It's probably because the cell will be reused. Use a different reuse identifier for the last cell, say, kLastCellID.
UITableViewCell *cell = nil;
// Check if it is the first cell
if (person == [people lastObject]) {
cell = [tableView dequeueReusableCellWithIdentifier:kLastCellID];
if (!cell) {
//create a last cell, with an UILabel in your content view
}
//update the cell's content
} else {
cell = [tableView dequeueReusableCellWithIdentifier:kCellID];
if (!cell) {
//create a regular cell
}
//update the cell's content
}
For my current project i need to have a table in which contains textfield in each cell, the number of cells and textfield must be dynamic, it's depends on the number of data in a MutuableArray. I have the textfield in cells working, but i can't get/set the textfield value. I wonder if you guys can help me out or at least correct me what I did wrong? Thank's alot in advance. See code snippets below:
// Adds textfield into cell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSUInteger row = indexPath.row;
X10ArchiefIndexDefs *curIndex = [indexDefinities objectAtIndex:row];
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
BOOL bShowSelection = ([curIndex.HasVasteWaarden isEqualToString:#"false"]);
if (bShowSelection) {
bShowSelection = !([curIndex.DataType isEqualToString:#"Datum"]);
}
if ([indexPath section] == 0) {
if (bShowSelection) {
cell.accessoryType = UITableViewCellAccessoryNone;
} else {
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
}
UITextField *editField = [[UITextField alloc] initWithFrame:CGRectMake(110, 10, 185, 30)];
editField.adjustsFontSizeToFitWidth = YES;
editField.textColor = [UIColor blackColor];
editField.placeholder = curIndex.Naam;
editField.keyboardType = UIKeyboardTypeDefault;
editField.returnKeyType = UIReturnKeyNext;
editField.backgroundColor = [UIColor whiteColor];
editField.autocorrectionType = UITextAutocorrectionTypeNo; // no auto correction support
editField.autocapitalizationType = UITextAutocapitalizationTypeNone; // no auto capitalization support
editField.textAlignment = UITextAlignmentLeft;
editField.clearButtonMode = UITextFieldViewModeNever; // no clear 'x' button to the right
editField.tag = [curIndex.UID intValue];
[editField setEnabled: YES];
[cell addSubview:editField];
[editField release];
}
}
return cell;
}
In some case i'm using popovercontroller to display list of data. User can select a value uit of the popup. This code is executed when there is a value selected:
- (void)selectedValue:(NSString *) value {
//---update value of the text field ---
//The first attempt it doesn't put the text to text field
//static NSString *CellIdentifier = #"Cell";
//UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
//
//if (cell == nil) {
// cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
//}
// second attempt it crashes
X10ArchiefIndexDefs *curIndex = [indexDefinities objectAtIndex:curRow.row];
int index = [curIndex.UID intValue];
UITextField *textField = (UITextField *) [curCell viewWithTag: index];
if (textField) {
[textField setText:value];
}
[textField release];
[self.popOverController dismissPopoverAnimated:YES];
}
When cell is selected I'm making sure that the cell is saved for use later.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
X10ArchiefIndexDefs *curIndex = [indexDefinities objectAtIndex:indexPath.row];
if (!curIndex) {
return;
}
curRow = indexPath; // saves the selected row
if ([curIndex.VasteWaarden count] > 0) {
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
curCell = cell; // saves the selected cell
CGRect frame = [cell.superview convertRect:cell.frame toView:self.view];
self.detailViewController = [[DetailViewController alloc] initWithNibName:#"DetailViewController" bundle:nil];
detailViewController.delegate = self;
self.popOverController = [[[UIPopoverController alloc] initWithContentViewController:detailViewController] autorelease];
X10ArchiefIndexDefs *curIndex = [indexDefinities objectAtIndex:indexPath.row];
self.detailViewController.Values = curIndex.VasteWaarden;
[self.popOverController presentPopoverFromRect:frame inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
}
Again thank's alot in advance.
Cheers,
Inoel
In the second code snippet you are releasing the textField. You shouldn't do this because you haven't retained it. Because viewWithTag: simple gets a reference to the text field it doesn't retain the textField. So you are releasing it more times that it has been retained, so the retainCount reaches 0 and the textfield is dealloced from memory. Then when you attempt it the second time there is no textfield in the memory.
Just remove the:
[textField release];
From the second code snippet. If you don't understand why, then read some articles about memory management (just google it). It takes some time to understand it fully, at least I know it took me a while :)
I am sure this is a simple fix, but I can't seem to find it. I have a table view that currently works just fine, set up as:
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
}
NSUInteger row = [indexPath row];
cell.textLabel.text = [creedsList objectAtIndex:row];
cell.imageView.image = [UIImage imageNamed:[creedsImages objectAtIndex:row]];
return cell;
The Admob SDK says to add this line:
[cell.contentView addSubview:[AdMobView requestAdWithDelegate:self]];
But then it populates EVERY cell with ads. Any thoughts?
EDIT:
I am using this code to populate:
NSUInteger row = [indexPath row];
cell.textLabel.text = [creedsList objectAtIndex:row];
You want to do that on only the particular rows you want the ads to show up in.
So if you wanted to show up only on the first row, you could do something like
static int adTag = 999; // Used for identifying whether cell already contains ad
UIView * adView = [cell.contentView viewWithTag:adTag];
if(row == 0 && !adView)
{
adView = [AdMobView requestAdWithDelegate:self];
adView.tag = adTag;
[cell.contentView addSubview:adView];
}
else if(row != 0 && adView)
{
// Must remove since cells are reused.
[adView removeFromSuperview];
}