UICollectionView Frame Wrong With Toolbar - iphone

I have a UICollectionViewController that is part of a Navigation Controller and Tab Bar Controller. At the beginning of the Navigation Controller, I have Interface Builder set to display the Toolbar at the bottom of the View. For the first View Controller of the Navigation Controller, I am using [self.navigationController setToolbarHidden:YES animated:YES]; in order to hide the Toolbar, then in my UICollectionViewController, I use
-(void)viewWillAppear:(BOOL)animated
{
[self.navigationController setToolbarHidden:NO animated:YES];
}
in order to have the Toolbar be displayed. This part works perfectly, my problem comes from the UICollectionViewCell that I have in the UICollectionView. I want it to be the full size of the UICollectionView, and I'm using AutoLayout, so I'm using:
-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
return self.collectionView.frame.size;
}
However, the first time the view is loaded, it returns the wrong value. The first time the view and CollectionView are loaded, that returns the size of the collectionView INCLUDING the height of the Toolbar, which then leads to the warning:
the item height must be less that the height of the UICollectionView
minus the section insets top and bottom values.
And the cell doesn't load. However, when I force a [self.collectionView reloadData]; after the warning, the correct value is returned for self.collectionView.frame.size and the cell loads.
I'm really frustrated at this and would greatly appreciate any help that anyone can offer.
Edit:
After reading Mundi's comment, I ended up changing some of my code to:
-(void)viewWillAppear:(BOOL)animated
{
[self.navigationController setToolbarHidden:NO animated:YES];
[self.collectionView reloadData];
}
And the issue was solved. However, now I have a new but related problem. When I add [self.collectionView scrollToItemAtIndexPath:selectedIndexPath atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:NO]; (selectedIndexPath is pushed from the first view controller) to viewWillAppear, I get the same warning about the size of the UICollectionView item. If I have my code like this:
-(void)viewWillAppear:(BOOL)animated
{
[self.navigationController setToolbarHidden:NO animated:YES];
[self.collectionView scrollToItemAtIndexPath:selectedIndexPath atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:NO];
[self.collectionView reloadData];
}
I don't get that size warning, but my collectionView always starts at index 0 rather than selectedIndexPath. If I change around the ordering to this:
-(void)viewWillAppear:(BOOL)animated
{
[self.navigationController setToolbarHidden:NO animated:YES];
[self.collectionView reloadData];
[self.collectionView scrollToItemAtIndexPath:selectedIndexPath atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:NO];
}
I get that size warning, and the cell doesn't load until I invoke a method to call reloadData. However, it does start at the correct indexPath.

This problem is really about dealing with the view lifecycle. In viewWillAppear all the subviews are already laid out, so maybe you are hiding the toolbar too late.
Your solution to call reloadData after showing the toolbar is not so bad as all this happens before the view appears. It is logical - the geometry has changed and you have to recalculate the layout.
Try experimenting with the view controller's hidesBottomBarWhenPushed property. Maybe that takes care of this problem without having to code anything.

Related

UITableView not pushing the Detail View!

losing sleep over this issue
My app hierarchy is ListVC1-->ListVC2-->DetailVC. [Working perfect]
and... SearchListVC-->DetailVC (the same DetailVC as above) [Issue is in this model]
The code in SearchListVC is almost same as ListVC2, with a difference that it contains a SearchBar, instead of a navigationBar, on top.
Also, please note that I am able to present the DetailVC as a ModalView, it is push that is not happening... the cell remains highlighted.
Here is the didselectrow code
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
// Navigation logic may go here. Create and push another view controller.
if (indexPath.row<[smses count]) {
WebSMSDetailViewController *detailViewController = [[WebSMSDetailViewController alloc] initWithNibName:#"WebSMSDetailViewController" bundle:nil];
[self.navigationController pushViewController:detailViewController animated:YES];
detailViewController.smsList = allWebSMSes;
detailViewController.smsIndex = indexPath.row;
[detailViewController populateDetails];
[detailViewController release];
}
else {
if (indexPath.row<totalSMSes) {
pageNumber++;
[self loadNotes];
}
}}
I think the problem is somewhere else.
I have been googling for quite a while but couldn't understand the solutions posted, so please be a little descriptive... beginner here!
I suppose the problem is that, you dont have a navigation controller in the SearchListVC.
Like you wrote,
it contains a SearchBar, instead of a navigationBar, on top
Use a navigation controller with the SearchListVC and I think your problem is solved.
Cheers
You just create/use #property for the navigationBar
or u have to place the Navigationbar on the top of the view and place your search bar on the bottom of the navigationBar

