UINavigationBar to a higher xib layer index - objective-c

Similar to how z-index works in HTML, I want to make my UINavigationBar be on the highest layer so that everything in my scroll view goes underneath it.
I currently just have a xib with a UINavigationBar located at the top with a UIScrollView below it vertically that has Bounce Vertically checked. When you slide the scroll view the content from the scroll view will appear to be above the UINavigationBar and covers it.

You can set the zPosition of navigationBar to the topmost layer as below
navigationController.navigationBar.layer.zPosition =[[self.view subviews] count];

If you use a UIViewController I would suggest using this code :
self.navigationController.navigationBarHidden = false;
But if you are using a plain UIView I will refer you to the UIView documentation http://developer.apple.com/library/ios/#DOCUMENTATION/UIKit/Reference/UIView_Class/UIView/UIView.html#//apple_ref/doc/c_ref/UIView
Look for the #property(nonatomic, readonly, copy) NSArray *subviews and other subviews related method.
You can order your view relative to each other with those method.

Related

Embed ImageView in ScrollView with Auto Layout on iOS 6

I am trying to make very simple element with new iOS 6 SDK with auto layout.
I have an ImageView and Embed it in ScrollView. (everything build with Interface Builder). The .png file is set and imageView mode is set to "Top Left".
Implementation:
#import "ImaginariumViewController.h"
#interface ImaginariumViewController ()
#property (weak, nonatomic) IBOutlet UIScrollView *scrollView;
#property (weak, nonatomic) IBOutlet UIImageView *imageView;
#end
#implementation ImaginariumViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.scrollView.contentSize = self.imageView.image.size;
self.imageView.frame =
CGRectMake(0, 0, self.imageView.image.size.width, self.imageView.image.size.height);
}
#end
When I run the app, the image is not scrolled. Doing all the same with auto layout turned off (with struts and springs), I have working scrolling.
I guess the problem is with constraints. Could anybody help me, please?
I just encountered the same issue in a tutorial that I was updating. I attempted programmatically deleting constraints, cursing, and banging my head against the wall - no luck.
About 5 minutes ago, however, I tried something that had fixed another issue I encountered, and, ta da! UIScrollView is working again! The solution was to move the old code that sets the UIScrollView contentSize property into an implementation of viewDidAppear, rather than viewDidLoad:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
self.theScroller.contentSize=CGSizeMake(200.0,2000.0);
}
I hope this helps someone else encountering some of the headaches that have appeared with Auto Layout.
Autolayout can be very confusing at first. You actually don't want to set the contentSize of the scrollview anywhere. With a pure autolayout approach the scrollview sets its own content size. See the section on autolayout and UIScrollView in the iOS 6 release notes:
The constraints on the subviews of the scroll view must result in a
size to fill, which is then interpreted as the content size of the
scroll view. (This should not be confused with the
intrinsicContentSize method used for Auto Layout.)
Note that this means that the constraints on the subviews of the scrollview must set explicit widths and heights and not use widths that vary based on aspects of the scrollview.
The second error here is that you set the frame of the UIImageView to the size of the image. With autolayout this is also unnecessary. The UIImageView actually has an intrinsicContentSize which is the size of the underlying image. (To change this you should set constraints for width and height with a high priority) That means that with auto layout to place an image in a scrollview and have it scroll the correct code should be the following:
** nothing at all!!! **
But theres still something you need to watch out for that could cause you to have an image that appears not to scroll and the hint is in the aforelinked release notes:
Note that you can make a subview of the scroll view appear to float
(not scroll) over the other scrolling content by creating constraints
between the view and a view outside the scroll view’s subtree, such as
the scroll view’s superview.
i.e. if you set constraints in interface builder and constrain the image view to a view above the scrollview in the hierarchy it will affect how the view appears to scroll. Mad!
Happy Coding...

How to show a UIView OVER a UIPopoverController

