Multiple Value Selection / Deselection in iPhone - iphone

I have multiple values for user selection.
When user selects multiple options then it should be saved in the array.
When user deselects the value then it should remove the same from the array.
How can it be done?
There can be any random selection and deselection from the options.
How can it be done?

Assuming that you want to do this using a table view, you can maintain an mutable array of selected index paths. You can set accessory type to check mark to indicate selection.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if ( [array indexOfObject:indexPath] == NSNotFound ) {
[array addObject:indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else {
[array removeObject:indexPath];
cell.accessoryType = UITableViewCellAccessoryNone;
}
}
and use the array to set the accessoryType properly during cell initialization.

Create a Model class named Options and place all your options as member variables. Update these variables when a user changes the value for any option. Use this variable to port your data from one object to other. Hope this will help you. If it is necessary for you to store the values in a Array then give me some more details about your requirement so we can think further.

Related

How to access values entered in a UITableViewCell?

I have a prototype table in my app witch I populate with a customTableViewCell class with a UITextField inside.
In my navigation bar I got a save button.
The question is, how to access this dynamic created cell's to get the UITextField content?
This is my code, you can see that I tried to use NSMutableArray
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"customTableCell";
customTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
[self.pfCells addObject:cell];
if(cell == nil)
{
cell = [[customTableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
}
// Configuration
cell.lblName.text = [self.pfFields objectAtIndex: [indexPath row]];
cell.txtType = [self.pfTypes objectAtIndex: [indexPath row]];
if ([[self.pfTypes objectAtIndex:[indexPath row]] isEqualToString: #"n"]) {
[cell.txtField setKeyboardType:UIKeyboardTypeNumberPad];
} else if ([[self.pfTypes objectAtIndex:[indexPath row]] isEqualToString: #"m"]) {
[cell.txtField setKeyboardType:UIKeyboardTypeEmailAddress];
}
return cell;
}
Here's another way to save content from a UITextField contained in a UITableViewCell:
Inside tableView:cellForRowAtIndexPath: set the delegate and a tag for txtField
Implement textFieldDidEndEditing: check for a UITextField tag value an save data in a private variable
Reload UITableView
The biggest advantage of this implementation if the fact that you doesn't need to iterate over whole tableview everytime you change a textfield value.
Quick answer:
#pragma mark - UITextFieldDelegate
- (void)textFieldDidEndEditing:(UITextField *)textField
{
// grab the row we are working on
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
// remove the old key/value pair if it exists and add the new one
[self.modelDictionary removeObjectForKey:indexPath];
[self.modelDictionary setObject:textField.text forKey:indexPath];
}
Be sure to add cell.txtField.delegate = self when configuring your cell. Then in your save button, you'd iterate through the dictionary and save the values -- or just save the dictionary itself.
Also, if you are targeting iOS6 or later, use dequeueReusableCellWithIdentifier:forIndexPath: as this method guarantees a cell is returned and resized properly, so you don't have to check for nil and manually init your cell.
Longer answer:
You generally never want to store your model in your view as you are doing. Aside from it breaking the MVC design patterns, it also causes issues with UITableViews. Specifically, a UITableViewCell will be recycled when it scrolls off the screen. So any values you have in those fields are lost. While you can get away with doing this if you only have visible rows that never scroll off the screen, I would encourage you to avoid this approach altogether.
Instead, you should store the values entered into the textboxes in your model object. The easiest way to do this is to use UITextFieldDelegate's textFieldDidEndEditing: to grab the values after the user enters them, then add these values to your model. You model could be something as simple as an NSDictionary using the indexPath as the key.

How to hide custom check mark in table view

I have a UITableiew that I want to be able to display a custom check mark when the row is selected (tapped), however, if there is a check mark on any of the other rows, it must be hidden. What is the best way to do this? The IF... doesn't seem to work at all, it will not hide and unhide the check mark as I thought it would.
Thanks in advance.
-PaulS.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
home_2_CustomCell *cell = (home_2_CustomCell*)[tableView cellForRowAtIndexPath:indexPath];
//This will hide the selected row...
cell.imageViewDidSelectRow.hidden = YES;
// if (cell.imageViewDidSelectRow.hidden = NO){
// cell.imageViewDidSelectRow.hidden = YES;
// }
}
1) Maintain a tag in class level as an NSIndexPath variable.
2) Whenever a cell is selected make note of the indexPath and reload the table view.
3) In cellForRowAtIndexPath delegate check for this variable and set marks accordingly.
4) This will not be costly if you have the cell with less information.
You can get the each cell of tableview by this code
UITableViewCell *cell=[product_table cellForRowAtIndexPath:[NSIndexPath indexPathForRow:clickedTag inSection:0]];
make one for loop.
for(int i=0;i<[tabledata count];i++){
cell.imageViewDidSelectRow.hidden = YES;
}
for each cell except the current row which is selected and you got only one image displayed for the current row.

tapping one row will select multiple rows

I have a weird issue in my tableview. I want to select rows and only want to show the checkmark. I have a tableview with multiple sections. Selecting the row and displaying the checkmark is fine, but 10 rows down the tableview, that row will also get selected??? When selecting more than one row, again, 10 lines down, multiple selections appear.
I am using:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)newIndexPath {
[tableView deselectRowAtIndexPath:[tableView indexPathForSelectedRow] animated:NO];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:newIndexPath];
if (cell.accessoryType == UITableViewCellAccessoryNone) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
// Reflect selection in data model
} else if (cell.accessoryType == UITableViewCellAccessoryCheckmark) {
cell.accessoryType = UITableViewCellAccessoryNone;
// Reflect deselection in data model
}
}
That's not another row being selected, that's the same check-marked cell being reused. In tableView:didSelectRowAtIndexPath: you are using the cell to store state. In tableView:cellForRowAtIndexPath: you are not addressing whether the row should have a check mark or not.
What you will likely want to do is have an ivar NSMutableSet and in didSelectRow.. either add or remove the indexPath from the set, depending on it's checked status. Then in cellForRow.. set the accessoryType property based on the indexPath's membership in the set.
Edit Sorry I didn't catch the comments where you save the state to in a data model. In that case all you have to do is add the check in cellForRow.... Since this is a common question I'll leave the original answer up.