setContentOffset only works if animated is set to YES

I have a UITableView which I would like to be displayed 100px down. For some reason this only works when animated is set to YES. Why is this?
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
/*[self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:0]
atScrollPosition:UITableViewScrollPositionNone
animated:NO];*/
/*[self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathWithIndex:1]
atScrollPosition:UITableViewScrollPositionNone
animated:NO];*/
[self.tableView setContentOffset:CGPointMake(0,100) animated:YES];
}
What if you try to use setFrame instead of setContentOffset?
You should add this code in your viewDidAppear method:
[self.tableView setFrame:CGRectMake(0, 100, 320, 380)];
Depending on the other elements you have in your view (e.g. navigation controller, tool bar etc.) you will have to adjust the 380 to something else.
Using the base Navigation-based Application that XCode supplies and giving it some table cells, it works fine with what you've given. Have you tried setting the content offset within viewDidAppear rather than viewWillAppear?
Move the "setContentOffset" to "viewDidLoad" and add "reloadData" before that:
In Swift:
func viewDidLoad() {
super.viewDidLoad()
tableView.reloadData() // important for scrolling to be possible
tableView.setContentOffset(newContentOffset), animated: false)
}

Strange UIKit bug, table view row stays selected

I'm facing what appears to be a UIKit bug, and it takes the combination of two less commonly used features to reproduce it, so please bear with me here.
I have quite the common view hierarchy:
UITabBarController -> UINavigationController -> UITableViewController
and the table view controller pushes another table view controller onto the navigation controller's stack when a row is selected. There's absolutely nothing special or fancy in the code here.
However, the second UITableViewController, the "detail view controller" if you will, does two things:
It sets hidesBottomBarWhenPushed to YES in its init method, so the tab bar is hidden when this controller is pushed:
- (id)initWithStyle:(UITableViewStyle)style {
if(self = [super initWithStyle:style]) {
self.hidesBottomBarWhenPushed = YES;
}
return self;
}
It calls setToolbarHidden:NO animated:YES and setToolbarHidden:YES animated:YES on self.navigationController in viewWillAppear: and viewWillDisappear: respectively, causing the UIToolbar provided by UINavigationController to be displayed and hidden with animations:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self.navigationController setToolbarHidden:NO animated:YES];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[self.navigationController setToolbarHidden:YES animated:YES];
}
Now, if the second UITableViewController was pushed by selecting the row at the bottom of the screen (it doesn't have to be the last row) in the first controller, this row does not automatically get deselected when the user immediately or eventually returns to the first controller.
Further, the row cannot be deselected by calling deselectRowAtIndexPath:animated: on self.tableView in viewWillAppear: or viewDidAppear: in the first controller.
I'm guessing this is a bug in UITableViewController's drawing code which of course only draws visible rows, but unfortunately fails to determine correctly if the bottommost row will be visible in this case.
I failed to find anything on this on Google or OpenRadar, and was wondering if anyone else on SO had this problem or knew a solution/workaround.
I had this same exact problem, (though I am not using a toolbar). My solution was to deselect the row in didSelectRowAtIndexPath after pushing my second view controller.
- (void)tableView:(UITableView *)aTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
RunViewController *runViewController = [[RunViewController alloc] initWithNibName:#"RunViewController" bundle:nil];
runViewController.managedObjectContext = self.managedObjectContext;
runViewController.hidesBottomBarWhenPushed = YES;
[self.navigationController pushViewController:runViewController animated:YES];
[runViewController release];
//deslect "stuck" row
[aTableView deselectRowAtIndexPath:indexPath animated:YES];
}
If I remember well I think I had same/similar problem once, but my solution was rather rough:
- (UITableViewCell*)tableView:(UITableView*)tableView
cellForRowAtIndexPath:(NSIndexPath*)indexPath {
// ...
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}

UITableView doesn't remember its scroll position

I can post code, though I'm not quite sure where to start. I have a UITableView with custom cells, in the middle tier of a three-level UINavigationView scheme. When I drill down to the bottom level and see details about my data, then use the top-left back button, my table view comes back scrolled all the way to the top, rather than scrolled down to where it was when I last saw it. Where should I look about this?
EDIT:
Here's the code in the EventsTableViewController to load an instance of EventsDetailViewController and push it on the navigation controller:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSMutableArray *events = [DataManager sharedDataManager].eventList;
Event *selectedEvent = [events objectAtIndex:[indexPath row]];
EventsDetailViewController *detailController = [[EventsDetailViewController alloc] initWithNibName:#"EventsDetailView" bundle:nil];
[detailController loadEvent:selectedEvent];
MyAppDelegate *del = (MyAppDelegate *)[UIApplication sharedApplication].delegate;
[del.navigationController pushViewController:detailController animated:YES];
[detailController release];
}
There's nothing in my EventsTableViewController about reloading the table, as far as I can see--I haven't implemented viewWillAppear or viewDidLoad or any of those.
Are you by any chance reloading the table where you shouldn't be? In the ViewWillAppear method for example?
I was accidentally instantiating a new copy of my table view whenever I hit this level of the navigation. That's all fixed now and this isn't a problem anymore.
I have a very similar question. When I go to the chatView, which is a UIViewController belonging to the navigationController and has a tableView as a subview, and then I scroll to some point, and then I go back, and then I go back to the chatView, it starts at the top again. I am allocing the tableView in loadView of the chatView, so the tableView gets realloced everytime I come back. But, isn't this standard? How do I just always scroll to the bottom like the iPhone Messages app and show the scroll bar for a few seconds at the bottom?
Here's the code:
http://github.com/acani/acani-chat/blob/master/Lovers2/Classes/ChatViewController.m#L184
Thanks!
Matt
are you doing:
[self presentViewController:navController animated:YES completion:nil];
where self is tableviewcontroller? give this a try:
[self.navigationController presentViewController:navController animated:YES completion:nil];

Can't get my detail view to show

I have a tabbed bar main window with four tabs, one of which is a list. This list is empty at first but when I click a "+" I am presented with a modal view of available options like this
- (IBAction)addThing:(id)sender {
MJAvailableThingsViewController *controller = [self availableThingsViewController];
[self presentModalViewController:availableThingsViewController animated:YES];
[controller setEditing:YES animated:NO];
}
This works.
The list of things has a UITableViewCellAccessoryDetailDisclosureButton on each row. This was done with the accessoryTypeForRowWithIndexPath. This works as well.
When I click the little blue button in this view the delegate accessoryButtonTappedForRowWithIndexPath is called. This works.
However, in accessoryButtonTappedForRowWithIndexPath I want to present a detail view of the thing and this is where I encounter problems:
The delegate looks like this:
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath;
{
NSLog(#"accessoryButtonTappedForRowWithIndexPath");
NSLog(#"Tapped row %d", [indexPath row]);
[[self navigationController] pushViewController:thingDetailViewController animated:YES];
The program enters this code but nothing happens, that is I get the NSLog output but no new window. I am very new at this so please forgive me if this is obvious; to me it is, however, not... :-)
Do you have a navigationController? It sounds like you have a TabController but not a NavigationController.
Check [self navigationController], is it set to anything?
Here's a similar question:
Tab Bar Application With Navigation Controller