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.
Related
I have a problem, setting a button to a UITableviewCell.
After viewDidLoad, the button is on the right place. But when I am scrolling down, the button is anyplace else.
Here is my code, I hope you can help me.
Thanks In Advance.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
if (indexPath.section == 0 && indexPath.row == 0 && _isAddImageViewLoad == NO) {
// Add Image Button
UIButton *addImage = [UIButton buttonWithType:UIButtonTypeCustom];
UIImage* image = [UIImage imageNamed:#"AddImage#2x"];
addImage.frame = CGRectMake(110.0f, 10.0f, 110.0f, 110.0f);
[addImage setImage:image forState:UIControlStateNormal];
[cell.contentView addSubview:addImage];
_isAddImageViewLoad = YES;
} else {
NSDictionary *dictionary = [_items objectAtIndex:indexPath.section];
NSArray *array = [dictionary objectForKey:#"data"];
NSString *cellValue = [array objectAtIndex:indexPath.row];
cell.textLabel.text = cellValue;
}
return cell;
}
It is because you are reusing the cells, and the button is getting placed when it shouldn't an easy solution in your else section. Write addImage.hidden = YES; and in your if statement put addImage.hidden = NO;
Just a couple things. If you use "AddImage" it will use the "AddImage#2x" automatically if it's a retina display. I don't think that will solve your issue but it could be causing weirdness.
When a table view cell is scrolled off the view it is "recycled" in a sense. It appears like you are using a bool to exclude the original cell from being loaded again with a button. You may want to use a header to hold your button if you always want it at the "top". You may also want to verify that the button is being removed when the cell is reused. if its not it will show up in the next row that reuses that cell.
On a side note... Buttons don't usually work very well in table view cells because they handle touches in very different ways. It's quite a bit of modification to get them to feel natural but that's another matter.
Hope that helps!
The problem is because of cell reuse. You need to put some code in the else clause to delete the button if it exits. One way to do this, would be to give your button a tag, like:
addImage.tag = 10;
Then in your else clause:
}else{
if (cell viewWithTag:10) [[cell viewWithTag: 10] removeFromSuperview];
...
The problem is because of the dequeue for the cells. The first time the tableview creates the cells, all the cells run through the
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
code. But when the section 0 row 0 is moved off the screen, that cell is pushed into the cell reusable queue.
Now when your tableview needs to display section 0 row 0, it will get a cell from the reuse queue. you will not get the same cell as the first time. So now you might have 2 cells with the button.
What you should do is have different CellIdentifier for section 0 row 0 , and all other sections and rows. Also create the button when creating the cell. So after the first time the tableView creates the cell, you will not be creating the the button everything.
Look at this line of code:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
This line of code means the UITableViewCells are not created every time. They are re-used as you scroll up and down. Using the code you have above, the UIButton will be created in the correct spot, but then as the cells are re-used, it will create the button in random spots.
One quick way to solve the problem, change the above line of code to simply
UITableViewCell *cell;
I have a tableView, and in that i have a UISegmentController. So each cell will have a UISegmentController each.
When the user clicks on a Segment in the UISegmentController (of a given cell), how do i know which cell was clicked? and i need to NSLog the title of that cell, how can i do this (note: the user will only be clicking on the UISegmentController of the cell, and not the cell it self)
The following code is the method that will be called when the UISegmentController is clicked;
-(void)segmentOfCellPressed:(id)sender{
}
Try this:
-(void)segmentOfCellPressed:(id)sender{
UISegmentController *segmentController = (UISegmentController *)sender;
YourCellClass *cell=(YourCellClass *)segmentController.superview.superview; // your clicked cell
// or a little bit more verbose but imho easier to understand:
// UIView *contentView = [segmentController superview];
// YourCellClass *cell = (YourCellClass *)[contentView superview];
NSIndexPath *path = [yourTableView indexPathForCell:cell]; //indexPath of clicked cell
}
Should be pretty easy. UISegmentedController derives from UIControl which derives UIView. UIView objects have a tag property. When you create each UISegmentedControler, give each one a unique tag value. You will need to manage which tag values separately in a dictionary perhaps.
-(void)segmentOfCellPressed:(id)sender
{
UISegmentedController *segmentedController = (UISegmentedController *)sender;
UITableViewCell *cell = [self cellFromTag:segmentedController.tag];
}
You will need to create a method called cellFromTag that will return the cell from the tag value of the UISegmentedController. If you don't want the cell but something else, then you can return that instead.
You could set the tag property of the segment controller to be the index of the cell in the cellForRowAtIndexPath then in the selector you could query the segment controller and then get the cell by the tag:
UISegmentController *segmentController = (UISegmentController*)sender;
int row = segmentController.tag;
Hopefully that helps.
In the cellForRowAtIndexPath method where you add the UISegmentController to the cell do the following:
segment.tag = indexPath.row;
I have more than 50 rows in my tableView. If i have to view the 50th cell, i will have to scroll down. I have also enabled multiple Selections to my table. The problem is that when i select like 5 rows, and then scroll down i get some other rows also selected (rows which i didn't select, and was auto selected when i scrolled further below).
1.) How do i overcome this ?
My cellForRowAtIndexPath method
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.textLabel.text=#"Text values";
}
My didSelectRowAtIndexPath method
UITableViewCell *cell = [self.tble cellForRowAtIndexPath:indexPath];
if ([cell accessoryType] == UITableViewCellAccessoryNone) {
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
}
else {
[cell setAccessoryType:UITableViewCellAccessoryNone];
}
2.) I am not sure if my didSelectRowAtIndexPath works correctly (as in allow multiple row selection ) Can someone help me solve this
You are storing the selection by setting the cell accessory view. When you reuse a selected cell, the accessory view is not reset. You need to set or unset the accessory view in cellForRowAtIndexPath as well (set if the index path is part of the table view's selection (indexPathsForSelectedRows), unset if not).
You may also find it helpful to store the selected state as part of your data model, so you can toggle easily in the didSelect... and also know what accessory view to display in cellForRow...
Your problem is that since you are reusing cells, the cells will show checkmarks if you dont "clean" them up... What you can do is keep some array to keep track of which cells are checked, initialized initally to whatever it is you want them to be, then in cell for row at index path you need to either set the cell as checked or not... for example
the didSelectRowAtIndexPath can look like
if ([cell accessoryType] == UITableViewCellAccessoryNone) {
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
[_array insertObject:[NSNumber numberWithInt:1] atIndex:indexPath.row];
}
else {
[cell setAccessoryType:UITableViewCellAccessoryNone];
[_array insertObject:[NSNumber numberWithInt:0] atIndex:indexPath.row];
}
then in cellForRowAtIndexPath you can do
BOOL checked=[[_array objectAtIndex:indexPath.row] boolValue];
if(checked)
{
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
}
else
{
[cell setAccessoryType:UITableViewCellAccessoryNone];
}
hope it helps
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
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