How to work with UITextFields inside of UITableViewCells?

I have 10 UITableViewCells in my UITableView. Each cell has a UITextField. They load fine, but I need a way to set each cell's text to its associated string.
Is there a delegate of UITextField that I can use to do this, and how can I determine which textfield belongs to what NSString, etc?
Edit:
Here is a picture of my tableView. I want it to load text into each cell's textfield from the server then the user can edit it. Or if there is no data on the server, the textfield will be blank and the user can add data and it will sync back.
I have created an NSString for each cell, such as temperatureString, pulseString, etc.
Edit: In respect to the new info this is my new solution
So by the looks of it you are inserting UITextField into each cell, instead of setting the tag of each cell set the tag for each UITextField
First Define your tags
#define DESCRIPTIVE_TAG_VALUE_1 10
#define DESCRIPTIVE_TAG_VALUE_2 11
#define DESCRIPTIVE_TAG_VALUE_3 12
...
Use these in your UITextField Delegate to determine which UITextField belongs to which NSString that is if you are syncing with each update, if your not. Then obtain a reference to the UITableView and retrieve each of the text values of each subview of a cell that has a tag equal to one of your defines (again in a switch statement).
Once again in when working with iOS use tags they are your friends
OR
Also you said that you are holding a reference to each NSString, you could just hold a reference to each UITextField instead that way when you sync you just have to retieve from each of your UITextField references.
But the Apple's best practises say to exercise the use of unique tags when dealing with mutliple views. It's really up to you
UITextfield is a subclass of UIView which has a 'tag' property. You can assign the cell's indexPath.row to be it's text field's tag as identification.
Based on your comment in response to #Javy (which contains extra information you should consider adding to your original question), you could do something like the following:
UITableViewCell *cell = nil;
NSString *key = nil;
switch (indexPath.row)
{
case 0:
cell = self.temperatureCell;
key = #"temperature";
break;
case 1:
// Do other cases similarly ...
}
NSString *text = [self.childAppointmentDictionary objectForKey:key];
cell.textField.text = text;
You should be setting the text in tableView: cellForRowAtIndexPath:
It sounds like you have a specific order that you want your items to appear in which would be a good time to use an NSArray, rather than an NSDictionary.
You could, in init, or initwithNibName, create a retained array property:
self.myListArray = [NSArray arrayWithObjects:#"fever", #"cough", #"runny nose", nil];
Then, assuming that you only have 1 section, you would do cell.textField.text = [self.myListArray objectAtIndex:indexPath.row];
Is there a reason that you're using an NSDictionary for this rather than an NSArray?
You must store a reference to each text field when they are created, so in the:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
Method, you would add this line:
[myTextFieldArray addObject: cell.textField];
Assuming textField is the property for your custom tabel view cell.
You would also set the text within the text field just after the if (cell == nil) method.
The delegate methods simply allow you to know when text is being typed, etc.
EDIT:
Considering what you've added, I agree with Sid and CStreel. Create the tags for each value:
#define kTemperatureTag 0
#define kPulseTag 1
// etc.
As an alternative to CStreel, I would assign/retrieve info matching the indexPath row, and not worry about assigning tags, because they will be the same thing if you start your tags at zero.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// setup / retrieve cell
NSInteger index = [indexPath row];
switch(index)
{
case kTemperatureTag:
cell.textField.text = [self.childAppointmentDictionary objectForKey:#"temperature"];
break;
// case ...
}
// ..
}
And:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
NSInteger index = [indexPath row];
switch(index){
case kTemperatureTag:
[self.childAppointmentDictionary addObject:cell.textField.text forKey:#"temperature"];

Selecting a default item when using UITableViewController as a checkbox list

In a lot of iPhone apps, I see a UITableViewController being used as a checkbox list. (See, for an example of what I mean, Auto-Lock under Settings)
While trying to implement this myself, I had to jump through a lot of hoops in order to have an item selected programmatically by default (ie., the current value for what the list represents). The best I've been able to come up with is by overriding the viewDidAppear method in my view controller class:
- (void)viewDidAppear:(BOOL)animated {
NSInteger row = 0;
// loop through my list of items to determine the row matching the current setting
for (NSString *item in statusItems) {
if ([item isEqualToString:currentStatus]) {
break;
}
++row;
}
// fetch the array of visible cells, get cell matching my row and set the
// accessory type
NSArray *arr = [self.tableView visibleCells];
NSIndexPath *ip = [self.tableView indexPathForCell:[arr objectAtIndex:row]];
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:ip];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
self.lastIndexPath = ip;
[super viewDidAppear:animated];
}
Is this the best/only/easiest way to get a reference to a particular cell and indexPath if I want to mark a row by default?
In order to display the status items, you have to implement tableView:cellForRowAtIndexPath: anyway, don't you? So, why not just set the accessory type of the cell before returning the cell, like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// dequeue or create cell as usual
// get the status item (assuming you have a statusItems array, which appears in your sample code)
NSString* statusItem = [statusItems objectAtIndex:indexPath.row];
cell.text = statusItem;
// set the appropriate accessory type
if([statusItem isEqualToString:currentStatus]) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
Your code is extremely fragile, especially because you use [self.tableView visibleCells]. What if there are more status items than rows fitting on the screen (as the name suggests, visibleCells only returns the currently visible cells of the table view)?