I an creating app that needs expand tableview feature like below screen. when i click the row the textbox and button will appear.when i click on textbox and press return from keyboard, application crashed.
When I tried to resign the text box showing in screenshot, application crashed,
I write Following Code...
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return 10;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"AffiliationCell"];
cell.backgroundColor = [UIColor clearColor];
UILabel *lblTitle = [[UILabel alloc] initWithFrame:CGRectMake(15, 0, 130, 44)];
lblTitle.tag = indexPath.row+1;
lblTitle.font = [UIFont fontWithName:Oxygen_Regular size:13];
lblTitle.text = [NSString stringWithFormat:#"Affiliation %d",indexPath.row+1];
lblTitle.backgroundColor = [UIColor clearColor];
lblTitle.textColor = [UIColor blackColor];
[cell.contentView addSubview:lblTitle];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell* checkCell = [tableView cellForRowAtIndexPath:indexPath];
[tableView beginUpdates];
if ([indexPath compare:self.checkedIndexPath] == NSOrderedSame) {
self.checkedIndexPath = nil;
[viewScreenName removeFromSuperview];
} else {
//add view
[txtScreenName setClearsOnInsertion:YES];
viewScreenName.frame = CGRectMake(0, 45, viewScreenName.frame.size.width, viewScreenName.frame.size.height);
[checkCell.contentView addSubview:viewScreenName];
self.checkedIndexPath = indexPath;
}
[tableView endUpdates];
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
if ([indexPath compare:self.checkedIndexPath] == NSOrderedSame) {
return expandedCellHeight; // Expanded height
}
return 44 ;
}
#pragma mark - TextField Delegate
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField{
tblAffiliations.frame = updatedFrame;
return TRUE;
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField{
#try {
if (textField) {
[textField resignFirstResponder];
}
}
#catch (NSException *exception) {
NSLog(#"Exception %#",exception);
}
tblAffiliations.frame = currentFrame;
return TRUE;
}
Please Help.
It seems that you are using a textfield that is being deallocated. I think the best way to proceed is adding the textfield in each cell like you added your label and setting it to be hidden. On the didSelectRow delegate, you should set the label as hidden and the textfield not hidden. It is better to work with hidden flag that to remove and add from superview.
Wish it helps.
Related
I have a tableviewcontroller that has dynamic controls created in cells. If it's a dropdown type, I take the user to a different tableviewcontroller to select the value. Once selected, I pop back and reload the data, but when I do that it overwrites the cells on top of one another. I know this is because I'm reusing the cells, but I cannot seem to figure out how to prevent it.
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:YES];
[self.tableView reloadData];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
EWHInboundCustomAttribute *ca = [visibleCustomAttributes objectAtIndex:indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell"];
cell.tag=indexPath.row;
if (ca.CustomControlType == 1) {
cell.detailTextLabel.hidden=true;
cell.textLabel.hidden=true;
UITextField *caTextField = [[UITextField alloc] initWithFrame:CGRectMake(10, 10, 185, 30)];
caTextField.adjustsFontSizeToFitWidth = YES;
caTextField.textColor = [UIColor blackColor];
caTextField.placeholder = ca.LabelCaption;
if (ca.ReadOnly) {
[caTextField setEnabled: NO];
} else {
[caTextField setEnabled: YES];
}
caTextField.text=nil;
caTextField.text=ca.Value;
caTextField.tag=indexPath.row;
caTextField.delegate=self;
[cell.contentView addSubview:caTextField];
} else if (ca.CustomControlType == 4) {
cell.detailTextLabel.text=ca.Value;
cell.textLabel.text=ca.LabelCaption;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
} else {
cell.detailTextLabel.hidden=true;
cell.textLabel.hidden=true;
UITextField *caTextField = [[UITextField alloc] initWithFrame:CGRectMake(10, 10, 185, 30)];
caTextField.adjustsFontSizeToFitWidth = YES;
caTextField.textColor = [UIColor grayColor];
caTextField.placeholder = ca.LabelCaption;
[caTextField setEnabled: NO];
caTextField.text = ca.Value;
caTextField.tag=indexPath.row;
caTextField.delegate=self;
[cell.contentView addSubview:caTextField];
}
return cell;
}
Instead of creating the UITextfield each time I would suggest at least using [UIView viewWithTag:tag] to capture the same UITextField object.
I'd suggest you to create custom UITableViewCell subclass and put all subviews related logic there.
Next, in order to reset/clear cell before reuse - you should override prepeareForReuse function.
Swift:
override func prepareForReuse() {
super.prepareForReuse()
//set cell to initial state here
}
First,I suggest you to use custom cells.If not and your cells are not so many,maybe you can try unique cell identifier to avoid cell reuse:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// unique reuseID
NSString *cellReuseID = [NSString stringWithFormat:#"%ld_%ld", indexPath.section, indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellReuseID];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellReuseID];
// do something
}
return cell;
}
Hope it's helpful.
I created a UITableView programmatically and set all of its attributes, but the data from my NSMutableArray will not populate the cells and the cells do nothing when tapped. Any insight appreciated, thanks!
Clayton
- (void)viewDidLoad {
[super viewDidLoad];
[self.view setBackgroundColor:[UIColor whiteColor]];
list = [[UITableView alloc] initWithFrame:CGRectMake(0, self.view.bounds.size.height * .3333, self.view.bounds.size.width, self.view.bounds.size.height * .6667) style:UITableViewStylePlain];
list.delegate = self;
list.dataSource = self;
list.backgroundColor = [UIColor magentaColor];
list.scrollEnabled = YES;
list.userInteractionEnabled = YES;
list.multipleTouchEnabled = YES;
list.hidden = NO;
[self.view addSubview:list];
[self.view bringSubviewToFront:list];
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [favorites count];
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *Cell = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:Cell];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:Cell];
}
cell.textLabel.text = [[global sharedInstance].favorites objectAtIndex:indexPath.row];
cell.textLabel.textColor = [UIColor blackColor];
cell.userInteractionEnabled = YES;
cell.hidden = NO;
cell.multipleTouchEnabled = YES;
[self.view bringSubviewToFront:cell];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"selected %ld row", (long)indexPath.row);
}
Got it thanks, the problem was with the data transferring from my singleton array of favorites to my local array (which was previously empty). Much obliged :)
At the end of viewDidLoad method, just add this:
[list reloadData];
I am making an inbox module in my app.On first load 20 messages are coming from server.
I want that after 20 messages a label named "load more messages" will be create in UItableview cell.
and after clicking on that label i want to make another call to server.
I had tried following code but it is not working . thanx in advance:(
below is my sample code of cellForRowAtIndexPath and numberOfRowsInSection
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [inboxmessagesarray count]+1;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *tableviewidentifier = #"cell";
__block tablecellTableViewCell *cell= [self.activitiesTableView_ dequeueReusableCellWithIdentifier:tableviewidentifier];
if(cell==nil)
{
cell = [[tablecellTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:tableviewidentifier];
}if(indexPath.row == [self tableView:self.activitiesTableView_ numberOfRowsInSection:indexPath.section] - 1){
cell.textLabel.text=#"Load More Record";// here i am making a label but it is not showing at the end of tableview cell
}
else{
__block NSString *row = [NSString stringWithFormat:#"%ld",(long)indexPath.row];
cell.titlename.font=[UIFont fontWithName:#"SegoeUI" size:15];
cell.tolbl.font=[UIFont fontWithName:#"SegoeUI-light" size:12];
cell.fromlbl.font=[UIFont fontWithName:#"SegoeUI-light" size:12];
cell.datelbl.font=[UIFont fontWithName:#"SegoeUI-light" size:8];
cell.timelbl.font=[UIFont fontWithName:#"SegoeUI-light" size:8];
if([[[self.inboxmessagesarray objectAtIndex:indexPath.row]objectForKey:#"messageRead"] intValue]==0)
{
cell.titlename.font=[UIFont fontWithName:#"SegoeUI" size:15];
cell.tolbl.font=[UIFont fontWithName:#"SegoeUI-light" size:12];
cell.fromlbl.font=[UIFont fontWithName:#"SegoeUI-light" size:12];
cell.datelbl.font=[UIFont fontWithName:#"SegoeUI-light" size:8];
cell.timelbl.font=[UIFont fontWithName:#"SegoeUI-light" size:8];
cell.contentView.backgroundColor=[UIColor lightGrayColor];
}
else
{
cell.titlename.font=[UIFont fontWithName:#"SegoeUI" size:15];
cell.tolbl.font=[UIFont fontWithName:#"SegoeUI-light" size:12];
cell.fromlbl.font=[UIFont fontWithName:#"SegoeUI-light" size:12];
cell.datelbl.font=[UIFont fontWithName:#"SegoeUI-light" size:8];
cell.timelbl.font=[UIFont fontWithName:#"SegoeUI-light" size:8];
cell.contentView.backgroundColor=[UIColor clearColor];
}
cell.titlename.text=[[self.inboxmessagesarray objectAtIndex:indexPath.row]objectForKey:#"offerTitle"];
//toCity
cell.tolbl.text=[[self.inboxmessagesarray objectAtIndex:indexPath.row]objectForKey:#"toCity"];
cell.fromlbl.text=[[self.inboxmessagesarray objectAtIndex:indexPath.row]objectForKey:#"fromCity"];
if(![[imagesDictionary allKeys] containsObject:row]) //if image not found download and add it to dictionary
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
NSString *img=[[self.inboxmessagesarray objectAtIndex:indexPath.row]objectForKey:#"offerPhoto"];// here i am getting image path
NSURL *url = [NSURL URLWithString:img];
NSData * imageData = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:imageData];
dispatch_sync(dispatch_get_main_queue(), ^{ //in main thread update the image
[imagesDictionary setObject:image forKey:row];
cell.profileimage.image = image;
cell.textLabel.text = #""; //add this update will reflect the changes
NSLog(#"loading and adding to dictionary");
});
});
}
else
{
cell.profileimage.image = [imagesDictionary objectForKey:row];
NSLog(#"retriving from dictionary");
}
cell.datelbl.text=[[self.inboxmessagesarray objectAtIndex:indexPath.row]objectForKey:#"messageDate"];
cell.timelbl.text=[[self.inboxmessagesarray objectAtIndex:indexPath.row]objectForKey:#"messageTime"];
}
return cell;
}
As u want a row to be added to tableview that shows Load More Records u can do it in 2 ways either by adding a footer view or every last row, by passing one extra row in the method -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section and return a particular cell for this row in -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
for example add one more custom cell in the tableview and add a label and set its text as Load more record and set its reuse identifier as LabelCell
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.inboxmessagesarray.count + 1 ;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//[self performSegueWithIdentifier:#"segueIdentifier" sender:tableView];
if(indexPath.row == [self.inboxmessagesarray count])
{
NSLog(#"load more records");
}
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
__block tablecellTableViewCell *cell= [tableView dequeueReusableCellWithIdentifier:tableviewidentifier];
if(cell == nil)
{
cell = [[tablecellTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:tableviewidentifier];
}
//in the last row
if(indexPath.row == self.inboxmessagesarray.count)
{
cell = [tableView dequeueReusableCellWithIdentifier:#"LabelCell"];
if(cell == nil)
{
cell = [[tablecellTableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"LabelCell"];
}
if([self.inboxmessagesarray count] > 0)
cell.hidden = NO;
else
cell.hidden = YES;
return cell;
}
//..rest of the code
try to use following Methods of UITableView
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
return 40;
}
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section {
UIView * viewHeader = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 320, 40)];
[viewHeader setBackgroundColor:[UIColor redColor]];
UIButton * btnLoadMore = [UIButton buttonWithType:UIButtonTypeCustom];
[btnLoadMore setFrame:CGRectMake(10, 5, 300, 30)];
[btnLoadMore setTitle:#"Load More Record" forState:UIControlStateNormal];
[btnLoadMore setTintColor:[UIColor blackColor]];
[btnLoadMore setBackgroundColor:[UIColor clearColor]];
[btnLoadMore addTarget:self action:#selector(loadMoreRecords:) forControlEvents:UIControlEventTouchUpInside];
[viewHeader addSubview:btnLoadMore];
return viewHeader;
}
- (void)loadMoreRecords : (id) sender {
NSLog(#"Your code to load more data");
}
you can use this in multiple types here I add in 3 types, customize your self
choice No 1
assume that u get the all data (e.g 100) from server , store in the some NSMutableArray, concept is declare one global int
int loadMoreItems;
in your viewWillAppear
-(void)viewWillAppear:(BOOL)animated
{
loadMoreItems=21; // initially set the count is more than 20
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if ([yourTotalArrayName count]<=loadMoreItems) {
return [yourTotalArrayName count];
}
else {
return loadMoreItems;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier;
// add your data
if (indexPath.row+1<loadMoreItems)
{
cell.lblLoadMoreItems.hidden=YES;
cell.itemsdetails.text = [NSString stringWithFormat:#"%#",[yourTotalArrayName objectAtIndex:indexPath.row]] ;
}
else
{
cell.itemsdetails.hidden=YES;
cell.lblLoadMoreItems.text = #"Load more results...!";
}
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row+1<loadMoreItems) {
// here do your stuff here
}
else {
loadMoreItems=loadMoreItems+20;
[self.yourtableview reloadData];
}
choice no 2
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Classic start method
// here add your data loaded
if (indexPath.row == [self.yourarrayName count] - 1)
{
cell.lblLoadMoreItems.text = #"Load more results...!";
[self launchReload];
}
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row == [self.yourarrayName count] - 1)
{
[self launchReload];
}
}
-(void)launchRelaod
{
// call the webservice
[self.yourtableview reloadData];
}
choiceNo 3
use 2 prototype cell in `UItableView`
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [yourarrayname count] + 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *postCellId = #"postCell";
static NSString *moreCellId = #"moreCell";
UITableViewCell *cell = nil;
if ([indexPath row] == [yourarrayname count]) {
cell = [tableView dequeueReusableCellWithIdentifier:moreCellId];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:moreCellId];
}
cell.textLabel.text = #"Load more items...";
cell.textLabel.textColor = [UIColor blueColor];
}
else
{
cell = [tableView dequeueReusableCellWithIdentifier:postCellId];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:postCellId];
}
// show your Data
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([indexPath row] == [yourarrayname count]) {
// call the web service and reload Data of UItableview
}
else
{
//normall selcftion procedure
}
}
Add your label as a Table's footerview.
tableview.tableFooterView = label;
By this you will get your label at the end of your table always.
And for load more action add tap gestures to the label.
If you just want something to show up at the bottom or below your tableView you just implement a quick step:
This will waive any auto layout woes or troubles with a UILabels frame or origins (it will never move)
UIView* footerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.tableView.bounds.size.width, 25)];
UIButton *loadMoreButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 100, 25)];
[loadMoreButton setTitle:#"Load More" forState:UIControlStateNormal];
[loadMoreButton addTarget:self action:#selector(loadMore:) forControlEvents:UIControlEventTouchUpInside];
//More customizing
[footerView addSubview:loadMoreButton];
self.tableView.tableFooterView = footerView;
-(IBAction)loadMoreButton:(id)sender {
//load more from server
}
I add a simple UITableView to my project,and every cell include a UITextField with clearButtonMode = UITextFieldViewModeAlways.
but strange issue occurs .when I reloadData,some textfield don't show clear button.
so I grab the part and build a sample and never find this issue.
I just wonder is some property has a effect to the textField.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"userIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:cellIdentifier];
}
for (UIView *sv in cell.contentView.subviews) {
[sv removeFromSuperview];
}
UITextField *tf = [[UITextField alloc] initWithFrame:cell.bounds];
tf.text = [self.tb_data[indexPath.row];
tf.rightViewMode = UITextFieldViewModeAlways;
tf.clearButtonMode = UITextFieldViewModeAlways;
tf.tag = indexPath.row+100;
tf.delegate = self;
[[cell contentView] addSubview:tf];
return cell;
}
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
if (textField.tag >= 100) {
return NO;
}
return YES;
}
- (BOOL)textFieldShouldClear:(UITextField *)textField
{
if (textField.tag >= 100) {
[self.tb_data removeObjectAtIndex:textField.tag-100];
[self.tb beginUpdates];
[self.tb deleteRowsAtIndexPaths:#[[NSIndexPath indexPathForRow:textField.tag-100 inSection:0]] withRowAnimation:UITableViewRowAnimationLeft];
[UIView animateWithDuration:0.3
animations:^{
CGRect frame = self.tb.frame;
frame.size.height = 40*self.tb_data.count;
self.tb.frame = frame;
}];
[self.tb endUpdates];
[self.tb reloadData];
}
return YES;
}
I insert a segmented in uitableview like this url image. If you see the url image, now i'm working ok everything data in uitable,
and...
When i scroll down table i wanna part 1: Image(in url) will scroll scroll to part 2: segmented will stop and if you still scroll uitable part 3: the data will be scroll (keep segmented on the top).
Have you any idea it. Thanks
I just test it, it is working!
Set your UITableView pain
UITableView has two section and each section has only one row.
When edit your section header, make sure only second section has header - second header will be your part2.
first section first row is your part1.
second section first row is your part3.
That's it : )
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 2;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = #"test";
return cell;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{
#try {
UIView *containerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 30)];
switch (section) {
case 0:
{
//nothing
}
break;
case 1:
{
UILabel *lbl = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 320, 30)];
lbl.text = #"second";
lbl.textColor = [UIColor blackColor];
[containerView addSubview:lbl];
}
break;
}
return containerView;
}
#catch (NSException *exception) {
}
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{
return 30;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return 1000.0;
}