Strange UITableViewCell behavior in UIPopoverController - ios

I've got a UIPopoverController created programmatically which pops up with the content from a UIViewController from a .xib. The UIViewController contains a (grouped) UITableView and a UITableViewCell "prototype".
When The popover pops up, the cell prototype is duplicated for all cells needed. The number of cells exceeds the size of the popover, so I can scroll through all cells.
When the popover pops up, everything looks nice, the cell labels are all left aligned. As soon as I touch the tableview to scroll, all cell labels suddenly align to center. When I scroll the cells outside and back in, the are left aligned again. After I scrolled all cells outside for once, they keep left aligned for the rest of their lifetime. I have no idea what is causing this... there is nothing in my code that alters the alignment of the cells. Here's some code:
UIViewController *editPopoverView = [[[ComponentViewEmptyEditPopover alloc] initWithNibName:#"ComponentViewEmptyEditPopover" bundle:nil] autorelease];
UIPopoverController* aPopover = [[UIPopoverController alloc] initWithContentViewController:editPopoverView];
aPopover.delegate = self;
[aPopover presentPopoverFromRect:sender.frame inView:self permittedArrowDirections:UIPopoverArrowDirectionLeft animated:YES];
From the popover viewcontroller
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *theCell = nil;
switch (indexPath.section)
{
case 0:
theCell = [tableView dequeueReusableCellWithIdentifier:#"typeCell"];
if (theCell == nil)
{
NSData *archivedData = [NSKeyedArchiver archivedDataWithRootObject:self.typeCell];
theCell = [NSKeyedUnarchiver unarchiveObjectWithData:archivedData];
}
switch (indexPath.row)
{
case 0:
[theCell.textLabel setText:#"Empty"];
break;
//
}
break;
}
return theCell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 1)
return 420;
return 44;
}
Any ideas why this is happening? I guess this is somehow related to cell reuse.
Update: Like I already guessed, it has to to with the reusing. When I do
theCell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:#"theCell"];
everything works fine. However, I want to be able to change the design of the cell through interface builder...
Update 2: If I comment out the dequeueReusableCellWithIdentifier line, all cells will go back to center alignment after they scroll in.

Related

UITableViewCells get emptied on scroll (objc)

UITableViewCells get emptied on scroll (Objective-C)
I am having a problem with UITableViewCells getting emptied as soon I a start to scroll within the table view.
I already had a look at Cells become empty after scrolling. (Xcode) - however the problem still persists.
1) I have a popover view controller, which presents a way to log into some administration. Upon successful login (which hasn’t been implemented yet, the LOGIN button simply takes one straight to a test tableView - which should be fed from some external database later on).
2) Upon successful login, the login view inside the popover gets removed and a custom UITableViewController comes into play with its own XIB.
3) This UITableViewController uses a custom UITableViewCell - since prototype cells are not possible within this configuration.
It all works to the point where I scroll the table - and all the cells get emptied for some reason.
Here is the code run down (I leave out the obvious, eg properties and table section, etc setups):
1) customPopUpViewController(XIB ,.h, .m):
- (IBAction)loginButtonPressed:(UIButton *)sender {
UITableViewController *libraryTableViewController = [[LibraryAdminTableViewController alloc]initWithNibName:#"LibraryAdminTableViewController" bundle:nil];
libraryTableViewController.view.frame = CGRectMake(0, 179, libraryTableViewController.view.frame.size.width, libraryTableViewController.view.frame.size.height);
[self.view addSubview:libraryTableViewController.view];
}
2) LibraryAdminTableViewController (XIB ,.h, .m):
- (void)viewDidLoad {
[super viewDidLoad];
self.LibraryAdminTable.delegate = self;
self.LibraryAdminTable.dataSource = self;
self.tblContentList = [[NSMutableArray alloc]init];
self.tblContentList = [NSMutableArray arrayWithObjects:#"Sync Pack 1",#"Sync Pack 2",#"Sync Pack 3", nil];
[self.LibraryAdminTable registerNib:[UINib nibWithNibName:#"LibraryAdminTableViewCell" bundle:[NSBundle mainBundle]] forCellReuseIdentifier:#"LibraryAdminCell"];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
LibraryAdminTableViewCell *cell = [self.LibraryAdminTable dequeueReusableCellWithIdentifier:#"LibraryAdminCell" forIndexPath:indexPath];
NSString* trackList = [self.tblContentList objectAtIndex:indexPath.row];
cell.cellLabel.text = trackList;
return cell;
}
3) LibraryAdminTableViewCell (XIB ,.h, .m) - I gave the Identifier in the Attributes Inspector “LibraryAdminCell”:
#property (strong, nonatomic) IBOutlet UILabel *cellLabel;
What am I missing?
It is solved. According to this thread I had to get a strong reference to the custom UITableViewController via a property in the popup controller since the ViewController (being the DataSource for the tableView) would not be retained in memory.
This is happening because you are not creating a new cell, when tableview will try to dequeue a cell, and it does not get the cell, then it should create the cell to use but you are not creating any cell, so it is returning nil.Try the code below
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
LibraryAdminTableViewCell *cell = (LibraryAdminTableViewCell*)[self.LibraryAdminTable dequeueReusableCellWithIdentifier:#"LibraryAdminCell"
forIndexPath:indexPath];
if (cell == nil)
{
cell = [[LibraryAdminTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:#"LibraryAdminCell"];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
NSString* trackList = [self.tblContentList objectAtIndex:indexPath.row];
cell.cellLabel.text = trackList;
return cell;
}

Call ViewController inside UITableViewCell

I have a ViewController wich have a UItableView.
Inside every cell in this TableView I have a subview.
In the first row of my TableView I have a subview that contains 2 buttons.
I want that when one of those buttons are pressed, my UINavigationController pushes my secondViewController on the screen.
But nothing happens, I don't get any errors, just don't happen!
I already try everything I now, but nothing seems to work.
Here is my code at my AppDelegate.m
firstViewController * firstView = [firstViewController new];
UINavigationController * navViewController = [[UINavigationController alloc]initWithRootViewController:firstView];
self.window.rootViewController = navViewController;
In my firstViewController I have my TableView:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString * CellIdentifier = #"Cell";
UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
if (indexPath.section == 0 && indexPath.row == 0) {
[cell.contentView addSubview:_actionBar];
}
else {
for (UIView * view in cell.contentView.subviews) {
[view removeFromSuperview];
}
_feed = [[Y_feedViewController sharedFeed]getViewWithThisInfo:[_arrayOfFeeds objectAtIndex:indexPath.section]];
[cell.contentView addSubview:_feed];
}
return cell;
}
So, the Buttons are in my _actionBar (that I add as a subview in my first row), and when I press the Button01 I want to call my secondViewController
Man, I already try everything, but can't work with this.
I already try to call the pushViewController: from my _actionBar, my TableViewController, my firstViewController, etc.
Thanks.
It's not clear how you are assigning an action to the buttons in _ActionBar. I think it would be easier and cleaner to use two different cell types, one of which has the buttons in it (rather than adding a subview in code). Just dequeue the one you want based on the indexPath. When you dequeue the one for the first row, add the action and target for your buttons (with the target being the view controller).

iOS Place a View on a TableViewCell when cell is in focus

In a VC I have a tableView with custom Cell "ChartListCell". When the user is on any particular cell I want to open a view with 2 buttons in it on top of the cell and let user click on any button and appropriate action be taken for that cell. What would be the best way to implement this feature ? I am stuck at :-
Event to find cell/row is selected.
Place the view at the cells' position - so it stays on top of the cell.
Create the view with 2 btns - would be better to create it programmatically so events can be mentioned in the same VC only or to create a xib would be better option ?
Hide the view again when selection is lost.
UPDATE :-
So I tap the cell, the view (like below with 2 buttons) appears. If I scroll the table, the view stays on the cell. Once I tap an option on the new view , or tap on another cell or somewhere outside it disappears.
UPDATE :-
I created a xib file and in didSelectRowAtIndexPath am trying to show the view, but it's not appearing.
// Get the SELECTED CELL
ChartListCell *cell = (ChartListCell*)[tableView cellForRowAtIndexPath:indexPath];
NSLog(#"ABOUT TO SHOW VOV");
NSArray *visitorOptView = [[NSBundle mainBundle] loadNibNamed:#"VisitorsOptionsView" owner:self options:Nil];
VisitorsOptionsView *vov = [visitorOptView objectAtIndex:0];
vov.frame = cell.frame;
[self.view addSubview:vov];
[self.view bringSubviewToFront:vov];
Nothing appears. Where am I going wrong ? To give the same location as of the cell, I tried vov.frame = cell.frame , but I think I may be wrong at that step. What else should be at that place ???
What would be the best methods to implement the above ? Can you please help me guide out. Any help is highly appreciated.
Below image shows what I am looking to meet up the design :-
I made this demo project for you:http://goo.gl/Y6GFmj , you can download it
You can add the view into your table cell instead of your view. You need to subclass your table view cell and add a property to hold the overlay view.
#interface MyTableViewCell : UITableViewCell
#property (weak, nonatomic) UIView * overlayView;
#end
Note that the overlay view should be a weak property, because the cell's view will have the strong reference to it, just like an IBOutlet.
You need to add another property in your table view controller to hold the last selected index path, so that when you select a new row, you can remove the overlay view in the old one.
#property (strong, nonatomic) NSIndexPath * lastSelectedRow;
Use the following function to remove the overlay view from a cell
- (void)removeViewInCellOfIndexPath:(NSIndexPath *)indexPath
{
if (!indexPath)
return;
MyTableViewCell * cell = (MyTableViewCell *)[self.tableView cellForRowAtIndexPath:indexPath];
if (cell.overlayView)
{
[cell.overlayView removeFromSuperview];
}
}
Now you can deal with the selection:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// deselecte the row
[tableView deselectRowAtIndexPath:indexPath animated:NO];
// remove the overlay view from the last selected row
[self removeViewInCellOfIndexPath:self.lastSelectedRow];
// add overlay view to this row
MyTableViewCell * cell = (MyTableViewCell *)[tableView cellForRowAtIndexPath:indexPath];
// note the origin of the frame is (0, 0) since you are adding itto the cell instead of the table view
UIView * view = [[UIView alloc]initWithFrame:CGRectMake(0, 0, cell.frame.size.width, cell.frame.size.height)];
view.backgroundColor = [UIColor greenColor];
[cell.contentView addSubview:view];
// remember this view and this indexpath
cell.overlayView = view;
self.lastSelectedRow = indexPath;
}
I had done something similar to this, What I did was while creating my custom cell I had placed another view at the bottom which contained the two buttons, make the two buttons as IBOutlets of their classes.
When I load it in my table view with the usual method in CellForROwAtIndexpath I defined as following...
- (UITableViewCell *)couchTableSource:(CBLUITableSource*)source
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *cellid=#"Cell";
CustomTableCell* cell=(CustomTableCell*)[_Mytableview dequeueReusableCellWithIdentifier:cellid];
if(cell==nil)
{
NSArray *nib=[[NSBundle mainBundle] loadNibNamed:#"CustomTableCell" owner:self options:nil];
cell=[nib objectAtIndex:0];
}
[cell.firstButton addTarget:self action:#selector(firstButtonClicked:event:) forControlEvents:UIControlEventTouchUpInside];
[cell.secondButton addTarget:self action:#selector(SecondButtonClicked:event:) forControlEvents:UIControlEventTouchUpInside];
}
I maintained a global integer flag as SelectedIndex and used it as follows
In didSelectRowAtIndexPath I have done something Like this..
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if(selectedIndex == indexPath.row)
{
selectedIndex = -1;
[_Mytableview reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
return;
}
//First we check if a cell is already expanded.
//If it is we want to minimize make sure it is reloaded to minimize it back
if(selectedIndex >= 0)
{
NSIndexPath *previousPath = [NSIndexPath indexPathForRow:selectedIndex inSection:0];
selectedIndex = indexPath.row;
[_Mytableview reloadRowsAtIndexPaths:[NSArray arrayWithObject:previousPath] withRowAnimation:UITableViewRowAnimationFade];
}
//Finally set the selected index to the new selection and reload it to expand
selectedIndex = indexPath.row;
[_Mytableview reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
also and the most important step in heightForRowAtIndexPath
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if(indexPath.row == selectedIndex)
{
return (return the actual size of the cell, Including the view with two buttons);
}
else
{
return (return the size of cell -(the size of view containing the two buttons));
}
}
In viewWillAppear make Sure to assign this so that the cell would be normal whenever the is presented
-(void)viewWillAppear:(BOOL)animated
{
selectedIndex=-1;
[myTableView reloadData];
}

UITableViewCell's Accessory View Button is not displaying in ipad portrait mode

I'm new to ios.Please guide me if you found something wrong. Here is my scenario.
UITableViewCell is showing a label and a button. Button should appears only when the cell is selected. As sometime they both get overlaps if label text is large. So decided to add button as Accessory view. Adding button to UITableViewCell's Accessory View is working in iPhone. Button appears in iPad landscape mode only.Its not showing button in iPad portrait mode. Did I miss something. Is there anyone found something similar.
- (void)tableView:(UITableView *)tview didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tview cellForRowAtIndexPath:indexPath];
cell.accessoryView = joinButton;
}
- (void)tableView:(UITableView *)tView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tView cellForRowAtIndexPath:indexPath];
cell.accessoryView = nil;
}
- (void)viewDidLoad{
NSString *joinLabel = NSLocalizedString(#"Join", #"");
self.joinButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[joinButton setTitle:joinLabel forState:UIControlStateNormal];
/* set join button frame **/
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
if (cell.isSelected) {
cell.accessoryView = joinButton; // No reason to create a new one every time, right?
}
else {
cell.accessoryView = nil;
}
}
It just shows join button in portrait mode only when its already showing in landscape mode and then you change rotation from landscape to portrait. Again clicking on some other cell does not show button on that particular selected cell. Ideally it should show button every time you click on cell in both orientation mode.
Thanks
Are you reloading table view on rotation?
You have done coding for (cell.accessoryView = joinButton;)in didSelectRowAtIndexPath instead do coding in cellForRowAtIndexPath of UITableViewDataSource or in a willDisplayCell of UITableViewDelegate.

Why is my UISearchDisplayController accessing an illegal cell / indexPath?

I have a table view with a search bar. Initially, the table view shows all (10) items. When I select a cell, a detail view is pushed on the navigation controller stack, and I can then go back to the table view by tapping the Back button. As long as I have not entered a search text yet, the table view shows all items, and I can go back and forth between the detail view and the table view indefinitely.
When I enter a text in the search bar, the table view is updated correctly with the self.searchDisplayController.searchResultsTableView (say it only shows 8 items now), that means
(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
is called 8 times (section 0, rows 0 to 7). Fine.
I can then tap a cell, see the detail view, and go back to the table view showing the 8 items.
If I then select a cell in the table view still showing the 8 items (the same cell as before or a different one, does not matter), I again see the detail view, and then tap the "Back" button,
(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
is called for section 0, row 8, which is not existing, since the searchResultsTableView still only shows the 8 items (rows 0 to 7) from the search.
I don't really understand what is going on:
the search works correctly,
but cellForRowAtIndexPath is called with a "wrong" indexPath
EDIT: Removed assumption about mixing up the two table views - everything seems to be in the correct place, but cellForRowAtIndexPath is still called for row 8. Also note that it's ALWAYS row 8.
EDIT 2: Here is the cellForRowAtIndexPath. "Zeichen" is a DAO, the getZeichenForIndexPath:indexPath returns the correct instance from the search result.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"SearchResultCell" ];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"SearchResultCell"];
}
Zeichen *zeichen = [self getZeichenForIndexPath:indexPath];
UIImage *img = [UIImage imageNamed:zeichen.filename];
cell.imageView.image = img;
cell.textLabel.text = [zeichen description];
return cell;
}
I think you should control tableView == self.searchDisplayController.searchResultsTableView. This control should be in didSelectRowAtIndexPath: method as well.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if(tableView == self.searchDisplayController.searchResultsTableView)
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"SearchResultCell" ];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"SearchResultCell"];
}
}
else
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" ];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Cell"];
}
}
return cell;
}
other thought: [tableView dequeueReusableCellWithIdentifier:#"SearchResultCell" forIndexPath:indexPath] usage is more convenient, if you are initialize your table view in storyboard or nib (setting cell identifier in storyboard).

Resources