how to make a uitableviewcell unselectable - iphone

I am putting together a search string based off 4 tableviewcells, each cell opens a subview and loads a bunch of data the user selects to set the cell of the previous view.
There is an order in which these cells needs to be set so that each preceding list of data in the subview is related to the data set in the parent view.
i.e. in the first cell you select a type of car, in the next cell you look at the models related to the type of car chosen.
That aside The basis of my question is how do I make a cell unselectable until the previous cell/s have been set.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//...
if (indexPath.section == 0)
{
if (indexPath.row == 0) // <<--- what could I put in here....
{
//...
}
}
}

Disallow the cell to track any interaction:
[cell setUserInteractionEnabled:NO];
or allow interaction, hiding the selection colour, and when clicked, do nothing.
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
- (void) tableViewDidSelectRow.... {
if(indexPath.row == indexOfCellWithNoUserInteraction) {
//do nothing
}
}

Use tableView:willSelectRowAtIndexPath:. Return nil for the rows you don't want selected.

Swift Syntax
cell.selectionStyle = UITableViewCellSelectionStyle.None

Related

accessory tick on uitableviewcell not showing in some instances

I have two tableviews, one has several tableview cells each cell opens the same subview but initalized with new data..
There are around about 100 - 200 entries into the table and I have a accessory view that is a tick that when a cell is selected it ticks the cell then loads the main view again.
If I select that same cell to get the same dataset back it loads the previously selected cell in the middle of the screen (so it knows its index path) however the tick "depending on how deep in the list" will or will not be visible..
It tends to work in about the top 30/40% of the table but anything lower the tick will not be visible... that is unless I go back and forth getting deeper and deeper each time then sometimes I can get the tick to appear in the deeper part of the tableview.. Would anyone know why this is happening?
Has anyone had something of this nature happen to them before?
At further investigation I think something is going wrong inside this method..
First of all, in the subview once the user selects a cell this method is called
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Navigation logic may go here. Create and push another view controller.
[self.navigationController popViewControllerAnimated:YES]; //pops current view from the navigatoin stack
//accesses selected cells content
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
// now you can use cell.textLabel.text
//This if statment is based off which cell was selected in the parent view so that it knows which cell to pass the data back to
if (parentViewSelectedIndexPath.section == 0) {
if (parentViewSelectedIndexPath.row == 0) {
manufactureCellTextLabel = cell.textLabel.text; //passing label text over to NSString for use with delegate (check "viewwilldissapear")
[[self delegate] setManufactureSearchFields:manufactureCellTextLabel withIndexPath:indexPath]; //This is where I pass the value back to the mainview
}
// a few more If statements for the other methods I can pass data too.
//--- this if block allows only one cell selection at a time
if (oldCheckedData == nil) { // No selection made yet
oldCheckedData = indexPath;
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
}
else {
UITableViewCell *formerSelectedcell = [tableView cellForRowAtIndexPath:oldCheckedData]; // finding the already selected cell
[formerSelectedcell setAccessoryType:UITableViewCellAccessoryNone];
[cell setAccessoryType:UITableViewCellAccessoryCheckmark]; // 'select' the new cell
oldCheckedData = indexPath;
}
}
This passes Index path over to the main view method...
- (void) setManufactureSearchFields:(NSString *)cellLabeltext withIndexPath:(NSIndexPath *)myIndexPath
{
manufactureSearchObjectString = cellLabeltext;
manufactureResultIndexPath = myIndexPath;
[self.tableView reloadData]; //reloads the tabels so you can see the value.
}
//Which then sets the manufactureResultIndexPath that is used in the next method to pass it back to the subview
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Navigation logic may go here. Create and push another view controller.
//--- Idendify selected indexPath (section/row)
if (indexPath.section == 0) {
//--- Get the subview ready for use
VehicleResultViewController *vehicleResultViewController = [[VehicleResultViewController alloc] initWithNibName:#"VehicleResultViewController" bundle:nil];
// ...
//--- Sets the back button for the new view that loads
self.navigationItem.backBarButtonItem = [[[UIBarButtonItem alloc] initWithTitle:#"Back" style: UIBarButtonItemStyleBordered target:nil action:nil] autorelease];
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:vehicleResultViewController animated:YES];
[vehicleResultViewController setDelegate:self];
if (indexPath.row == 0)
{
vehicleResultViewController.title = #"Manufacture";
[vehicleResultViewController setRequestString:#"ID.xml"]; //sets the request string in searchResultsViewController
vehicleResultViewController.dataSetToParse = #"ID"; // This is used to controll what data is shown on subview... logic
[vehicleResultViewController setAccessoryIndexPath:manufactureResultIndexPath]; //sends indexpath back to subview for accessory tick
vehicleResultViewController.parentViewSelectedIndexPath = indexPath;
}
//etc etc
}
And finaly I pass it to the method in my subview that passes the indexpath to oldCheckedData
- (void)setAccessoryIndexPath:(NSIndexPath *)myLastIndexPath
{
oldCheckedData = myLastIndexPath;
[self.tableView reloadData]; //<<---- this is where I reload the table to show the tick...
}
Try moving the cell.accessoryType = lines to the willDisplayCell: delegate function like so:
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
// You can move this one here too:
cell.selectionStyle = UITableViewCellSelectionStyleNone; // no blue selection
if (indexPath == oldCheckedData) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
}
I read that the willDisplayCell: method should be used for any basic visual related modifications to a cell like selectionStyle/accessoryType, and the cellForRowAtIndexPath: method for cell data related operations like setting text, images, etc...
I have recently come across this issue, if turned out the in my case the cell has a accessoryview set. This snippet withh ensure the view is removed.
public func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
..logic here to to determine if cell should be selected...
if ( cell.accessoryView != nil) {
cell.accessoryView?.removeFromSuperview()
cell.accessoryView = nil
}
cell.accessoryType = .checkmark

How to check cell is selected in UItableview for image display

My application is navigation base. I have UITableViewController.when i tap a cell i need to display check mark in left side of selected cell for indication of cell is selected. For example 2 cell . First cell is selected i need to indicate cell is selected for check mark. if i select second cell i need to disable first cell check mark and i need to show check mark in second cell.how to check cell selection .
Try this. In your cellForRowAtIndexPath delegate method put the following code.
if (cell == nil) {
...
[[cell imageView] setImage:[UIImage imageNamed:#"checkMark"]];
...
}
[[cell imageView] setHidden:YES];
if (indexPath.row == selectedRow) {
[[cell imageView] setHidden:NO];
}
Have a integer variable named selectedRow and in your didSelectRowAtIndexPath delegate method include the following code,
...
selectedRow = indexPath.row;
[self.tableView reloadData];
Make sure you initialize ,
selectedRow = -1;
in init method or somewhere where it will be initialized before the table view loads.
You might want to look here. Or just google for accessoryView, that's what you have to set.

Using multiple cell style types and custom cells in a UITableView

I'm having problems figuring out how to display different cell styles as well as custom cells together within a UITableView. I understand how to set up and put cells together and the construction of a basic UITableView, but just not how to "mix and match" cell within one.
The best example I can show you on what I am trying to achieve is with the Tweetie 2 application.
The top of the segment there is a block paragraph, then below it there UITableViewCell's with the UITableViewCellStyleValue2 style set. How exactly would I go about achieving this effect?
Thanks ahead of time
The main layout is a grouped table. Each cluster of cells is a table section. The top most cell is set with a transparent background.
The key to making this work is to have a logical structure in the tableview delegate that understands which cell layout goes in which section and which row. A switch statement is usually easiest although you can also use arrays or dictionaries configure to reflect the layout.
So, in tableView:cellForRowAtIndexPath: you would have something like:
switch (indexPath.section) {
case 0:
cell= //configure cell with transparent background
break;
case 1:
if (indexPath.row==0) {
cell = // configure cell for multiline
}else {
cell = // configure for UITableViewCellStyleValue2
}
break;
case 2:
// .. and so on for each section and cell
break;
default:
break;
}
In this layout, the tableview is being used less as a logical table (which displays repeating units of list structured data) and more as convenient mechanism for managing a layout. The logic managing the tableview has to be more complex and reflect the needs of the layout.
The most direct approach would be to change your implementation of -tableView:cellForRowAtIndexPath: to use indexPath.section and indexPath.row to determine which type of cell to draw. For example:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section == 0) {
if (indexPath.row == 0) {
// return long text style cell
} else {
// return left/right label style cell
}
} else {
// return the 4-way button style cell
}
}
Depending on how many cells you are rendering and how many cell styles you've got, you may need to re-use cells in which case you should use a different cell identifier for each style of cell.
This is an elegant way to do:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
/*
Call a function to create all custom cells.
Send the tableview and the indexPath to this function.
So, your code will be clean and easy to read an maintenance =D
DON'T forget to change the height of each cell
*/
if (indexPath.row < 3)
return [self createACustomCell1:tableView indexPath:indexPath];
else
return [self createACustomCell2:tableView indexPath:indexPath];
}
//*************
// Create CUSTOM CELL 2
//*************
-(UITableViewCell *)createACustomCell1:(UITableView *)anTableView indexPath:(NSIndexPath *)indexPath{
static NSString *CUSTOMCELL_1 = #"CUSTOMCELL_1";
CustomCell_1 *cell = [anTableView dequeueReusableCellWithIdentifier:CUSTOMCELL_1];
if (!cell){
[anTableView registerNib:[UINib nibWithNibName:CUSTOMCELL_1
bundle:nil] forCellReuseIdentifier:CUSTOMCELL_1];
cell = [anTableView dequeueReusableCellWithIdentifier:CUSTOMCELL_1];
}
// Cell customization above
return cell;
}
//*************
// Create CUSTOM CELL 2
//*************
-(UITableViewCell *)createACustomCell2:(UITableView *)anTableView indexPath:(NSIndexPath *)indexPath{
static NSString *CUSTOMCELL_2 = #"CUSTOMCELL_2";
CustomCell_2 *cell = [anTableView dequeueReusableCellWithIdentifier:CUSTOMCELL_2];
if (!cell){
[anTableView registerNib:[UINib nibWithNibName:CUSTOMCELL_2
bundle:nil] forCellReuseIdentifier:CUSTOMCELL_2];
cell = [anTableView dequeueReusableCellWithIdentifier:CUSTOMCELL_2];
}
// Cell customization above
return cell;
}
To get the same effect as Tweetie's split cell, create a custom cell and add a Segmented Control and create title and detail labels

First Tap on customcell of uitableview should expand it and second should contract it

In my application I have this requirement that first tap on custom cell of uitableview with a label in it should expand it and second should contract it. I'm able to expand and contract cell and expand label inside cell, but not able to contract the label on second tap.
I'm using this function
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
if( selected == YES ) {
[self expandRow];
}
else {
[self contractRow];
}
height = [lblFeed frame].size.height + 75;
}
expandRow expands the label and contractRow contracts it. I'm perplexed as for how many rows this function gets called. It doesn't get called only for the cell tapped, it gets called more number of times for single tap on single cell may be for other cells but I'm not getting which rows.
This' really urgent.
Can anybody please help?
Tapping a selected row doesn't cause it to be deselected. When a cell gets selected, it stays selected until deselectRowAtIndexPath:animated: gets called on its table. That's why your method isn't getting called for the second tap.
In an MVC architecture like UIKit, it's recommended that you handle user interactions in your controller classes. It would be appropriate to override -[UITableViewCell setSelected:animated:] if all you were doing was customizing the way the view represents a selected cell, but in this case your expand/contract toggle behavior would require a change in the way UITableView selects and deselects its cells.
You could subclass UITableView and implement this toggle behavior yourself, or you can leave UITableView alone and handle it all at the UIViewController level by doing something like this:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if ([self.expandedIndexPath isEqual:indexPath]) {
[(YourCustomCell *)[self tableView:tableView cellForRowAtIndexPath:indexPath] contractRow];
self.expandedIndexPath = nil;
}
else {
if (self.expandedIndexPath) {
[(YourCustomCell *)[self tableView:tableView cellForRowAtIndexPath:self.expandedIndexPath] contractRow];
}
[(YourCustomCell *)[self tableView:tableView cellForRowAtIndexPath:indexPath] expandRow];
self.expandedIndexPath = indexPath;
}
[tableView deselectRowAtIndexPath:indexPath animated:NO];
}
I would suggest that you don't add your functionality on top of the selected property of the cell, which has slightly different behaviour than you expect.
Just add your own BOOL expanded property, and see how that works. You should probably call it from the UITableView delegate methods, too.

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)?