TableView Row unable to Select - iphone

I defined my own controller with no nib file like this:
#interface EngineViewController : UIViewController <UITableViewDelegate, UITableViewDataSource> {
EngineViewProperties* viewProp;
UIImageView *imgView; // image view of selected engine
NSUInteger selectedIndex;
UITableView *menu;
}
#property (nonatomic,retain) EngineViewProperties* viewProp;
- (EngineViewController *) initWithEngineViewProperties: (EngineViewProperties *) _viewProp;
- (void) dropdownMenu: (id) sender;
I created my view in loadView,with three subviews. The subview arrowBtn is helped to popup a list of search engines.
- (void)loadView {
// ...
UIButton *arrowBtn = [[UIButton alloc] initWithFrame:rect];
[arrowBtn setImage:viewProp.arrowImg forState:UIControlStateNormal];
[arrowBtn addTarget:self action:#selector(dropdownMenu:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:imgView];
[self.view addSubview:label];
[self.view addSubview:arrowBtn];
// ...
}
I create a table listing search engines in the selector dropdownMenu:
- (void) dropdownMenu: (id) sender {
UIButton *arrowBtn = (UIButton *)sender;
// ...
menu = [[UITableView alloc] initWithFrame:rect style:UITableViewStylePlain];
menu.delegate = self;
menu.dataSource = self;
menu.backgroundColor = [UIColor blackColor];
menu.allowsSelection = YES;
[self.view addSubview:menu];
[self.view bringSubviewToFront:menu];
[menu release];
}
And I implemented
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
as usual.
But the result is that the menu popup happily,but I can do nothing with the cells.I clicked the cells,but no response.Those methods like "didSelectRowAtIndexPath" can not be called.
Sorry to paste up so much codes one time.But I really need help.I don't know what is the problem.Please forgive me for my poor English and low development skill in Iphone.And thanks a lot if you give me a little suggestions.
//Added-------------------------
"numberOfRowsInSection" is simple:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [viewProp.txtArray count];
}
and another method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *MenuItems = #"MenuItems";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MenuItems];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier: MenuItems] autorelease];
}
NSUInteger row = [indexPath row];
cell.imageView.image = [viewProp.imgArray objectAtIndex:row];
cell.textLabel.text = [viewProp.txtArray objectAtIndex:row];
cell.textLabel.textColor = [UIColor whiteColor];
cell.textLabel.font = [UIFont systemFontOfSize:12.0];
cell.selectionStyle = UITableViewCellSelectionStyleNone; // Blue style tried,helpless too
if (row == selectedIndex) {
cell.selected = YES;
}
cell.userInteractionEnabled = YES;
return cell;
}
// Added
Strangely,when the menu firstly poped up,the default selected cell was highlighted correctly,but very quickly the highlighting disappeard.

Check if you have implemented this
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]
initWithTarget:self
action:#selector(dismissKeyboard)];
[self.view addGestureRecognizer:tap];
The didSelectRowAtIndexPath will not called if this is present. One way to workaround this is set [self.view addGestureRecognizer:tap]; towards your targeted view only such as [self.svContent addGestureRecognizer:tap];.
Alternatively, check which view is touched.
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
if ((touch.view == YourTable))
{
return NO;
}
return YES;
}

Try giving cell.selectionStyle = UITableViewCellSelectionStyleBlue in your table View data source. Also check if the userInteraction is enabled for the table view and the cells.

Are you showing any data in the table have you implemented
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
in you viewController??
Seems that you are setting the delgate property correctly, also you added the protocols to the same ViewController. So the problem can be either there is no data in the tableView for selection, or there is some View on top of tableView which is blocking you interaction with the tableView.

Use
cell.selectionStyle = UITableViewCellSelectionStyleGray;
in your
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
for your cell.
remove
cell.userInteractionEnabled = YES;
code from your file.

Related

Adding UIActivityIndicator to UITableView