In my app, I have my main view and when i click a button, a UIPopoverController is shown over my main view (not fullscreen so i still see the view behind) containing a UITableView. When I click one of the tableview cells, I want to show a custom view centered on screen (simple view informing the user that the app is processing) that will fade in and fade out during a specific amount of time.
The problem is that my custom view always appears UNDER the UIPopover...I tried all I can think of, bringSubviewToFront etc...Nothing works... I also tried to wrap my custom view in a UIViewController and use [mainView presentViewController:myCustomView ...] but when I do that the main view disappear
Someone can help?
Thx
Thx Ole Begemann, this question was indeed a duplicate.
Although, the solution to my problem is not to subclass UIWindow but to add my UIView to the key UIWindow :
NSArray * windows = [[UIApplication sharedApplication] windows];
UIWindow* win0 = [windows objectAtIndex:0];
[win0 addSubview:loadingView];
[win0 bringSubviewToFront:loadingWindow];

Putting a custom view into a UITableView

I have a regular-style UITableView—the one that has a white background and gray horizontal lines to separate the rows.
I have another custom UIView that is just a 100x100 rectangle filled with redColor.
How can I put the latter into the former, such that it appears over the horizontal lines, but is still a “part” of the table view in the sense that when I scroll the table view around, the red view scrolls with it? In fact, I should also be able to put my finger on the red area and scroll the table view.
Once again, if the red view is placed to overlap some horizontal lines, it should appear over the lines. Sadly, when I just add the red view as a subview to the table view, the horizontal lines go over the red view; see this screenshot.
How can this be accomplished?
The correct place to handle the stacking order of your red square is in the layoutSubviews method. The table view sends itself layoutSubviews any time it adds or removes subviews (and at other times).
You need to make a subclass of UITableView that has a reference to the red square:
#interface MyTableView : UITableView
#property (weak, readonly) IBOutlet UIView *redSquare;
#end
You can initialize redSquare in whatever way you want. I just put it in my nib along with the table view, and moved it to be a subview of the table view in awakeFromNib:
#implementation MyTableView
#synthesize redSquare = _redSquare;
- (void)awakeFromNib {
[self addSubview:self.redSquare];
}
Anyway, to actually make sure the red square is always on top of the table cells and grid lines, override layoutSubviews like this:
- (void)layoutSubviews {
[super layoutSubviews];
[self bringSubviewToFront:self.redSquare];
}
EDIT
If you are trying to add the view a above the lines (hide the lines) try to use – bringSubviewToFront: to take it to the front of the table view.
[self.tableView bringSubviewToFront:redView];
ELSE
Add the view to the self.tableView.tableHeaderView this will place it above the table view and will scroll with the table view.
UIView *redView = [[UIView alloc]init];
redView.frame = //set the frame
redView.backgroundColor = [UIColor redColor];
self.tableView.tableHeaderView = redView;
Good Luck
Just add this view to UITableView as subview:
[tableView addSubview:myRedView];
See userInteractionEnabled property in order to handle interaction and scrolling.
Make your view a subview of any normal subview of the UITableView: a header, a footer or any UITableViewCell.
I think what you've described can best be achieved using a UITableViewCell or even a subview of the header. A cell has the inherent ability to scroll the table and can be customized any way you like it. It's essentially a view.
In your situation, for example, you may want the red box to appear by default at the top of the table. You would make the first cell a 'red box' cell, where you would insert your red box into the cell's content view.
So, your problem is basically, that the UITableViewCells of a UITableView are added as Subviews dynamically, and you cannot control wether they are added in front of or behind your view.
So to keep your view at the front, you need to get it back there every time cells may be added, which occurs when the UITableView scrolls.
I would suggest you try adding your custom view as a subview and then override -scrollViewDidScroll like so:
- (void)scrollViewDidScroll {
[super scrollViewDidScroll];
// myCustomView is your custom view referenced in an IVar
[self.tableView bringSubviewToFront:myCustomView];
}
Edit your viewWillAppear delegate with these lines
UIView *redView=[[UIView alloc]initWithFrame:CGRectMake(30,30, 100, 100)];
redView.backgroundColor=[UIColor redColor];
[self.tableView addSubview:redView];

How to access subviews in nested UIScrollViews

