Resizing a presenting view on rotate - ios

I'm having a problem handling rotation in a view controller.
When the view is topmost and the phone is rotated, it adapts correctly.
When there's a view controller being presented modally over it and the device is rotated, the view controller under is not fully updated for the rotation when the user returns. The biggest problem I appear to be having is that the separator lines don't expand to fill the whole width.
Example:
I've uploaded my test project to GitHub; you can clone it from https://github.com/tewha/ResizeOnRotate.git.
I have no code handling rotation at all. My understanding was that this was supposed to be fully automatic. What am I missing to make this work correctly?
Edit:
Inspired by the answer below, a simple workaround:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
UITableViewCellSeparatorStyle separatorStyle = self.tableView.separatorStyle;
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
self.tableView.separatorStyle = separatorStyle;
}

I think this may be an Apple bug. You can reproduce it in their own app "Mail".
Steps to reproduce in "Mail" app -
Open Inbox of messages in "Mail" app. (say, in Portrait orientation)
Tap compose message icon (bottom right) and rotate the device (in landscape).
Close the compose message and see the inbox messages view now.
Result: The separator lines are broken.
Workaround for user: Scroll down and up in message inbox (leads to display refresh).
Reproducible up to iOS 7.0.2.
Edit
(Code workaround - 1)
If possible, you could reloadData to refresh the tableview when it appears.
- (void)viewWillAppear:(BOOL)animated
{
[self.tableView reloadData];
}
Code workaround - 2 (reload only the visible cells)
- (void)viewWillAppear:(BOOL)animated
{
NSArray *refreshCells = [self.tableView indexPathsForVisibleRows];
[self.tableView reloadRowsAtIndexPaths:refreshCells withRowAnimation:UITableViewRowAnimationNone];
}

Related

Orientation not updating after pop segue

My setup
I have a UICollectionViewController which displays 2 columns in Portrait and 3 Columns in Landscape, Like So :
. . . .
I am using this code to trigger a layout refresh on rotation :
- (void)updateViewConstraints
{
[super updateViewConstraints];
[[self.collectionView collectionViewLayout] invalidateLayout];
}
Everything is working fine, But...
The issue
1. I am viewing the collectionView in Portrait :
Everythings fine.
2. I click on one of the cells to go to a detail view, which also supports both orientations. Then on the detail view, I switch the orientation to landscape. Still good.
3. Still in Landscape, I now tap < back to come back to the collectionView, and then this is what I see :
OOPS!
I have absolutely no idea what is the cause of this. Searching on SO and Google didn't turn up anything.
What I've Tried
I tried implementing this method in the collectionVC.m file :
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
[super blahblah];
[[self.collectionView collectionViewLayout] invalidateLayout];
}
Although it gets called when even I am on the detailView, it doesn't solve the issue.
Notes :
I am not implementing any of those should/will/did methods related to orientation except the two I posted above.
One thing I noticed is that the collectionView is switching to a 2 column layout nd all. It seems like its the view bounds that is getting mixed up.
Sorry for the long post. Here's a potato.
So Any thoughts on what is going wrong??
Update : I grabbed a screenshot of the UI hierarchy, might help.
The problem you are facing is the rotation did happen when the collection viewController is not the visible one. so both updateViewConstraints and viewWillTransitionToSize:withTransitionCoordinator: will not get called.
There is two possible solutations for this probelm.
You can observe the the change of orientation
// in viewDidLoad
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(orientationDidChange:) name:UIDeviceOrientationDidChangeNotification object:nil];
- (void)orientationDidChange:(NSNotification *)notification
{
//TODO: resetup the layout itemSize, etc if your it depend on the collection bounds.
// and make sure to do that after the rotation did happend(i.e in viewWillAppear or orientationDidChange:)
[[self.collectionView collectionViewLayout] invalidateLayout];
}
you can invalidate the layout in viewWillAppear anyway
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
//TODO: resetup the layout itemSize, etc if your it depend on the collection bounds.
// and make sure to do that after the rotation did happend(i.e in viewWillAppear or orientationDidChange:)
[[self.collectionView collectionViewLayout] invalidateLayout];
}
Thanks to Ismail's Answer, which set me on the right path and I figured it out finally:
Upon careful observation of the code, I made some observations :
Firstly, the UICollectionViewController is properly adjusting to the rotation, it's viewWillTransitionToSize: and updateViewConstraints are getting called right on cue. The 3 column/2 column switch is also happening properly and all the required datasource methods are getting called.
So Its not the CollectionViewController
Then I took a closer look at the view hierarchy (Image link at the end of my question).
Interestingly, the tabBar Controller still thinks its in portrait while everything above and below it has switched to landscape. The tab bar and all is still at portrait width.
So I just added this in the CollectionViewController's viewDidAppear method :
-(void) viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self.tabBarController.view setNeedsDisplay];
}
Even Better, I subclassed the TabBar controller and added this:
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
[self.view setNeedsLayout];
}
And that did the trick!
I still have no idea why this is happening. So I will be investing and will update my answer when I find out more.