I need to load some data in a table view and while this is going on in the background I want to add an activity indicator in order to show that there is a process going on and will hide once the process finishes. What would be the most efficient way to implement something like this?
Depends, whether you want to block your user or not and also how important is the activity indication.
If you don't want to block user, use Application.networkActivityIndicatorVisible, if you want to have larger activity indicator and still not to block user, animate UIView with text and UIActivityIndicator below the table view (tableview.height -= activityview.height) and then hide on complete or if you would like to block user, use blocking activity indicator.
http://www.dejal.com/developer/?q=developer/dsactivityview
https://github.com/jdg/MBProgressHUD (I was using MBProgressHUD personally and it's easy to learn and use)
You can add a view which has a UIIndicatorView and a UILabel as your cell's subview. You can use this way to show error data loading/ error network/ empty data...
Example:
Your Controller can define two modes: UITableViewModeMessage and UITableViewModeData.
In viewDidLoad, you set self.tableViewMode = UITableViewModeMessage. When has returned data, set self.tableViewMode = UITableViewModeData and reload data for tableview.
Some code:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (self.tableViewMode == UITableViewModeMessage) {
return 2;
} else {
return self.yourEntries ? self.yourEntries.count : 0;
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (self.tableViewMode == UITableViewModeMessage) {
return [self tableView:tableView messageCellForRowAtIndexPath:indexPath];
} else {
return [self tableView:tableView dataCellForRowAtIndexPath:indexPath];
}
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
// Remove Loading... progress view if exist.
UIView *progressView = [cell viewWithTag:100];
[progressView removeFromSuperview];
if (self.tableViewMode == UITableViewModeMessage) {
if (indexPath.row == 1) {
// remove the current label.
cell.textLabel.text = nil;
// We build progress view and attach to cell here but not in cellForRowAtIndexPath is because in this method cell frame is already calculated.
UIView *progressView = [self progressViewForCell:cell message:#"Loading..." alpha:0.9];
[cell addSubview:progressView];
}
}
}
// cell to display when loading
- (UITableViewCell *)tableView:(UITableView *)tableView messageCellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"MessageCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.textLabel.textColor = [UIColor grayColor];
cell.textLabel.textAlignment = UITextAlignmentCenter;
}
if (indexPath.row == 1) {
cell.textLabel.text = #"Loading...";
} else {
cell.textLabel.text = nil;
}
return cell;
}
// cell to display when has data
- (UITableViewCell *)tableView:(UITableView *)tableView dataCellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"DataCell";
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = [[self.yourEntries objectAtIndex:indexPath.row] description];
return cell;
}
// Build a view which has a UIActivityIndicatorView and a UILabel
- (UIView *)progressViewForCell:(UITableViewCell *)cell message:(NSString *)message alpha:(CGFloat)alpha
{
// NOTE: progressView needs to be removed from cell in cellForRowAtIndexPath:
CGRect progressViewFrame = CGRectZero;
progressViewFrame.size.width = CGRectGetMaxX(cell.bounds);
progressViewFrame.size.height = CGRectGetMaxY(cell.bounds) - 2;
UIView *progressView = [[UIView alloc] initWithFrame:progressViewFrame];
progressView.backgroundColor = RGBA(255, 255, 255, 1);
progressView.alpha = alpha;
progressView.tag = 100;
UILabel *loadingLabel = [[UILabel alloc] initWithFrame:progressView.bounds];
loadingLabel.backgroundColor = [UIColor clearColor];
loadingLabel.font = [UIFont systemFontOfSize:14];
loadingLabel.textColor = [UIColor blackColor];
loadingLabel.textAlignment = UITextAlignmentCenter;
loadingLabel.text = message;
CGFloat widthOfText = [loadingLabel.text sizeWithFont:loadingLabel.font].width;
CGFloat spaceBetweenIndicatorAndLabel = 5;
// activityIndicatorView has size in which width and height is equal to 20.
UIActivityIndicatorView *activityIndicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[activityIndicatorView setCenter:CGPointMake(CGRectGetMidX(cell.bounds) - (widthOfText / 2) - (activityIndicatorView.bounds.size.width / 2) - spaceBetweenIndicatorAndLabel, CGRectGetMidY(cell.bounds))];
[activityIndicatorView setColor:[UIColor blackColor]];
[activityIndicatorView startAnimating];
[progressView addSubview:activityIndicatorView];
[progressView addSubview:loadingLabel];
return progressView;
}

