I want to have a setting in an iphone app that uses a toggle switch to allow something to be turned on or off. I have seen tutorials, but they only show how to do this in the iPhone's settings place. I want this done inside the application. Any guides, help advice. I'm going for something similar to the picture below.
You can use the UISwitch as accessoryView. This will look (almost?) exactly like in your picture.
Something like this:
- (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"CellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
UISwitch *mySwitch = [[[UISwitch alloc] init] autorelease];
[mySwitch addTarget:self action:#selector(switchToggled:) forControlEvents:UIControlEventValueChanged];
cell.accessoryView = mySwitch;
}
// configure cell
UISwitch *mySwitch = (UISwitch *)cell.accessoryView;
mySwitch.on = YES; // or NO
cell.textLabel.text = #"Auto Connect";
return cell;
}
- (IBAction)switchToggled:(UISwitch *)sender {
UITableViewCell *cell = (UITableViewCell *)[sender superview];
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
NSLog(#"Switch %i,%i toggled", indexPath.section, indexPath.row);
}
You can use a UISwitch. Here's the very simple class reference guide.
http://developer.apple.com/library/ios/#documentation/uikit/reference/UISwitch_Class/Reference/Reference.html
Basically you can check its state by checking its "on" property.
if(mySwitch.on) {
//do something here
}
First, make sure you're UITableView style is set to "Grouped"
Then, in your cellForRowAtIndexPath method, do something along these lines:
if (indexPath.section == kSwitchSection) {
if (!randomControl) {
randomControl = [ [ UISwitch alloc ] initWithFrame: CGRectMake(200, 10, 0, 0) ];
[randomControl addTarget:self action:#selector(switchAction:) forControlEvents:UIControlEventValueChanged];
randomLabel = [[UILabel alloc] initWithFrame:CGRectMake(20,8,180,30)];
[randomLabel setFont:[UIFont boldSystemFontOfSize:16]];
[randomLabel setText:#"My Label"];
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
[cell addSubview:randomControl];
[cell addSubview:randomLabel];
}
Remember to release the UISwitch object later and to include code for setting it to on or off depending on what state it should be in.
Related
Edit:
Thanks everyone, but this has gotten to be too general as it is clear there are deeper issues at hand. I'm going to try to delete this question. I appreciate all of your help!
We have a large UITableViewCell with a UILabel inside and we want to detect the user's single tap or touch on that label. We're adding a UITapGestureRecognizer inside of our subclassed UITableViewCell:
CGRect frame = CGRectMake(0, 10, 150, 20);
self.titleLabel = [[UILabel alloc] initWithFrame:frame];
self.titleLabel.text = self.title;
self.titleLabel.userInteractionEnabled = YES;
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(expandButtonTapped:)];
singleTap.numberOfTapsRequired = 1;
singleTap.numberOfTouchesRequired = 1;
[self.titleLabel addGestureRecognizer:singleTap];
[cell.contentView addSubview:self.titleLabel];
We've also tried setting the target to the cell's UITableViewController, but same result, the action doesn't get performed. When checking the debugger, the gesture is indeed there and attached to the label.
Edit: After more investigating, if we add a normal UIButton to the cell, it cannot be clicked. Doing more investigating, but here is the cellForRowAtIndexPath method:
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (![self.metaDataSections count]) {
return nil;
}
ACMTableCellMetaData *metaData = [self metaDataForIndexPath:indexPath];
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:metaData.reuseIdentifier];
if (cell == nil) {
cell = [metaData createCell];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
cell = [metaData updateCellWithCellForReuse:cell];
return cell;
}
The createCell method:
- (UITableViewCell *)createCell
{
UITableViewCell *cell = [super createCell];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:self.reuseIdentifier];
cell.frame = CGRectMake(CGRectGetMinX(cell.contentView.frame),
CGRectGetMinY(cell.contentView.frame),
CGRectGetWidth(cell.contentView.frame),
ACM_TABLE_CELL_HEIGHT);
[self setupExpandButtonInCell:cell];
}
return cell;
}
updateCell method:
- (UITableViewCell *)updateCellWithCellForReuse:(UITableViewCell *)cell {
UILabel * titleLabel = (UILabel *)[cell.contentView viewWithTag:TITLE_TAG];
titleLabel = self.titleLabel;
self.cell = [super updateCellWithCellForReuse:cell];
return self.cell;
}
I clipped out some code that I don't believe affects anything. The didSelectRowAtIndexPath that is being over ridden in the the subclassed tableview doesn't have anything that would prevent user taps. But strangely, if I put a break point there, it never gets hit when tapping the cells. So I believe there are other issues at play here. We can't see why this is the case however.
If you are writing this code in class, which inherits UITableViewCell, then instead of
[cell.contentView addSubview:self.titleLabel];
use
[self addSubView:self.titleLabel];
make sure to implement
-(void)expandButtonTapped:(parameter type)parameter{
}
in the same class.
I forgot to mention about
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
TableCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(!cell)
{
cell = [[TableCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Cell"];
}
// Configure the cell...
return cell;
}
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;
}
}
my app has a bug, and i believe its because I'm not reseting the cells content. The apple docs say
The table view’s data source implementation of tableView:cellForRowAtIndexPath: should always reset all content when reusing a cell.
Could someone please explain how to do this, or point me to a tutorial? Thank you in advance!
My cellForRow
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath
{
static NSString *identifier = #"Cell";
cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier] autorelease];
addBtn = [[UIButton alloc]init];
addBtn =[UIButton buttonWithType:UIButtonTypeRoundedRect];
[addBtn setFrame:CGRectMake(220,10,25,55)];
[addBtn addTarget:self action:#selector(addLabelText:) forControlEvents:UIControlEventTouchUpInside];
[addBtn setTitle:#"+" forState:UIControlStateNormal];
[addBtn setEnabled:YES];
[cell addSubview:addBtn];
subBtn = [[UIButton alloc]init];
subBtn=[UIButton buttonWithType:UIButtonTypeRoundedRect];
[subBtn setFrame:CGRectMake(260,10,25,55)];
[subBtn addTarget:self action:#selector(subtractLabelText:) forControlEvents:UIControlEventTouchUpInside];
[subBtn setTitle:#"-" forState:UIControlStateNormal];
[subBtn setEnabled:YES];
[cell addSubview:subBtn];
}
//cellText.hidden=!self.editing;
cell.textLabel.textColor = [UIColor orangeColor];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
cell.imageView.image = [imageArray objectAtIndex:indexPath.row];
cell.textLabel.text = [number objectAtIndex:indexPath.row];// <------ Is this line in the right place?
cell.textLabel.text = #"1"; // <---- Is this line in the right place?
return cell;
}
It's pretty simple. You provide the call cellForRowAtIndexPath in your code. In it, you either provide a brand new cell, or you reuse a cell that the OS has chucked into memory. Basically, you code looks like this:
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
// Configure the cell...
[[cell textLabel] setText:[pickerData objectAtIndex:indexPath.row]];
cell.accessoryType = (indexPath.row == currentValueOfIndex ) ?
UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;
return cell;
The part under the comment // Configure the cell is where you have to reset your cells content. Since it can either be a new cell, or a recycled cell, it will either have no information, or the information from another cell where it was recycled from. In both cases, you provide the cell's text and accessories and anything else you want to use each time the cell is called. Basically, it's a callback to you to provide a cell, either a brand new one, or a recycled one, and you have to stuff the right info for the cell it's going to be (based on the index path). Hope I made this clear enough.
If you're adding views programmatically to the cell, you should do the following for cleaning them:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"CellID";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
for (UIView * v in cell.contentView.subviews) {
[v removeFromSuperview]
}
//Configure your cell
return cell;
}
See the comments in the code below...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"CellID";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
// this is where you want to configure your generic cell
// for example, if EVERY cell needs to have a disclosure indicator, you could do
cell.accessoryType = UITableViewAccessoryTypeDisclosurseIndicator;
}
// this is where you want to put code that would or could be unique to a cell
// for example, if you wanted to put the row number you could do:
cell.textLabel.text = [NSString stringWithFormat:#"%d", indexPath.row];
// you would put this here and not in the above if statement because the value of the textLabel changes for different cells
return cell;
}
Please look at my following code snippet. I place check box in to my cell , i can able to check or uncheck the checkbox. but when i scroll the table view the checkbox's check mark is getting hidden.
i mean i set the check mark by setting the image.
Please anybody help me to solve this problem.
Thanks for your time.
// Customize the appearance of table view cells.
- (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:#"en"] autorelease];
cb = [[UIButton alloc] initWithFrame:CGRectMake(5,10, unselectedImage.size.width, unselectedImage.size.height)];
[cb setImage:unselectedImage forState:UIControlStateNormal];
[cb setImage:selectedImage forState:UIControlStateSelected];
[cb addTarget:self action:#selector(buttonAction:) forControlEvents:UIControlEventTouchDown];
[cell.contentView addSubview:cb];
}
if ( tableView == myTableView )
{
titleLabel = [[UILabel alloc]initWithFrame:CGRectMake(60, 0, 150, 35)];
titleLabel.font = [UIFont boldSystemFontOfSize:13];
titleLabel.textColor = [UIColor blackColor];
[cell.contentView addSubview:titleLabel];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
return cell;
}
Taken from here
If I understand the TableView concept correctly, you need to save the checkmark setting somewhere else. If your cell gets scrolled out of view the TableViewController might release the cell. Then, when you're asked to re-create the cell in your delegate, you have to restore it in the same state as before.
In DidSelectRowAtindexPath:
if ([set containsObject:indexPath])
{
[set removeObject:indexPath];
}
else
{
[set addObject:indexPath];
}
and in CellForRpwAtIndexPath:
if ([set containsObject:indexPath])
{
cell.imgView.image=[UIImage imageNamed:#"chealBox1.png"];
}
else
{
cell.imgView.image=[UIImage imageNamed:#"chealBox2.png"];
}
here set is NSMutableSet and you have to make property and synthesize and alloc as well in viewDidLoad...will work definitely...
I just can't seem figure out how to do this hopefully someone here can help me. In my tableview i want to add checkboxes to each cell and if you touch the checkbox a checkmark appears and a specific action is supposed to happen. but if you just touch the cell a different action is supposed to happen. Does anyone have an idea how to do this?? I started doing the following. But i think my approach creates memory leaks and i don't know how to perform an action only for the button that was pressed instead for all of them.....
It would be great if someone could help me out....
- (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];
}
NSArray *tempArray = [[exerciseNames objectAtIndex:indexPath.section] objectForKey:#"rowValues"];
UIButton *checkButton = [UIButton buttonWithType:UIButtonTypeCustom];
checkButton.tag = indexPath.row;
[checkButton setFrame:CGRectMake(10, 10, 23, 23)];
if (checkButtonPressed == YES) {
[checkButton setBackgroundImage:[[UIImage imageNamed:#"checked.png"] stretchableImageWithLeftCapWidth:10.0 topCapHeight:0.0] forState:UIControlStateNormal];
}
else {
[checkButton setBackgroundImage:[[UIImage imageNamed:#"unchecked.png"] stretchableImageWithLeftCapWidth:10.0 topCapHeight:0.0] forState:UIControlStateNormal];
}
[checkButton addTarget:self action:#selector(checkAction) forControlEvents:UIControlEventTouchUpInside];
[cell addSubview:checkButton];
cell.imageView.image = [UIImage imageNamed:#"unchecked.png"];
cell.textLabel.adjustsFontSizeToFitWidth = YES;
cell.textLabel.text = [NSString stringWithFormat:#"%# (%#)", [[tempArray objectAtIndex:indexPath.row] objectForKey:#"full"], [[tempArray objectAtIndex:indexPath.row] objectForKey:#"short"]];
// Set up the cell...
return cell;
}
- (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tv dequeueReusableCellWithIdentifier:#"CellWithSwitch"];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"CellWithSwitch"] autorelease];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.textLabel.font = [UIFont systemFontOfSize:14];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
cell.textLabel.text = #"Sound Effects";
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)path {
UITableViewCell *cell = [tableView cellForRowAtIndexPath:path];
if (cell.accessoryType == UITableViewCellAccessoryCheckmark) {
cell.accessoryType = UITableViewCellAccessoryNone;
} else {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
}
I would try subclassing UITableViewCell and make each cell the target of the buttons action. That way when the button is pressed, the event will be handled by the cell object, not the table controller. If you don't like that, you could try using the tag your assigning to the button to make a distinction. To do that, make your button selector be
checkAction:(UIButton *)_btn {}
and when you add the target,
[checkButton addTarget:self action:#selector(checkAction:) forControlEvents:UIControlEventTouchUpInside];
(notice the : at the end of the #selector())
I haven't tried the second way, but I think it would work.
In Cocoa Touch, a UISwitch is the UI paradigm equivalent for a checkbox on a desktop UI.
Your checkAction handler can check which control called it, and only change that one control.