UICollectionView UIRefreshControl Doesn't Animate After Visiting a Different View

I have a UIRefreshControl connected to a UICollection that is defined this way for pull to refresh:
self.refreshControl = [[UIRefreshControl alloc] init];
[self.refreshControl addTarget:self action:#selector(startRefresh:)
self.collectionView.alwaysBounceVertical = YES;
[self.collectionView addSubview:self.refreshControl];
This works fine. However, whenever I move to a new view by either pushing a new view controller or displaying the sliding sidebar menu, and return to this view, the refresh control starts displaying the image for a control pulled all the way (i.e. it doesn't animate and shows the full circle). However, if I pull down fully and release, the refresh control returns to normal functionality. The control works fine, it just looks funky the first time you pull after navigating elsewhere.
I would love any feedback on what might be going wrong. Thanks!
This is what the image looks like when not working (note I am linking to an online image, this is not from my app so this doesn't show that the collectionview is being pulled down):
Posted solution below worked, but I had to do some extra work to figure out when my top view controller received focus from the sidebar menu that I was using (ECSlidingViewController): Is there a way for the Top View Controller in ECSlidingViewController to know when the sidebar menu has been dismissed?
After completed loading You have to stop the refreshing
[tableView.refreshControl endRefreshing]
Hope its useful for you..:)
I had a slightly different issue but the symptoms were similar. This is what worked for me:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
_refreshControl.hidden = YES;
}
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
if (_refreshControl.isRefreshing) {
[self.collectionView sendSubviewToBack:_refreshControl];
}
}

UISearchbar vanishes when in UIScrollView

I seem to be having an issue with the UISearchbar in iOS 7 vanishing in two scenarios. First the controller is fairly simple it has a nib which contains a scrollview which has in it the uisearch bar and some content. The ui search bar is at the top of the scrollview. So when I scroll the scrollview so the uisearchbar is longer visible and I exit and reneter the controller the uisearch bar is longer visible. Clicking the region makes it appear again. The uisearchbar also vanishes when I double tap it quickly. This controller worked fine is iOS 6 these issues are only happening now that I am building for ios 7
Edit
Investigating the double tap issue causing the uisearchbar to disappear. It seems that the uisearch bar when double tapped quickly is removing the uisearchbar from the view hierarchy when displaying it but never readding it back when it has been dismissed. So I can workaround that by doing
- (void)searchDisplayControllerDidEndSearch:(UISearchDisplayController *)controller
{
// workaround for bug in ios 7 were quickly double tapping uisearchbar (e.g it appears and get dismissed quickly)
// does not re add the uisearch bar to the correct view.
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"7.0")) {
UIView *parentView = [self.scrollView.subviews objectAtIndex:0];
[parentView addSubview:self.searchDisplayController.searchBar];
}
return;
}
Have you tried doing some UI refresh stuff?
Like:
- (void)viewWillAppear:(BOOL)animated{
[self.scrollView setNeedsLayout];
}

iOS 7 XCode 5.0 IBAction not called