Creating A TableVIew Programmatically With Objective-C iOS

I'm new to developing iOS applications and Objective C itself, so I have a probably very simple question.
Currently I have the following method that is called from a ToolBar Button click. The method is designed to create a table view in the frame variable fr.
- (IBAction)addGolfer:(id)sender {
CGRect fr = CGRectMake(101, 45, 100, 416);
UITableView *tabrleView = [[UITableView alloc]
initWithFrame:fr
style:UITableViewStylePlain];
tabrleView.autoresizingMask =
UIViewAutoresizingFlexibleHeight |
UIViewAutoresizingFlexibleWidth;
tabrleView.delegate = self;
tabrleView.dataSource = self;
[tabrleView reloadData];
self.view = tableView;
}
The result of calling this method is not what I expect. Instead of creating the Table View in the frame "fr", the table view fills the entire screen.
Again I'm totally new and would a appreciate any answers and any suggestions. Thanks!
When you set dataSource and delegate properties for your UITableView, it means, you have to write at least this methods for dataSource:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
If you wouldn't do this, it will be crash. Summary you'll get this (this code may contain syntax or logic errors - I wrote it in notepad):
#interface YourViewController : UIViewController <UITableViewDataSource, UITableViewDelegate> {
UITableView *firstTableView;
UITableView *secondTableView;
}
#end
//
#implementation YourViewController
#pragma mark - Objects Processing
- (void)addGolfer:(UIBarButtonItem *)sender {
if (secondTableView) {
[secondTableView removeFromSuperView];
secondTableView = nil;
}
secondTableView = [[UITableView alloc] initWithFrame:CGRectMake(101, 45, 100, 416)];
secondTableView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
secondTableView.delegate = self;
tabrleView.dataSource = self;
[self.view addSubview:secondTableView];
}
#pragma mark - TableView DataSource Implementation
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (tableView == firstTableView) { // your tableView you had before
return 20; // or other number, that you want
}
else if (tableView == secondTableView) {
return 15; // or other number, that you want
}
}
- (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.backgroundView = [[UIView alloc] init];
[cell.backgroundView setBackgroundColor:[UIColor clearColor]];
[[[cell contentView] subviews] makeObjectsPerformSelector:#selector(removeFromSuperview)];
if (tableView == firstTableView) { // your tableView you had before
// ...
}
else if (tableView == secondTableView) {
cell.titleLabel.text = [NSString stringWithFormat:#"Cell %d", indexPath.row + 1];
}
return cell;
}
#end
Step 1: Add delegate UITableViewDataSource,UITableViewDelegate
#interface viewController: UIViewController<UITableViewDataSource,UITableViewDelegate>
{
UITableView *tableView;
}
Step 2:
-(void)viewDidLoad
{
tableView=[[UITableView alloc]init];
tableView.frame = CGRectMake(10,30,320,400);
tableView.dataSource=self;
tableView.delegate=self;
tableView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
[tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"Cell"];
[tableView reloadData];
[self.view addSubview:tableView];
}
Step 3: Properties for tableview (rows & column)
//-- For no of rows in table
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 10;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
//-- Table header height if needed
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return 50;
}
//-- Assign data to cells
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath] ;
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.textLabel.text=[your_array objectAtIndex:indexPath.row]; ***(or)*** cell.textLabel.text = #"Hello";
return cell;
}
//-- Operation when touch cells
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Your custom operation
}
Instead of setting the view of the UIViewController, add the tableView as a subview.
Instead of:
self.view = tableView;
Do this:
[self.view addSubview:tableView];
This will properly respect the frame that you set.

Customize header section for UITableViewController

