I have a reusableCell that has a label for which the values are supplied by an array. But the values of the label and the constraints change every time, my cellForRowAtIndexPath code looks like
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if(indexPath.row % 2 == 0)
{
isReceived =TRUE;
}
else{
isReceived = FALSE;
}
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"id" forIndexPath:indexPath];
ChatMessageCellTableViewCell *messageCell = (ChatMessageCellTableViewCell*) cell;
if(messageCell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"ChatMessageCellTableViewCell" owner:self options:nil];
messageCell = [nib objectAtIndex:0];
}
else{
[[messageCell formLabel]setText:messages[indexPath.row]];
[messageCell setSelectionStyle:UITableViewCellSelectionStyleNone];
} // this else part is just to make sure that the if has a else part as I saw many people it will work , but in my case it didn't help.
[[self tableView] setEstimatedRowHeight:50.0];
[self.tableView setRowHeight:UITableViewAutomaticDimension];
return messageCell;
}
When I scroll the table, Values are changing. I tried many different way, but could not find a solution and I am so confused that I had to post my question.
Thank You
I know it's bad practice to answer your own post, but I hope this helps someone
I was able to avoid those changes by changing the method cellForRowAtIndexPath
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *cellIdentifier = (indexPath.row % 2 == 0 ? #"EvenCell" : #"OddCell"); //using different identifier for every cell did the trick I guess
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
ChatMessageCellTableViewCell *messageCell = (ChatMessageCellTableViewCell*) cell; ;
if (messageCell == nil) {
messageCell = [[ChatMessageCellTableViewCell alloc] initWithStyle: UITableViewCellStyleDefault
reuseIdentifier:cellIdentifier];
if(indexPath.row % 2 == 0)
{
isReceived =TRUE;
}
else{
isReceived = FALSE;
}
}
[[messageCell formLabel]setText:messages[indexPath.row]];
[messageCell setSelectionStyle:UITableViewCellSelectionStyleNone];
[[self tableView] setEstimatedRowHeight:50.0];
[self.tableView setRowHeight:UITableViewAutomaticDimension];
return messageCell;
}
I have commented the change's which I have made in order to prevent changes in the cell's while scrolling.
Thanks for all the support :)
There is a wrong logic in your code, your code is only assign data for reused cell but not for new created cell. You should move the code in else bracket out like this.
ChatMessageCellTableViewCell *messageCell = (ChatMessageCellTableViewCell*) cell;
if(messageCell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"ChatMessageCellTableViewCell" owner:self options:nil];
messageCell = [nib objectAtIndex:0];
}
[[messageCell formLabel]setText:messages[indexPath.row]];
[messageCell setSelectionStyle:UITableViewCellSelectionStyleNone];
I'm not familiar with Obj-C, but this may helpful to you.
if youHaveTitleText {
cell.title.text = data.displayText
} else {
cell.title.text = ""
}
Related
I have a UITableView with two different custom cells. One will show normal text message and other with some text and image. I am able to use two different custom cells in cellForRowAtIndexPath and able to see two different cells like below
But whenever i scroll the tableview then the cells are overlapping like below.
Below is my code
-(CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
//minimum size of your cell, it should be single line of label if you are not clear min. then return UITableViewAutomaticDimension;
return UITableViewAutomaticDimension;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
id cell = [tableView cellForRowAtIndexPath:indexPath];
if ([cell isKindOfClass:[TicketTableViewCell class]]) {
return 171;
} else {
return UITableViewAutomaticDimension;
}
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [chatHistoryArr count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *msgTypeStr = [msgTypeArr objectAtIndex:indexPath.row];
if ([msgTypeStr isEqualToString:#"msg"]) {
static NSString *simpleTableIdentifier = #"ChatConversationTableViewCell";
ChatConversationTableViewCell *cell = (ChatConversationTableViewCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"ChatConversationTableViewCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.chatmsgLabel.text = [chatHistoryArr objectAtIndex:indexPath.row];
cell.timeAndDateMsgLabel.text = [timeAndDateMsgArr objectAtIndex:indexPath.row];
return cell;
}
else{
static NSString *simpleTableIdentifier = #"TicketTableViewCell";
TicketTableViewCell *cell = (TicketTableViewCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"TicketTableViewCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.tktMsgTxtView.text = [chatHistoryArr objectAtIndex:indexPath.row];
cell.ticketDateAndTimeLbl.text =[timeAndDateMsgArr objectAtIndex:indexPath.row];
return cell;
}
}
No issues in showing data or showing different cells, only problem is overlapping. I have already tried the available solutions but no luck. Below is one of them.
adding the below code in cellForRowAtIndexPath but no use.
for(UIView *view in cell.contentView.subviews){
if ([view isKindOfClass:[UIView class]]) {
[view removeFromSuperview];
}
}
Tried a lot to fix the issue but no luck. Any help will be really appreciated.
Change your code of tableViewCell height
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *msgTypeStr = [msgTypeArr objectAtIndex:indexPath.row];
if ([msgTypeStr isEqualToString:#"msg"]) {
return UITableViewAutomaticDimension;
} else {
return 171;
}
}
It will resolve your overlap issue.
Try this once
NSString *CellIdentifier = [NSString stringWithFormat:#"Cell %d",indexPath.row];
UITableViewCell *cell=[self.tableView cellForRowAtIndexPath:indexPath];
if (cell == nil){
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
My Custom tableview cell content getting empty after scrolling.So pls help me with this.
My custom cell has 8 buttons and a label.First I'm showing only label that has title and on selection I'm expanding the cell and showing all buttons.So, when I select few buttons and I do scrolling,buttons that I selected getting refreshed or get back to normal state.Here is the code.Pls help me with this
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"newFilterCell";
newFilterCell *cell = (newFilterCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"newFilterCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
[cell.contentView.superview setClipsToBounds:YES];
}
cell.QuestionLabel.text=[orderArray objectAtIndex:indexPath.row];
NSArray * arr = [filterInfo objectForKey:[orderArray objectAtIndex:indexPath.row]];
int val = 0;
NSLog(#"%#",cell.subviews);
NSArray * cellViews = cell.contentView.subviews;
if (arr.count>0)
{
for (int i=1; i<=8; i++) {
if (i<=arr.count) {
UIButton * target = (UIButton*)[cell viewWithTag:i];;
[target setTitle:[arr objectAtIndex:i-1]forState:UIControlStateNormal];
[target addTarget:self action:#selector(selectButton:) forControlEvents:UIControlEventTouchUpInside];
}
else
{
[[cell viewWithTag:i] setHidden:YES];
}
}
}
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
return cell;
}
On selection of my cell I'm expanding and reloading the tableview cells.
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath==_expandIndexPath) {
_expandIndexPath = nil;
NSMutableArray *modifiedRows = [NSMutableArray array];
[tableView reloadRowsAtIndexPaths:modifiedRows withRowAnimation:UITableViewRowAnimationLeft];
}
else
{
selectedRow=indexPath.row;
NSMutableArray *modifiedRows = [NSMutableArray array];
[tableView deselectRowAtIndexPath:indexPath animated:TRUE];
_expandIndexPath = indexPath;
[modifiedRows addObject:indexPath];
[tableView reloadRowsAtIndexPaths:modifiedRows withRowAnimation:UITableViewRowAnimationLeft];
}
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
NSArray * arr = [filterInfo objectForKey:[orderArray objectAtIndex:indexPath.row]];
if ([indexPath isEqual:_expandIndexPath])
{
if ([[orderArray objectAtIndex:indexPath.row]isEqualToString:#"Height"]||[[orderArray objectAtIndex:indexPath.row]isEqualToString:#"Age"])
{
return 275;
}
else
{
if(arr.count==3)
return 55*arr.count;
else
return 37*arr.count;
}
}
else
return 70;
}
UITableViewCells are getting recycled. That's why its not safe to do it your way. Your data model needs to remember your buttons and other stuff that changed. You need to apply the changes every time the cell gets created.
You need to check in the cellForRowAtIndexPath what button is pressed and then show the view correctly.
You need to remember what happend in the cells with an external data source to apply the changes you want.
In your cellForRowAtIndexPath should be something like a check for a boolean whether or not you show some stuff:
if(button_is_pressed_for_row_5 == true){
button_in_cell.hidden = true;
}else{
button_in_cell.hidden = true;
}
I found it can create different cells with different xibs, but I want to know is possible to create different cell in one xib? If possible, what should I can do this?
Here is the code, I know it is wrong code, so can you guys help me to fix it?
- (void)viewDidLoad {
[super viewDidLoad];
[imageTableView registerNib:[UINib nibWithNibName:#"ImageTableViewCell" bundle:nil] forCellReuseIdentifier:#"oneImageTableViewCell"];
[imageTableView registerNib:[UINib nibWithNibName:#"ImageTableViewCell" bundle:nil] forCellReuseIdentifier:#"twoImageTableViewCell"];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
NSString *identifier1 = #"oneImageTableViewCell";
NSString *identifier2 = #"twoImageTableViewCell";
if (indexPath.row % 2 == 0) {
ImageTableViewCell *cell = [imageTableView dequeueReusableCellWithIdentifier:identifier1 forIndexPath:indexPath];
return cell;
} else {
ImageTableViewCell *cell = [imageTableView dequeueReusableCellWithIdentifier:identifier2 forIndexPath:indexPath];
return cell;
}
}
My first idea would be to not do it. But if I had to do it, I guess I'd try building cells by using the old style dequeue, and, to build the initial pool of reusable cells, by manually extracting them from the nib.
So, don't do any cell nib or cell class registration, then in cellForRowAtIndexPath...
NSString *identifier;
NSInteger index;
if (indexPath.row % 2 == 0) {
identifier = #"oneImageTableViewCell";
index = 0;
} else {
identifier = #"twoImageTableViewCell";
index = 1;
}
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (!cell) {
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"ImageTableViewCell" owner:self options:nil];
cell = topLevelObjects[index];
}
return cell;
I have one table that I want load from xib two cell.
in UITableViewCell xib file I have two cell (two part with tag 100 and 200) that I want load first view (first cell) in first row and load second cell in second row.
both cells are in xib file like this:
this is my code :
#pragma mark Table View Data Source Methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 2;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 2;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section == 0) {
CustomCell *cell = (CustomCell *)[self.table dequeueReusableCellWithIdentifier:#"myCell"];
if (cell == nil)
{
NSArray *topLevelObject = [[NSBundle mainBundle] loadNibNamed:#"CustomCell" owner:nil options:nil];
NSLog(#"%#",topLevelObject);
cell = [topLevelObject objectAtIndex:0];
NSLog(#"%#",cell);
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
else if (indexPath.section == 1) {
CustomCell *cell2 = (CustomCell *)[self.table dequeueReusableCellWithIdentifier:#"Cell2"];
if (cell2 == nil)
{
NSArray *topLevelObject = [[NSBundle mainBundle] loadNibNamed:#"CustomCell" owner:nil options:nil];
for (id currentObject in topLevelObject) {
if ([currentObject isKindOfClass:[CustomCell class]]) {
cell2 = (CustomCell *)currentObject;
break;
}
}
}
cell2.selectionStyle = UITableViewCellSelectionStyleNone;
return cell2;
}
return nil;
}
I don't know where is my wrong because when run code I see only first cell in tableView
You are using first cell from XIB at section = 0
cell = [topLevelObject objectAtIndex:0];
so, in the same way you can get the second cell at index 1 for the section 1
cell = [topLevelObject objectAtIndex:1];
This question already has answers here:
2 different types of custom UITableViewCells in UITableView
(3 answers)
Closed 9 years ago.
I'm having an issue and would like to know if what I am trying to do is even possible.
I have a ViewController that has a UITableView as a subview. I then loaded a custom cell and it worked fine. However, I needed another custom cell in the same tableview - this second cell has a separate nib as well.
Is this possible?
Two different custom cells in on section in a UITableView?
I did try something like this:
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier1 = #"ContentCell";
static NSString *CellIdentifier2 = #"SpaceCell";
// Space Cell
if (indexPath.row== 0) {
CellSpace *cell = (CellSpace *) [tableViewdequeueReusableCellWithIdentifier:CellIdentifier2];
return cell;
}
// Content cell
else {
CellView *cell = (CellView *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier1];
// Configure cell
return cell;
}
}
However it seems the else statement is never fired and I normally get a crash saying the method returned nil.
UPDATE
I used the advice and code here and came up with this:
#pragma mark - UITableView Delegate Methods
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 160;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 22;
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
-(UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier1 = #"UsernameCell";
static NSString *CellIdentifier2 = #"PasswordCell";
if(indexPath.row == 0) {
BBUsernameRegistrationCell *cell = (BBUsernameRegistrationCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier1];
if(cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:CellIdentifier1 owner:self options:nil]; // set properties
cell = nib[0];
}
// set properties
return cell;
}
// Content cell
else {
BBPasswordTableViewCell *cell = (BBPasswordTableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier2];
if(cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:CellIdentifier2 owner:self options:nil]; // set properties
cell = nib[0];
}
// set properties
return cell;
}
}
However I only see the first Cell in my tableview. If I switch the cells around the second one loads. But not both at the same time. Does anyone have any idea why?
Yes, it is possible..
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier1 = #"ContentCell";
static NSString *CellIdentifier2 = #"SpaceCell";
// Space Cell
if (indexPath.row== 0) {
CellSpace *cell = (CellSpace *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier2];
if(cell == nil) {
cell = [[CellSpace alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier1];
// set properties
}
// set properties
return cell;
}
// Content cell
else {
CellView *cell = (CellView *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier2];
if(cell == nil) {
cell = [[CellView alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier2];
// set properties
}
// set properties
return cell;
}
}
in your custom cell, do something like this in initWithStyle method:
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"CellView" owner:self options:nil];
for (id currentObj in topLevelObjects ) {
if ([currentObj isKindOfClass:[CellView class]]) {
self = (CellView*) currentObj;
}
}
return self;
}
Yes it is possible. But before use this dequeueReusableCellWithIdentifier:. Just register your cell and corresponding nib files.
code as..
-(void)initiateCellRegisteration
{
static NSString *CellIdentifier1 = #"ContentCell";
static NSString *CellIdentifier2 = #"SpaceCell";
[self.tableView registerClass:[ContentCell class] forCellReuseIdentifier:CellIdentifier2];
[self.tableView registerNib:[UINib nibWithNibName:CellIdentifier2 bundle:nil] forCellReuseIdentifier:CellIdentifier2];
[self.tableView registerClass:[SpaceCell class] forCellReuseIdentifier:CellIdentifier1];
[self.tableView registerNib:[UINib nibWithNibName:CellIdentifier1 bundle:nil] forCellReuseIdentifier:CellIdentifier1];
}
Call this method in viewDidLoad
If you are using the cell nib then you need little tricky way to get your cell nib like
static NSString *CellIdentifier = #"ProductCell";
IVProductCell *cell = (IVProductCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray* objects = [[NSBundle mainBundle] loadNibNamed:#"IVProductCell" owner:nil options:nil];
for (id currentObject in objects) {
if ([currentObject isKindOfClass:[IVProductCell class]]){
cell = (IVProductCell*) currentObject;
}
}
}