I have an application developed in iOS4 using XiBs. I got it working all good with iOS6.1 and earlier. But for some buttons, IBAction is not getting called if it is iPhone and iOS 7.0. Also it is working fine with iPad and iOS 7.0. Of course, I am using different Xibs for iPhone and iPad.
Here is the code. It is pretty basic. But just not getting into it.
- (IBAction) didReceiveMapButtonPress {
NSLog(#"IN DID RECEIVE MAP BUTTON PRESS");
if ([self wasReferredFromMap]) {
[[self navigationController] popViewControllerAnimated:YES];
} else {
[self pushMapViewController];
}
}
Many of the developer used custom view to show custom cell on Table view for older version of iOS. If you are one of them, then you will have to face a problem that your button click action will no longer work with iOS7.
How to resolve this:
You have three options:
Option 1: Create the new lay out with new table cell instead of taking view. and put all layouts again in table cell.
I know, this will require a lot of effort.If you don't want to do this, we have a very small hack for it:option 2
Option 2: Create a IBOutlet for your button and add this button as a subview of your cell's content view.
[self.myCell.contentView addSubview:self.btn_click];
The above line of code will add btn_click as a subview of you content view. Now button click action should work.
Option 3:
The best way :
i) Take An outlet UITableViewCell.
ii) Make existing view as subview of new table cell.
iii) Disconnect the connection of custom cell to existing view and connect it to new UITableViewCell.
thats it, Your IBAction will work now.
May be you got the crash with error message that "class is not key value coding - compliant.". Check your old view connection and remove all connection having yellow mark.
When I faced with this problem, I had tons of cells from xibs. That's way I've create the category for UITableViewCell
#implementation UITableViewCell (customs)
- (void)awakeFromNib {
[super awakeFromNib];
[self reAddSubviews];
}
- (void)reAddSubviews {
for (UIView * o_vw in [[[self subviews] objectAtIndex:0] subviews]) {
if (o_vw != self.contentView) {
[o_vw removeFromSuperview];
[self.contentView addSubview:o_vw];
}
}
}
#end
Please make sure the TCell.xib for your UITableViewCell is correct.
Double check if this xib file has "Content view". If you can not see this item, that means your view is not a UITableViewCell, it probably is a UIView.
The correct method is to recreate this XIB file. you can do it like this:
NewFile(User Interface)--->Empty--->Device Family(iphone)--->Save as TCell.xib.
add UITableViewCell
copy your subview from your previous xib file to this view and connect the outlets. http://i.stack.imgur.com/WB4j3.png

UISearchDisplayController change dimmed view frame

In my iPad app I have an UITableView. Table's frame size is less than screen size, so to make search functionality look nice I have to adjust searchResultTableView's frame to fit my TableView. I'm doing it in my UISearchDisplayDelegate's -searchDisplayController:willShowSearchResultsTableView: method.
Everything works fine except dimming view. When I'm starting search dimming view's width is equal to screen width:
When I start entering search string or clear textfield my searchResultsTableView resizes properly and everything works as it should:
I tried to change searchResultsTableView frame inside -searchDisplayControllerWillBeginSearch: method using this line
controller.searchResultsTableView.frame = myFrame;
but it doesn't work as well. Any suggestions besides implementing my own search display controller?
I also needed to change the frame of the dimming view but for a different reason. In my case I created a UISearchDisplayController and UISearchBar programmatically in a regular UIViewController not a UITableViewController. I was also using MFSideMenu which added to the complexity of the problem. What ended up happening was the dimming view was in the correct position initially but the next time the search was cleared the dimming view shifted leftwards and upwards by exactly half of it's size. Given the UISearchDisplayController you can find the dimming view like so.
for(UIView * v in controller.searchContentsController.view.subviews)
{
if([v isMemberOfClass:[UIControl class]])
{
v.frame = newFrame; //This frame should account for the UISearchBar
}
}
To handle for the initial incorrect frame you should change it in this delegate method:
- (void) searchDisplayController:(UISearchDisplayController *)controller didShowSearchResultsTableView:(UITableView *)tableView;
To handle for an incorrect frame on any subsequent clears you should change it in this delegate method:
- (void) searchDisplayController:(UISearchDisplayController *)controller didHideSearchResultsTableView:(UITableView *)tableView;
Note: this solution runs through the subviews of the searchContentsController which is one of the reasons I used isMemberOfClass instead of isKindOfClass (UIButton is a subclass of UIControl). Further discrimination would be required if you added a UIControl instance into your view (you could use tags to help determine which ones are yours).

Resources