I'll need to customize the header section of a UITableViewController where for each sections a different header text is returned (getting data from datasource as well). This is accomplished using the following:
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
NSArray *temp = [listOfMBeans allKeys];
DLog(#"MBean details: %#", temp);
NSString *title = [temp objectAtIndex:section];
DLog(#"Header Title: %#", title);
return title;
};
This works well and I can see the expected output. However I need to change also the font size of text and after looking at similar questions I've implemented the following:
- (UIView *) tableview:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
DLog(#"Custom Header Section Title being set");
UIView *headerView = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, tableView.bounds.size.width, 30)] autorelease];
UILabel *label = [[[UILabel alloc] initWithFrame:CGRectMake(0, 0, tableView.bounds.size.width, 30)] autorelease];
label.text = [tableView.dataSource tableView:tableView titleForHeaderInSection:section];
label.backgroundColor = [UIColor clearColor];
label.font = [UIFont boldSystemFontOfSize:14];
[headerView addSubview:label];
return headerView;
}
- (CGFloat) tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return 44.0;
}
However it seems that the code is never called. My understanding was that UITableViewController is setting by default itself as delegate but it seems I'm wrong.
The UITableViewController is created in this way (as part of hierarchical data):
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
ProjectDetails *detailViewController = [[ProjectDetails alloc] initWithStyle:UITableViewStyleGrouped];
detailViewController.project = [listOfMetrics objectAtIndex:indexPath.row];
// Push the detail view controller.
[[self navigationController] pushViewController:detailViewController animated:YES];
[detailViewController release];
}
What changes, I should make to make this working?
Thanks.
This question is an older one but I wanted to share my code. I'm using a usual table cell view for my section headers. I have designed it with interface builder and implemented the following delegate method.
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: #"Header"];
cell.textLabel.text = #"test";
return cell;
}
You can set explicitly the delegate:
detailViewController.tableView.delegate = detailViewController;
Or you can do it in the controller initial function.
EDIT: your init method should conform to the canonical init. Furthermore, it seems to me that you have not created your UITableView. Try and use this code:
- (id)initWithStyle:(UITableViewStyle)style {
if ((self = [super initWithStyle:style])) {
self.tableView = [[[UITableView alloc] initWithFrame:self.view.bounds] autorelease];
self.tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth UIViewAutoresizingFlexibleHeight;
self.tableView.delegate = self;
}
return self;
}
Of course, you could also do all of this in a nib file...
Here is how you get the barebones section view up using the UITableViewDelegate methods:
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
UIView *header = [[UIView alloc] initWithFrame:CGRectMake(0, 0, tableView.frame.size.width, 40.0)];
header.backgroundColor = [UIColor grayColor];
UILabel *textLabel = [[UILabel alloc] initWithFrame:header.frame];
textLabel.text = #"Your Section Title";
textLabel.backgroundColor = [UIColor grayColor];
textLabel.textColor = [UIColor whiteColor];
[header addSubview:textLabel];
return header;
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return 40.0;
}
You could try this: In your ProjectDetails.h declare a UIView *tableHeader and also an accessor method - (UIView *)tableHeader;. Then in the implementation file:
- (UIView *)tableHeader {
if (tableHeader)
return tableHeader;
tableHeader = [[UIView alloc] initWithFrame:CGRectMake(0, 0, tableView.bounds.size.width, 30)];
// addlabel
return tableHeader;
}
In viewDidLoad, call: self.tableView.tableHeaderView = [self tableHeader];
I don't believe you'll need to use the heightForHeaderInSection method.

UITableView custom section header appears below the cells

