How to addSubview with a position? - ios

I have something like this:
myViewController = [[MyViewController alloc] initWithNibName:#"MyView" bundle:nil];
[mainCanvas addSubview: myViewController.view];
self.view = mainCanvas;
It will be added at the position (0, 0), but I want to add it at (0, 100) or somewhere else. How can I do so?

Something like this:
myViewController = [[MyViewController alloc] initWithNibName:#"MyView" bundle:nil];
myViewController.view.frame = CGRectMake(0, 100, myViewController.view.frame.size.width, myViewController.view.frame.size.height);
[mainCanvas addSubview: myViewController.view];
self.view = mainCanvas;

In addition to setting the frame property, you can also set the center property of a view.

Set the frame property on the sub view.

This is the best way I've found to add a subView, like a loading screen or something that you want to show whether you are in a UIView, UIScrollView, or UITableView.
myViewController = [[MyViewController alloc] initWithNibName:#"MyView" bundle:nil];
myViewController.view.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);
[self.view addSubview:myViewController.view];
self.view.bounds = myViewController.view.bounds;
This will make the subView appear in full screen no matter where you are in the self.view by adding the subView to where you are currently located in your self.view instead of positioning it in the top left corner, only showing fully if you are at the very top of your view.

Related

iOS: How to keep showing a subView after pushing to a viewController

I have viewController No.1, which has a subView showing. And after I push to another viewController, No.2, this subView does not shown on the screen anymore, which makes sense, since I have pushed to another VC.
However, I hope to keep this subView on the screen even though I am in a pushed viewController now. So I wonder how I can achieve this?
This will work:
//Create a view in the center of the screen
UIView *view = [[UIView alloc]initWithFrame:CGRectMake(([UIScreen mainScreen].bounds.size.width/2)-50, ([UIScreen mainScreen].bounds.size.height/2)-50, 100, 100)];
view.backgroundColor = [UIColor redColor];
//Create a window class
UIWindow* window = [[UIApplication sharedApplication].windows objectAtIndex:0];
//Pick a level
window.windowLevel = UIWindowLevelStatusBar;
//Add the view
[window addSubview:view];

Full screen horizontally scrolling UICollectionView cells shift downwards when used in first displayed UIViewController

I'm creating a series of help pages that display when the user first starts the app. To do this, I have a programatically set up UIViewController that initializes a (programatically set up) UICollectionView the size of the view controller bounds. Each cell contains a fullscreen sized image.
When this view controller is pushed when there's already an existing view controller, it shows up fine. But, when this view controller is used as the initial root view controller for the app navigation controller, the collection view has the correct size and alignment, but the cells are shifted down about 10 pixels from the top of the screen, so that the collection view background shows through.
(note that red is the collection view background color)
If I set up the collection view in viewDidLoad, viewDidLayoutSubviews, or viewWillAppear, I get the same problem. I don't encounter this issue if I set up the collection view in viewDidAppear, but this doesn't work because the user will see a black screen before the collection view loads.
Here is the code that is displaying the view controller, in application:didFinishLaunchingWithOptions:launchOptions:
UIViewController* viewControllerToPush = [[OnboardingViewController alloc] initWithNibName:nil bundle:nil];
_nav = [[UINavigationController alloc] initWithRootViewController:viewControllerToPush];
[_nav setNavigationBarHidden:YES];
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
[self.window setRootViewController:_nav];
[self.window makeKeyAndVisible];
And here is the code that is setting up the collection view and layout:
UICollectionViewFlowLayout* layout = [[UICollectionViewFlowLayout alloc] init];
layout.minimumInteritemSpacing = 0;
layout.minimumLineSpacing = 0;
layout.itemSize = CGSizeMake(self.view.bounds.size.width, self.view.bounds.size.height);
layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
CGRect collectionViewFrame = self.view.bounds;
_collectionView = [[UICollectionView alloc] initWithFrame:collectionViewFrame collectionViewLayout:layout];
_collectionView.delegate = self;
_collectionView.dataSource = self;
_collectionView.pagingEnabled = YES;
_collectionView.showsHorizontalScrollIndicator = NO;
[_collectionView registerClass:[OnboardingCollectionViewCell class] forCellWithReuseIdentifier:#"Cell"];
[self.view addSubview:_collectionView];
I fixed this issue by setting the view controller's automaticallyAdjustsScrollViewInsets to NO in the init function. Thanks to https://stackoverflow.com/a/25352483/1370967 for the inspiration on this.
For Swift 5.5 use that -> collectionView.contentInsetAdjustmentBehavior = .never

UIPopoverController with UINavigationController border sizing

I am embedding a UINavigationController within a UIPopoverController. It "works", but the top border of the popover expands to the size of the navigation controller bar (behind it), casting the border's shadow onto the top of the main view (read: the top border of the popover is 44 points high). When I instantiate the popover with the class itself...not within the UINavigationController, it all works fine (but, of course I don't have access to the navigational controller).
Where am I going wrong?
CGPoint buttonPoint = [self.mapView convertPoint:sender.center fromView:self.guideButtonScroll];
GuideViewController *guideViewController = [[GuideViewController alloc] initWithNibName:#"GuideView" bundle:nil];
UINavigationController *guideNavigationController = [[UINavigationController alloc] initWithRootViewController:guideViewController];
self.buttonbarPopoverController = [[UIPopoverController alloc] initWithContentViewController:guideNavigationController];
self.buttonbarPopoverController.delegate = self;
self.buttonbarPopoverController.popoverContentSize = CGSizeMake(320, 504);
[self.buttonbarPopoverController presentPopoverFromRect:CGRectMake(buttonPoint.x - 30, buttonPoint.y, 10, 10) inView:self.mapView permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
What you are seeing is not the top border of the popover expanded. The popover has normal borders. What you are seeing is the UINavigationBar at the top of the navigation controller's view. The UINavigationBar casts a shadow in iOS 6.
The UINavigationBar is automatically given a special color / style that matches that of the popover borders. Of course you can change that if you don't like it. You are also free to hide the navigation controller's navigation bar if you don't want to see it.
Went with subclassing the UIPopoverController, but that didn't get the gloss look of the popover. Simply just put the UINavigationController inside a UIViewController...gets the custom navigation bar and the gloss look of the popover. Here's what I ended up with:
UIViewController *guideviewViewController = [[UIViewController alloc] init];
guideviewViewController.view.frame = CGRectMake(0, 0, 320, 508);
GuideViewController *guideViewController = [[GuideViewController alloc] initWithNibName:#"GuideView" bundle:nil];
self.guideNavigationController = [[UINavigationController alloc] initWithRootViewController:guideViewController];
self.guideNavigationController.view.frame = CGRectMake(0, 0, 320, 508);
[guideviewViewController.view addSubview:self.guideNavigationController.view];
CGPoint buttonPoint = [self.mapView convertPoint:sender.center fromView:self.guideButtonScroll];
self.guidePopoverController = [[UIPopoverController alloc] initWithContentViewController:guideviewViewController];
self.guidePopoverController.delegate = self;
self.guidePopoverController.popoverContentSize = CGSizeMake(320, 508);
[self.guidePopoverController presentPopoverFromRect:CGRectMake(buttonPoint.x - 30, buttonPoint.y, 10, 10) inView:self.mapView permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];

Replacing self.view with new UIView shows black view

I want to change the existing view in a UIViewController to a new view. The new view contains the old view and a little banner view.
Doing this fairly simple change leaves me with a black view.
My code looks like this
UIView *existingView = self.view;
UIView *newView = [[UIView alloc] initWithFrame:existingView.frame];
UIView *bannerView = [[UIView alloc] initWithFrame:CGRectMake(0, (self.view.frame.size.height - 50), 320, 50)];
CGRect existingViewFrame = existingView.frame;
existingViewFrame.size.height -= 50;
existingView.frame = existingViewFrame;
[newView addSubview:existingView];
[newView addSubview:bannerView];
self.view = newView;
However when switch Tabs and come back to the view which changed the view is shown just like I want. I guess I need to set a flag or something to tell the controller to redraw it's (new) view.
Edit
I wrote an simple example for this problem. You can find it on GitHub: https://github.com/Oemera/ChangeView
You did not say where you do this. It may be that you need to save the original view's super view, then add the new view to that views subViews array. I'm betting that is the problem.

Can't add UITableView as subview

Xcode 4.3/iOS 5.1/Storyboards.
I have a UIViewController with a UITableView in the storyboard
when initializing that view
-(void) loadView {
UITableView *tTableView = [[UITableView alloc] initWithFrame:CGRectMake(20,60, 300, 300)
style:UITableViewStyleGrouped];
[tTableView setDelegate:self];
[tTableView setDataSource:self];
[tTableView setBackgroundView:[[UIView alloc] initWithFrame:self.tableView.bounds]];
self.tableView = tTableView;
self.view = tTableView; // <--- THIS WORKS
}
This works, but the TableView is stretched over the entire width of the screen. I'd like it to be of a certain size as I'm using it for a login username/password control.
I was told to add it as a sub-view, but this crashes my app with some kind of recursive calling into the same "loadView" method.
-(void) loadView {
UITableView *tTableView = [[UITableView alloc] initWithFrame:CGRectMake(20,60, 300, 300)
style:UITableViewStyleGrouped];
[tTableView setDelegate:self];
[tTableView setDataSource:self];
[tTableView setBackgroundView:[[UIView alloc] initWithFrame:self.tableView.bounds]];
self.tableView = tTableView;
[self.view. addSubview: tTableView]; // <-- THIS CRASHES
}
Why is this crashing? How can I add the UITableView to a subview where I can control its width and not have it occupy the entire width of my screen?
you need to self.view = tTableView or self.view = [UIView alloc] initWithFrame.... and then add the table view. Overriding the loadView method means you are going to create the self.view. So for your case, create an UIView, set it to self.view and then add your tableView as subview of self.view
You use the loadView method, which means you define the view by yourself.
So self.view is not defined and the controller complains that its view is not defined when it should display itself.
Either put your interface in a xib (or storyboard) and bind those values in viewDidLoad, or instanciated the self.view by hand in loadView.

Resources