I create a subview for create a custom pickerview, I use a tableview item for do it, I need to have a different color only for the middle cell, for example if I have 3 visible row I need to have grey,black,grey, for do it I try in this way:
- (void) tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
NSArray *visibleCells = [tableView visibleCells];
for (int i = 0; i < [visibleCells count]; i++) {
if (i == 1) {
UITableViewCell *cell = [visibleCells objectAtIndex:i];
[cell.textLabel setTextColor:[UIColor blackColor]];
}
}
}
the first time tableview appear is good but if I scroll I get first 2 or last 2 cell of one color and the remaining cell have the other color. How can I solve the problem?
Quick answer:
- (void) tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
NSArray *visibleCells = [tableView visibleCells];
for (int i = 0; i < [visibleCells count]; i++) {
if (i == 1) {
UITableViewCell *cell = [visibleCells objectAtIndex:i];
[cell.textLabel setTextColor:[UIColor blackColor]];
}
else{
UITableViewCell *cell = [visibleCells objectAtIndex:i];
[cell.textLabel setTextColor:[UIColor grayColor]];
}
}
}
Explanation:
When you scroll a tableview.. the rows that are not visible are 'deleted' and 'recreated' when shown.. thats why there is a reuse identifier.. to reuse those cells.. if you reuse a cell with blackColor.. AS YOU DONT HAVE AN ELSE STATEMENT.. it will remain black.. even if you wanted it gray.. add the else statement to get the desired result.. GL HF
Related
Trying to implement the checkmark for UITableView.
Checkmark for UITableView Cell is not selecting to all row, when scroll tableview
its not not enable.
Below is my code which i Implemented.
IndexButton is UIButton Class which added index init.
-(void)selectAllAction:(IndexedButton *)sender{
for (int rowIndex = 0; rowIndex < [array_MedicineList count]; rowIndex++) {
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:rowIndex inSection:0];
UITableViewCell *cell = [tbl_ProductList cellForRowAtIndexPath:indexPath];
IndexedButton *btn_SelectItem = (IndexedButton *)[cell viewWithTag:TAG_SELECTEDITEM];
[btn_SelectItem setBackgroundImage:[UIImage imageNamed:#"checkMark"] forState:UIControlStateNormal];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *productListTableViewCell = #"ProductListTableViewCell";
ProductListTableViewCell *cell = (ProductListTableViewCell *)[tableView dequeueReusableCellWithIdentifier:productListTableViewCell];
if (cell == nil){
cell = [[ProductListTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:productListTableViewCell];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
IndexedButton *btn_SelectItem = [IndexedButton buttonWithType:UIButtonTypeCustom];
btn_SelectItem.frame = CGRectMake(10,52,32,32);
[btn_SelectItem setBackgroundImage:[UIImage imageNamed:#"uncheckMark"] forState:UIControlStateNormal];
[btn_SelectItem addTarget:self action:#selector(selectItemAction:)forControlEvents:UIControlEventTouchUpInside];
btn_SelectItem.index = (int)indexPath.row;
btn_SelectItem.tag = TAG_SELECTEDITEM;
[cell addSubview:btn_SelectItem];
}
IndexedButton *btn_SelectItem = (IndexedButton *)[cell viewWithTag:TAG_SELECTEDITEM];
btn_SelectItem.index = (int)indexPath.row;
cell.backgroundColor = [UIColor clearColor];
return cell;
}
#All
Need suggestion, how to go forward to implement the check mark for tableview.
I would suggest you to use cell with accessory view with UITableViewCellAccessoryCheckmark type to show all cells selected/ few cells selected/ none of the cells selected.
Also, you must keep the state for each cell index within a section, whether it's selected or not as
// keeps info for selected rows in a section in mutable index set as
NSMutableIndexSet *selctedCellsInSection;
// initialize the above set instance
selctedCellsInSection = [[NSMutableIndexSet alloc] init];
//Inside cell for row at index path
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
if ([selctedCellsInSection containsIndex:indexPath.row])
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
else
[cell setAccessoryType:UITableViewCellAccessoryNone];
// customize cell as per your requirements
return cell;
}
You need to hold the information about a cell's checkmark whether it needs to be shown or not in selctedCellsInSection set as -
Use [selctedCellsInSection addIndex:rowToSelect]
// to add cell index on which checkmark needs to be shown
Use [selctedCellsInSection removeIndex:rowToUnselect]
// to add cell index on which checkmark should not be shown
After, customizing the data source selctedCellsInSection(which keeps information about selected/ unselected cell) reload the tableview.
Reloading the table will reflect the selected cells with Cell's Accessory Checkmark.
In your case as you need show check mark on all cell, you can do so as-
-(void)showCheckMarkOnAllCells
{
for (int rowIndex = 0; rowIndex < [array_MedicineList count]; rowIndex++)
{
[selctedCellsInSection addIndex: rowIndex];
}
[tableView reloadData];
}
#interface BRNCategoryViewController ()
{
NSMutableArray *arySelectCategory;
NSMutableArray *aryCategory;
}
- (void) viewDidLoad
{
arySelectCategory=[NSMutableArray new];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return aryCategory.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
BRNCategoryCell *cell=[[BRNCategoryCell alloc]initWithOwner:self];
if ([arySelectCategory containsObject:[aryCategory objectAtIndex:indexPath.row]])
{
cell.imgBoxView.image=[UIImage imageNamed:#"checkMark"];
}
else
{
cell.imgBoxView.image=[UIImage imageNamed:#"uncheckMark"];
}
cell.lblTitle.textColor=Rgb2UIColor(127, 127, 127);
cell.lblTitle.font=[ASCustomClass FontWithSize:20.0];
cell.lblTitle.text=aryCategory[indexPath.row];
cell.backgroundColor=[UIColor clearColor];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
if ([arySelectCategory containsObject:[aryCategory objectAtIndex:indexPath.row]])
{
[arySelectCategory removeObject:[aryCategory objectAtIndex:indexPath.row]];
}
else
{
[arySelectCategory addObject:[aryCategory objectAtIndex:indexPath.row]];
}
[tblEventCategory reloadData];
}
I added UIButton in the last cell of UITableView, and I want to show more cells with click..
- (void)viewDidLoad {
[super viewDidLoad];
rowCount = 15;
dataArray = [[NSMutableArray alloc] init];
for (int i = 0; i < 100; i++) {
NSString *value = [NSString stringWithFormat:#"the value of row is: %d", i +1];
[dataArray addObject:value];
}
}
...
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return rowCount;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *idintify = #"Cell";
UITableViewCell *cell = [self.myTable dequeueReusableCellWithIdentifier:idintify];
[cell.textLabel setText:dataArray[indexPath.row]];
if (indexPath.row == rowCount -1) {
UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, self.myTable.frame.size.width, 44)];
[button addTarget:self action:#selector(cellButtonClicked) forControlEvents:UIControlEventTouchUpInside];
[button setBackgroundColor:[UIColor yellowColor]];
[button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[button setTitle:#"Show more..." forState:UIControlStateNormal];
[cell addSubview:button];
}
return cell;
}
...
- (void)cellButtonClicked
{
if (rowCount +10 >= dataArray.count) {
rowCount = dataArray.count;
} else {
rowCount += 10;
}
[self.myTable reloadData];
NSLog(#"%ld", (long)rowCount);
}
At beginning its work properly, But when I scrolled the table the cell did not changed!
I want to show the button at last cell
Cells in a table view are reused when the user scrolls. When you add a button to an instance of your cell prototype and don't remove it, the button remains, even if the cell is used at another index later. This results in what you have on your screenshots.
You should create two cell prototypes in the interface builder and your cellForRow:atIndexPath: should look something like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return cell with data
if (indexPath.row < dataArray.count) {
UITableViewCell *cell = [self.myTable dequeueReusableCellWithIdentifier:#"cell_prototype_1"];
[cell.textLabel setText:dataArray[indexPath.row]];
return cell;
}
// If it's the last index, return cell with button
else {
UITableViewCell *cell = [self.myTable dequeueReusableCellWithIdentifier:#"cell_prototype_2"];
return cell;
}
// This won't get called
return [UITableViewCell new];
}
That will be better if you use two different cells otherwise replace the code in your cellForRowAtIndexPath
if (indexPath.row == rowCount -1){}
with
if ( (indexPath.row-15)%10 == 0 ){}
and Put
[cell.textLabel setText:dataArray[indexPath.row]];
in the else part.
and place code just below UITableViewCell *cell....
for(UIView *view in cell.view.subviews){
if([view isKindOfClass: [UIButton class]]){
[view removeFromSuperView];
}
}
I think you need to refresh visible cells, doing:
[tableView reloadRowsAtIndexPaths:[tableView indexPathsForVisibleRows]
withRowAnimation:UITableViewRowAnimationNone];
Also better way to do it would be that you have 2 prototype cells, one for data, one with button. let's sey you give the second one identifier "buttonCell", than you just do this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *idintify = (indexPath.row < rowCount -) ? #"Cell" : #"buttonCell";
UITableViewCell *cell = [self.myTable dequeueReusableCellWithIdentifier:idintify];
if (cell == nil) //initialize
if (indexPath.row < rowCount -1) {
[cell.textLabel setText:dataArray[indexPath.row]];
}
return cell;
}
and in didSelectRowAtIndexPath you increase rowCount and reload data if indexPath.row == rowCount - 1
I am fairly new to Objective C programming, and have a UITableView setup with a custom cell. I want to make it so a user can touch a button that will add another cell, and this button will appear in the last cell only. Currently, it is not showing up. Here is the code that I am using. I have created the button within the custom cell, and used "setHidden:YES" to hide it within the cell itself. I am trying "setHidden:NO" to make the button appear in the TableView code, but it is not working. I thought maybe it had something to do with reloading the cell, but I am not sure if I am going in the right direction with this or not. I would appreciate any help on this, thanks.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{workoutTableViewCell *cell = (workoutTableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// Configure the cell...
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
[cell.addButton setTitle:(NSString *)indexPath forState:UIControlStateApplication];
[cell.textLabel setText:[NSString stringWithFormat:#"Row %i in Section %i", [indexPath row], [indexPath section]]];
NSInteger sectionsAmount = [tableView numberOfSections];
NSInteger rowsAmount = [tableView numberOfRowsInSection:[indexPath section]];
if ([indexPath section] == sectionsAmount - 1 && [indexPath row] == rowsAmount - 1) {
NSLog(#"Reached last cell");
[cell.addButton setHidden:NO];
if (lc == NO)
{[[self tableView] reloadData];
lc = YES;
}
}
return cell;
}
Following UITableViewDataSource method will help you to return exact number of rows available in section. Here you need to return additional as you want to have last as your button.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return yourRowCount + 1;
}
Now in folowing method you will check row number using indexpath.row as
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *lastCellIdentifier = #"LastCellIdentifier";
static NSString *workoutCellIdentifier = #"WorkoutCellIdentifier";
if(indexPath.row==(yourRowCount+1)){ //This is last cell so create normal cell
UITableViewCell *lastcell = [tableView dequeueReusableCellWithIdentifier:lastCellIdentifier];
if(!lastcell){
lastcell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:lastCellIdentifier];
CGRect frame = CGRectMake(0,0,320,40);
UIButton *aButton = [UIButton buttonWithType:UIButtonTypeCustom];
[aButton addTarget:self action:#selector(btnAddRowTapped:) forControlEvents:UIControlEventTouchUpInside];
aButton.frame = frame;
[lastcell addSubview:aButton];
}
return lastcell;
} else { //This is normal cells so create your worktouttablecell
workoutTableViewCell *cell = (workoutTableViewCell *)[tableView dequeueReusableCellWithIdentifier:workoutCellIdentifier];
//Configure your cell
}
}
Or you can do like create UIView programatically and set it as FooterView as suggested by #student in comment code would look like,
CGRect frame = CGRectMake(0,0,320,40);
UIView *footerView = [[UIView alloc] initWithFrame:frame];
UIButton *aButton = [UIButton buttonWithType:UIButtonTypeCustom];
[aButton addTarget:self action:#selector(btnAddRowTapped:) forControlEvents:UIControlEventTouchUpInside];
aButton.frame = frame;
[footerView addSubView:aButton];
[yourTableNmae setTableFooterView:footerView];
Declare method as follow
-(IBAction)btnAddRowTapped:(id)sender{
NSLog(#"Your button tapped");
}
if ([indexPath section] == sectionsAmount - 1 && [indexPath row] == rowsAmount - 1) {
NSLog(#"Reached last cell");
[cell.addButton setHidden:NO];
} else {
[cell.addButton setHidden:YES];
}
Replace this code in your program.
If you know your number of cells in the uitable and you wish to just know when the last row will appear, you could implement the following delegate method
(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
this method tells the delegate table view is about to draw cell for particular row, simple compare your row with table rowcount.
Ok, so I have this puzzling bug in my app.
I created a TableView dynamically and filled it with some data (the data is not the issue here, empty cells behaves the same). The UITableView displays fine and the data is loaded ok. When i tap the rows in the cell everything is FINE, it selects normally and deselects normally! No worries at all.
Problem:
When I scroll the UITableView it's scrolling normally BUT whenever i try to select a row after scrolling it, the wrong row is selected. The row selected is the one that was pointed at when starting to scroll. It's like the row is getting selected upon touch when you start to scroll and then fires didSelectRowAtIndexPath: when you try to tap on another row in the table. Once the wrong row is selected you can again select the rows you want, until you scroll again!
What could be causing this?
Here's my code for the table view!
//Function to display a summary view after answering all the questions
-(IBAction)displaySummaryView {
viewSummary = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height-60)];
[viewSummary setAlpha:0.0f];
[viewSummary setHidden:YES];
UITableView *tableView = [[UITableView alloc] init];
[tableView setBackgroundColor:[UIColor clearColor]];
[tableView setSeparatorColor:[UIColor colorWithWhite:0.0f alpha:0.25f]];
[tableView setDataSource:self];
[tableView setDelegate:self];
[tableView setTranslatesAutoresizingMaskIntoConstraints:NO]; //Taken care of elsewhere
[viewSummary addSubview:tableView];
//Get all the answers and sort them right!
NSMutableString *predicate = [[NSMutableString alloc] initWithString:#"((SELF.id == '-1')"]; //Init with dummy
for(Answer *ans in activeSession.answers) {
[predicate appendFormat:#" OR (SELF.id == %#)", ans.question_id];
}
[predicate appendFormat:#")"];
summaryQuestionsAndAnswers = nil;
summaryQuestionsAndAnswers = [currentQuestions filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:predicate]];
predicate = nil;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [summaryQuestionsAndAnswers count];
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 120.0f;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *cellIdentifier = [NSString stringWithFormat:#"formCell%d",indexPath.row];
UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
//Cell creation here
}
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
NSLog(#"Indexpath section %d row %d", indexPath.section, indexPath.row);
}
-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
[cell setBackgroundColor:[UIColor clearColor]];
}
Solved it!
I had a window that logged all touches in the app. This is the function that screwed up my code! Good luck any others encountering this bug. It's usually NOT a reuseIdentifier problem.
if (touch.phase == UITouchPhaseBegan) {
for (UIView *view in views) {
if ( ![view isHidden] && [view pointInside:[touch locationInView:view] withEvent:event] ) {
touchView = view;
[touchView touchesBegan:[event allTouches] withEvent:event];
break; //NOTE: this used to be a return in the previous version
}
}
}
I have a UIViewController with a UITableView which has multiple accessory checkmark implemented into it. My problem is, when I click some cells in the tableview it gets checked but there will be some other cell also checked below. I can view it when I scroll down the tableview. I would only want the cell to be checked whichever the user is clicking and not the extra cells. Please let me know how can I do it. Thanks.
Here is the code:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [someData count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"Cell"];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
cell.textLabel.text=[self.someData objectAtIndex:indexPath.row];
cell.textLabel.font=[UIFont fontWithName:#"Times New Roman" size:11];
cell.textLabel.lineBreakMode = NSLineBreakByWordWrapping;
[cell.textLabel setNumberOfLines:2];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
if ([selectedCell accessoryType] == UITableViewCellAccessoryNone) {
[selectedCell setAccessoryType:UITableViewCellAccessoryCheckmark];
NSArray *arrayOfIndexPathsTableOne = [self.tableView indexPathsForSelectedRows];
for (int i = 0; i < [arrayOfIndexPathsTableOne count]; i++) {
NSIndexPath *indexPathImInterestedIn = [arrayOfIndexPathsTableOne objectAtIndex:i];
UITableViewCell *currentCell = [self.tableView cellForRowAtIndexPath:indexPathImInterestedIn];
[saveData addObject:[NSString stringWithFormat:#"%#", currentCell.textLabel.text]];
}
} else {
[selectedCell setAccessoryType:UITableViewCellAccessoryNone];
NSArray *arrayOfIndexPathsTableOne = [self.tableView indexPathsForSelectedRows];
for(int i = 0; i < [arrayOfIndexPathsTableOne count]; i++) {
NSIndexPath *indexPathImInterestedIn = [arrayOfIndexPathsTableOne objectAtIndex:i];
UITableViewCell *currentCell = [self.tableView cellForRowAtIndexPath:indexPathImInterestedIn];
[saveData removeObject:[NSString stringWithFormat:#"%#", currentCell.textLabel.text]];
}
}
[tableView deselectRowAtIndexPath:indexPath animated:NO];
}
This is a cell reuse problem.
To fix, ensure that each time you return a cell from cellForRowAtIndexPath: you always set the selection (checkmark) status. That means explicitly setting it true and false as appropriate.
There are only 2 things you need:
Disable multiple selection on your UITableView.
Implement setSelected:(BOOL)selected in your UITableViewCells and make it select/deselect the cell's sub-views (your checkmarks) accordingly.
When you select table you show check box on it but when you scroll and the cell desapeare and it goes to reusable pool after you scroll back the cell is taken from this pool and it doesn't remember the 'state'.
The solution is create NSMutableArray and in didSelectCellAtIndexPath: method add or remove the indexPath for that cell to the array and in cellForRowAtIndexPath: check this array and show/hide checkmark base on that table.
dont write this line in cell for row at index path
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"Cell"];
it must be in loadview or viewdidload