I've a custom section header in my UITableView and I can't figure out why they are appearing bellow the UITableViewCell of the table. See the screenshots:
This is the code that creates the section header:
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
NSString *sectionTitle = [self tableView:tableView titleForHeaderInSection:section];
if (sectionTitle == nil) {
return nil;
}
return [LojaInfoHeaderView lojaInfoHeaderForSection:section withTitle:sectionTitle opened:[self sectionIsOpen:section] andDelegate:self];
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
return [LojaInfoHeaderView viewHeight];
}
And the section's cell are inserted or deleted when the user touches the section header:
- (void)lojaInfoHeader:(LojaInfoHeaderView *)lojaInfoHeader sectionDidOpen:(NSInteger)section {
NSArray *indexPathsToInsert = [self indexPathsForSection:section];
[self setSection:section open:YES];
[_tableView insertRowsAtIndexPaths:indexPathsToInsert withRowAnimation:UITableViewRowAnimationTop];
}
- (void)lojaInfoHeader:(LojaInfoHeaderView *)lojaInfoHeader sectionDidClose:(NSInteger)section {
NSArray *indexPathsToDelete = [self indexPathsForSection:section];
[self setSection:section open:NO];
[_tableView deleteRowsAtIndexPaths:indexPathsToDelete withRowAnimation:UITableViewRowAnimationTop];
}
How can I make the section header appears above the cells? How to fix it?
Update to show how things are created
These are the class methods I'm using:
+ (CGFloat)viewHeight {
return 44.0;
}
+ (LojaInfoHeaderView *)lojaInfoHeaderForSection:(NSInteger)section withTitle:(NSString *)title opened:(BOOL)isOpen andDelegate:(id<LojaInfoHeaderDelegate>)delegate {
LojaInfoHeaderView *newHeader = [[[LojaInfoHeaderView alloc] initWithFrame:CGRectMake(0, 0, 320, 44)] autorelease];
newHeader.section = section;
[newHeader setTitle:title];
newHeader.delegate = delegate;
[newHeader setOpen:isOpen animated:NO];
return newHeader;
}
I found the problem. I was setting the backgroundColor using alpha (yeah, I can't believe I miss this).
Wrong code in initWithFrame:
self.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.1];
Correct code:
self.backgroundColor = [UIColor colorWithRed:0.89 green:0.89 blue:0.89 alpha:1.0];
Try to change your whole table style to be grouped instead of plain. Or change your section view to be opaque. Whatever is the design requirement.

Accordion table cell - How to dynamically expand/contract uitableviewcell?