I was having trouble getting a UIScrollView with multiple UIImageView subviews to zoom properly so I tried using a UIScrollView with multiple UIScrollView subviews inside of it and a UIImageView inside of each of those. That way one UIScrollView can only scroll and the other can only zoom.
My question is: How can I access subviews of a subview. I know that normally I can access subviews using [scrollView viewWithTag:tagInt]; for example, but I can't seem to access the subviews of a subview using [[scrollView viewWithTag:tagInt] viewWithTag:tagInt2]; since viewWithTag only returns a single UIView and not all of it's subviews.
I could always give each subview a unique tag and access them that way, but that doesn't seem to be the most elegant solution.
What is the best way to access a subView and then get to the subView's subview (ie: access my UIScrollView used for zooming which is a subview of my main view, and then access it's subView UIImageView)?
If you don't feel comfortable subclassing for now, you'd have to assign tags to the UIScrollViews containing images. You'd then have to do what the BobC suggested with a little more work.
for (UIView *subview in [myScrollView subviews])
{
//check if the current subview is one of the UIScrollViews
if (subview.tag > 100)
//do something with the UIScrollView
}
The most elegant way to do this would be to subclass UIScrollView, give it a UIImageView property. That way, you could access this UIImageView with something like:
MyScrollView *myScrollView = (MyScrollView *)[scrollView viewWithTag:tagInt];
UIImageView *imageView = myScrollView.imageView;
Hope this helps!
You can get an array of subviews of any UIView using subviews property.
for(UIView *subview in [myScrollView subviews]) {
// do anything with your subview here.
}

Adding a UINavigationController as a subview of UIView

I'm trying to display a UILabel on top of a UINavigationController. The problem is that when I add the UILabel as a subview of UIWindow it will not automatically rotate since it is not a subview of UIViewController (UIViewController automatically handles updating subviews during rotations).
This is the hierarchy I was using:
UIWindow
UILabel
UINavigationController
So I was thinking I could use the following hierarchy:
UIWindow
UIViewController
UIView
UILabel
UINavigationController
This way the label could be displayed on top of the UINavigationController's bar while also automatically being rotated since it is a subview of UIViewController.
The problem is that when I try adding a UINavigationController as a subview of a view:
[myViewController.view addSubview:myNavigationController.view];
it will appear 20 pixels downwards. Which I'm guessing is because it thinks it needs to make room for the status bar. But, since the UINavigationController is being placed inside a UIView which does not overlay on top of the status bar, it is incorrectly adding an additional 20 pixels. In other words, the top of the UINavigationBar is at the screen's 40 pixel mark instead of at 20 pixels.
Is there any easy way to just shift the UINavigationController and all of its elements (e.g. navigation bar, tool bar, root view controller) up 20 pixels? Or to let it know that it shouldn't compensate for a status bar?
If not, I guess I would need to use my first hierarchy mentioned above and figure out how to rotate the label so it is consistent with the navigation bar's rotation. Where can I find more information on how to do this?
Note: by "displaying a label on top of the navigation bar", I mean it should overlay on top of the navigation bar... it can't simply be wrapped in a bar button item and placed as one of the items of the navigation bar.
Using this code seems to work:
nav.view.frame = CGRectMake(nav.view.frame.origin.x, nav.view.frame.origin.y - 20,
nav.view.frame.size.width, nav.view.frame.size.height);
I did this before adding the navigation controller as a subview. Using the [UIApplication sharedApplication].statusBarFrame instead of the hard coded 20 would probably be a good idea too.
I'm not sure if it's the best way to do it though.
If you want a frame representing the available content area, then you should just use: [[UIScreen mainScreen] applicationFrame]. Of course, this restricts your top-level view controller so that it can only be top level. So still kind of dodgy, but less so.
Why don't you use App Frame instead of adding some values to origins? I mean using:
CGRect appFrame = [[UIScreen mainScreen] applicationFrame];
as a reference frame, and do something like this:
nav.view.frame = CGRectMake(appFrame.origin.x, appFrame.origin.y, ...
This one worked for me.
I had this same problem actually but managed to fix it.
I noticed that my view controller's view had the correct frame, but the view controller's navigation bar did not (it had a frame origin of (0,20) ).
Insert this into the view's controller that is the superview of the navigation controller:
- (void) viewDidAppear:(BOOL)animated {
if (navigationController.navigationBar.frame.origin.y != 0) {
[[navigationController view] removeFromSuperview];
[[self view] addSubview:navigationController.view];
}
}
Swift 5:
add the following line in the viewDidLoad() of the root view controller of the UINavigationController.
self.edgesForExtendedLayout = [.top, .bottom]