I am trying create an accordion type of uitableviewcell that, when the user selects the cell, it expands to display a detailed info view inline similar to how the digg app works. I initially tried replacing the current tablecell with a customcell in cellForRowAtIndex, however the animation looks a bit choppy as you can see the cell being replaced and overall the effect doesn't work too well.
If you look at the digg app and others who have done this it seems that they aren't replacing the current cell but instead perhaps adding a subview to the cell? The original cell however doesn't seem to animate at all and only the new view accordions into the table.
Does anyone have any ideas how to accomplish a similar effect?
I have made some progress using neha's method below and while the cell is animating the correct way it is wreaking havoc with the other cells in the table. What I have done is subclassed UITableViewCell with a custom class which contains an instance of a UIView which actually draws the view which I then add to the table cell's contentview.
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
if (selected) {
[self expandCell];
}
}
-(void)expandCell {
self.contentView.frame = CGRectMake(0.0, 0.0, self.contentView.bounds.size.width, 110);
}
Here are all the table delegate methods I am using:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (isSearching && indexPath.row == selectedIndex) {
static NSString *CellIdentifier = #"SearchCell";
CustomTableCell *cell = (CustomTableCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[CustomTableCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
[cell setCustomTitle:[timeZoneNames objectAtIndex:indexPath.row] detail:[timeZoneNames objectAtIndex:indexPath.row]];
UILabel *theText = [[UILabel alloc] initWithFrame:CGRectMake(10.0, 10.0, cell.contentView.bounds.size.width -20, 22.0)];
theText.text = #"Title Text";
[cell.contentView addSubview:theText];
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(10.0, 10 + 46.0, cell.contentView.bounds.size.width - 20, 40.0)];
textField.borderStyle = UITextBorderStyleLine;
[cell.contentView addSubview:textField];
UILabel *testLabel = [[UILabel alloc] initWithFrame:CGRectMake(5.0, 88.0, cell.contentView.bounds.size.width - 20, 22.0)];
testLabel.text = [NSString stringWithFormat:#"Some text here"];
[cell.contentView addSubview:testLabel];
[theText release];
[textField release];
[testLabel release];
return cell;
} else {
static NSString *CellIdentifier = #"Cell";
CustomTableCell *cell = (CustomTableCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[CustomTableCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
[cell setCustomTitle:[timeZoneNames objectAtIndex:indexPath.row] detail:[timeZoneNames objectAtIndex:indexPath.row]];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:NO];
selectedIndex = indexPath.row;
isSearching = YES;
[tableView beginUpdates];
[tableView endUpdates];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if (isSearching && indexPath.row == selectedIndex) {
return 110;
}
return rowHeight;
}
It seems now that the cell is expanding but not actually being refreshed so the labels, and textfield aren't being shown. They do however show up when I scroll the cell off and on the screen.
Any ideas?
The Apple way to do is quite simple.
First, you'll need to save the selected indexPath row:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
self.selectedRowIndex = [indexPath retain];
[tableView beginUpdates];
[tableView endUpdates];
}
I'll explain the begin/end updated part later.
Then, when you have the currently selected index, you can tell the tableView that it should give that row more space.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
//check if the index actually exists
if(selectedRowIndex && indexPath.row == selectedRowIndex.row) {
return 100;
}
return 44;
}
This will return height 100 for the selected cell.
Now we can go back to the begin/end updates. That block triggers the reload of all tableView geometry. Moreover, that block is animated, which eventually gives the impressions of the row expanding.
Pawel's beginUpdates/endUpdates trick is good, and I often use it. But in this case you simply need to reload the rows that are changing state, ensuring that you correctly reload them with the desired cell type, and that you return the correct new cell height.
Here is a complete working implementation of what I think you're trying to accomplish:
.h:
#import <UIKit/UIKit.h>
#interface ExpandingTableViewController : UITableViewController
{
}
#property (retain) NSIndexPath* selectedIndexPath;
#end
.m:
#implementation ExpandingTableViewController
#synthesize selectedIndexPath;
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
return 10;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier1 = #"Cell1";
static NSString *CellIdentifier2 = #"Cell2";
UITableViewCell *cell;
NSIndexPath* indexPathSelected = self.selectedIndexPath;
if ( nil == indexPathSelected || [indexPathSelected compare: indexPath] != NSOrderedSame )
{
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier1];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier1] autorelease];
}
cell.textLabel.text = [NSString stringWithFormat: #"cell %d", indexPath.row];
}
else
{
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier2];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier2] autorelease];
}
cell.textLabel.text = [NSString stringWithFormat: #"cell %d", indexPath.row];
cell.detailTextLabel.text = [NSString stringWithFormat: #"(expanded!)", indexPath.row];
}
return cell;
}
#pragma mark -
#pragma mark Table view delegate
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if ( self.selectedIndexPath != nil && [self.selectedIndexPath compare: indexPath] == NSOrderedSame )
{
return tableView.rowHeight * 2;
}
return tableView.rowHeight;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSArray* toReload = [NSArray arrayWithObjects: indexPath, self.selectedIndexPath, nil];
self.selectedIndexPath = indexPath;
[tableView reloadRowsAtIndexPaths: toReload withRowAnimation: UITableViewRowAnimationMiddle];
}
#pragma mark -
#pragma mark Memory management
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void)viewDidUnload {
}
- (void)dealloc {
[super dealloc];
}
#end
If you don't want to reload the cell (you want to keep your existing cell and just change the size, and likely add/remove some subviews), then simply do the beginUpdates/endUpdates trick in didSelectRowAtIndexPath:, and call some method on your cell to incite the layout change. beginUpdates/endUpdates will prompt the tableView to re-query the heights for each cell - so be sure to return the correct value.
Create a class that subclasses UITableviewcell in your project. Create this class' nib and set its parent to be the class in your project with tableview and override its -
(void)setSelected:(BOOL)selected animated:(BOOL)animated
Write methods contractCell() and expandCell() in this class, and provide the height of the cells you want in expandCell method. Call this methods appropriately based on some flags set to identify wheather the cell is in expanded state or contracted state. Use your tableview's
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
method to handle selection of cells.
Replace your cellForRowAtIndexPath function with this one.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath
*)indexPath {
if (isSearching && indexPath.row == selectedIndex) {
static NSString *CellIdentifier = #"SearchCell";
CustomTableCell *cell = [[[CustomTableCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
[cell setCustomTitle:[timeZoneNames objectAtIndex:indexPath.row] detail:[timeZoneNames objectAtIndex:indexPath.row]];
UILabel *theText = [[UILabel alloc] initWithFrame:CGRectMake(10.0,
10.0, cell.contentView.bounds.size.width
-20, 22.0)];
theText.text = #"Title Text";
[cell.contentView addSubview:theText];
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(10.0, 10 +
46.0, cell.contentView.bounds.size.width - 20, 40.0)];
textField.borderStyle = UITextBorderStyleLine;
[cell.contentView addSubview:textField];
UILabel *testLabel = [[UILabel alloc] initWithFrame:CGRectMake(5.0,
88.0, cell.contentView.bounds.size.width - 20, 22.0)];
testLabel.text = [NSString stringWithFormat:#"Some text here"];
[cell.contentView addSubview:testLabel];
[theText release];
[textField release];
[testLabel release];
return cell;
} else {
static NSString *CellIdentifier = #"Cell";
CustomTableCell *cell = [[[CustomTableCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
[cell setCustomTitle:[timeZoneNames objectAtIndex:indexPath.row] detail:[timeZoneNames objectAtIndex:indexPath.row]];
return cell;
}
}
create array wof dictionary which have a key Select_sts which is 0 in start when click its change 1
accourding u change table
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{
customView = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 40.0)];
UILabel * headerLabel = [[UILabel alloc] initWithFrame:CGRectZero];
headerLabel.backgroundColor = [UIColor clearColor];
headerLabel.opaque = NO;
headerLabel.textColor = [UIColor blackColor];
headerLabel.highlightedTextColor = [UIColor whiteColor];
headerLabel.font = [UIFont boldSystemFontOfSize:16];
headerLabel.frame = CGRectMake(5.0, 10.0, 300.0, 20.0);
headerLabel.text=[NSString stringWithFormat: #"PNR %#",[[record objectAtIndex:section] objectForKey:#"number"]];
customView.backgroundColor=[UIColor whiteColor];
btn_openClose.tag=section+10000;
btn_openClose.backgroundColor=[UIColor clearColor];
// [btn_openClose setImage:[UIImage imageNamed:#"down_arrow.png"] forState:UIControlStateNormal];
[btn_openClose addTarget:self action:#selector(collapseExpandButtonTap:) forControlEvents:UIControlEventTouchUpInside];
[customView addSubview:btn_openClose];
}
- (void) collapseExpandButtonTap:(id) sender{
int indexNo=[sender tag]-10000;
// NSLog(#"total_record %#",[total_record objectAtIndex:indexNo]);
NSMutableDictionary *mutDictionary = [[total_record objectAtIndex:indexNo] mutableCopy];
if([[mutDictionary objectForKey:#"Select_sts"] integerValue]==0)
[mutDictionary setObject:[NSNumber numberWithInt:1] forKey:#"√"];
else
[mutDictionary setObject:[NSNumber numberWithInt:0] forKey:#"Select_sts"];
[total_record replaceObjectAtIndex:indexNo withObject:mutDictionary];
// [table_view beginUpdates];
// [table_view reloadData];
// [table_view endUpdates];
NSMutableIndexSet *indetsetToUpdate = [[NSMutableIndexSet alloc]init];
[indetsetToUpdate addIndex:indexNo]; // [indetsetToUpdate addIndex:<#(NSUInteger)#>]
// You can add multiple indexes(sections) here.
[table_view reloadSections:indetsetToUpdate withRowAnimation:UITableViewRowAnimationFade];
}