How to draw View Controller from the bottom - ios

I am trying to develop an app in Xcode. I am new in Objective C programming but so far I did OK. Today I got my first problem. I am trying to draw a transparent VC (View Controller) from the bottom up but I do not know how I can accomplish this. I know that drawing in iPhone begins from 0,0 coordinates from top left corner going right and down. Is there a way to kind of cheat and draw the VC from the bottom to top 70% covering the screen, just like the tools menu when swipe up on iPhone screen in iOS 7.x.x
Thanks in advance.

Heres one solution:
Create the view as a subview of the main view in this controller.
self.rolloutView = [[UIView alloc]initWithFrame:CGRectMake(0, [[UIScreen mainScreen] bounds].size.height, [[UIScreen mainScreen] bounds].size.width, heightYouWant)];
When the user takes the action, call this function
-(void)toggleView:(id)sender
{
__block CGRect frame = self.rolloutView.frame;
// Check if the frame's origin.y is at the bottom of the screen
if(self.rolloutView.frame.origin.y == [[UIScreen mainScreen] bounds].size.height){
// if it is, reduce it by the height of the view you eventually want
frame.origin.y = [[UIScreen mainScreen] bounds].size.height-heightYouWant ;
}
else{
// else push it down again
frame.size.height = [[UIScreen mainScreen] bounds].size.height;
}
[UIView animateWithDuration:.3
animations:^{
self.rolloutView.frame = frame;
}
completion:nil];
}
I have not compiled the code but it should give you the idea on what i am suggesting

Related

Custom UIWindows do not rotate correctly in iOS 8

Get your application into landscape mode and execute the following code:
UIWindow *toastWindow = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
toastWindow.hidden = NO;
toastWindow.backgroundColor = [[UIColor cyanColor] colorWithAlphaComponent:0.5f];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[toastWindow removeFromSuperview];
});
In iOS 7 you will get a transparent blue overlay on top of the entire screen that disappears after 5 seconds. In iOS 8 you will get a transparent blue overlay that covers a little over half the screen
This obviously has something to do with the change Apple did in iOS 8 where the screen coordinates are now interface oriented instead of device oriented but in true Apple fashion they seem to have left a myriad of bugs in landscape mode and rotation.
I can "fix" this by checking if the device orientation is landscape and flip the width and height of the main screen bounds but that seems like a horrible hack that is going to break when Apple changes everything again in iOS 9.
CGRect frame = [[UIScreen mainScreen] bounds];
if (UIInterfaceOrientationIsLandscape([UIDevice currentDevice].orientation))
{
frame.size.width = frame.size.height;
frame.size.height = [[UIScreen mainScreen] bounds].size.width;
}
UIWindow *toastWindow = [[UIWindow alloc] initWithFrame:frame];
toastWindow.hidden = NO;
toastWindow.backgroundColor = [[UIColor cyanColor] colorWithAlphaComponent:0.5f];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[toastWindow removeFromSuperview];
});
Has anyone been experiencing this problem and come across a better, less brittle solution?
EDIT: I know I could just use a UIView and add it to the key window but I would like to put something on top of the status bar.
Your 'fix' isn't great for another reason, in that it doesn't actually rotate the window so that text and other subviews appear with the appropriate orientation. In other words, if you ever wanted to enhance the window with other subviews, they would be oriented incorrectly.
...
In iOS8, you need to set the rootViewController of your window, and that rootViewController needs to return the appropriate values from 'shouldAutoRotate' and 'supportedInterfaceOrientations'. There is some more about this at: https://devforums.apple.com/message/1050398#1050398
If you don't have a rootViewController for your window, you are effectively telling the framework that the window should never autoRotate. In iOS7 this didn't make a difference, since the framework wasn't doing that work for you anyway. In iOS8, the framework is handling the rotations, and it thinks it is doing what you requested (by having a nil rootViewController) when it restricts the bounds of your window.
Try this:
#interface MyRootViewController : UIViewController
#end
#implementation MyRootViewController
- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskAll;
}
- (BOOL)shouldAutorotate
{
return YES;
}
#end
Now, add that rootViewController to your window after it is instantiated:
UIWindow *toastWindow = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
toastWindow.rootViewController = [[MyRootViewController alloc]init];
I believe you have to convert the UICoordinateSpace.
On iPhone 6 Plus apps can now launch already in landscape orientation, which messed up an application I am working on since it only supports portrait orientation throughout most of the app, except one screen (meaning it needed to support landscape orientations in the plist).
The code that fixed this was as follows:
self.window = [[UIWindow alloc] initWithFrame:[self screenBounds]];
and calculating the bounds with the following code:
- (CGRect)screenBounds
{
CGRect bounds = [UIScreen mainScreen].bounds;
if ([[UIScreen mainScreen] respondsToSelector:#selector(fixedCoordinateSpace)]) {
id<UICoordinateSpace> currentCoordSpace = [[UIScreen mainScreen] coordinateSpace];
id<UICoordinateSpace> portraitCoordSpace = [[UIScreen mainScreen] fixedCoordinateSpace];
bounds = [portraitCoordSpace convertRect:[[UIScreen mainScreen] bounds] fromCoordinateSpace:currentCoordSpace];
}
return bounds;
}
Hopefully this will lead you in the right direction.
In iOS 7 and earlier, UIWindow's coordinate system did not rotate. In iOS 8 it does. I am guessing the frame supplied from [[UIScreen mainScreen] bounds] does not account for rotation, which could cause issues like what you're seeing.
Instead of getting the frame from UIScreen, you could grab the frame from the appDelegate's current key window.
However, it does not appear you really need functionality supplied by UIWindow. I'd like to echo others' recommendation that you use a UIView for this purpose. UIView is more generic than UIWindow, and should be preferred.
The best thing to do is use views instead of windows:
Most iOS applications create and use only one window during their lifetime. This window spans the entire main screen [...]. However, if an application supports the use of an external display for video out, it can create an additional window to display content on that external display. All other windows are typically created by the system
But if you think you've got a valid reason to create more than one window, I suggest you create a subclass of NSWindow that handles sizes automatically.
Also note that windows use a lot of RAM, especially on 3x retina screens. Having more than one of them is going to reduce the amount of memory the rest of your application can use before receiving low memory warnings and eventually being killed.

Move image left to right continuously

I need to make run this animation from left to right continuously. Now Is working, but show 1 time only (when the game is loaded). I want to make this animation run continously, left to right continuously. Timer and speed is already working. Here my current code:
- (void)airplane1Code {
airplane1.center = CGPointMake(airplane1.center.x + 10, airplane1.center.y);
}
Any suggestion? Thanks
You can create a UIView animation with the UIViewAnimationOptionRepeat
airplane1.center = CGPointMake(startX, startY);
[UIView animateWithDuration:10.0 //10seconds
delay: 0
options: UIViewAnimationOptionRepeat
animations:^{
airplane1.center = CGPointMake(endX, endY);
}
completion:nil];
That will make it do the same animation from start to end over and over. In order to stop the animation, call
[airplane1.layer removeAllAnimations];
If you want the airplane to show up on the start side after it disappears from the end side, just reset the center off screen on the start side once it passes the window's frame. If you want another plane to show up and start flying after that one has left, then add another plane object and move them at the same time.
CGRect screenRect = [[UIScreen mainScreen] bounds];
CGFloat screenWidth = screenRect.size.width;
CGFloat screenHeight = screenRect.size.height;
-(void) airplane1Code{
airplane1.center = CGPointMake(airplane1.center.x + 10, airplane1.center.y);
if(airplane1.center > screenWidth + halfTheImageSize)
// if the plane is completely off the screen, move the image to other side
// and keep running this method with your loop
airplane1.center = CGPointMake(0 - halfTheImageSize, airplane1.center.y);
}

CGRect positioning according to center point

I'm trying to create multiple views for an iPad app. First I created a menu view and then a sub-menu view with coordinates according to menu. So it looks like this:
What I did:
self.view = [[UIView alloc] initWithFrame:CGRectMake(self.parentViewController.view.frame.size.width, 0, 150, screenHeight)];
But now on sub-menu I'm trying to create the content view, which is a UINavigationController. Trying to do the same thing, I get this result:
What I'm doing (this time creating the frame on sub-menu view controller):
CGRect frame = CGRectMake(self.view.frame.origin.x + self.view.frame.size.width,
0,
[[UIScreen mainScreen] bounds].size.width - self.view.frame.origin.x - self.view.frame.size.width,
[[UIScreen mainScreen] bounds].size.height);
It's pretty self-explanatory but, I just get the sub-menu origin and add its width so I can get the right edge coordinate.
After a lot of attempts I managed to get it working, because I noticed that the CGRectMake is using the center of the UINavigationController view to arrange its position. So the following code:
CGRect frame = CGRectMake(self.view.frame.origin.x + self.view.frame.size.width + 259,
0,
[[UIScreen mainScreen] bounds].size.width - self.view.frame.origin.x - self.view.frame.size.width,
[[UIScreen mainScreen] bounds].size.height);
Yields the right position.
What's going on? I thought CGRectMake origin would always be top-left, but on this particularly view is actually top-middle (or middle-middle, not sure.) What am I doing wrong?
EDIT1:
Here's the console output for the frame with right position:
Notice how the nav bar is now positioned right:
But the x-coord is not 250 (as it should be, because menu.width + sub-menu.width = 250.)
EDIT2:
I eventually gave up. The problem was with the automatically generated UINavigationBar, which is created by the UINavigationViewController. I can't seem to figure out how to configure it. I'm gonna leave the question open in case someone knows the answer.
Center of a CGRect is a CGPoint created from the origin.x + ( size.width / 2 ) and origin.y + ( size.height / 2 ).
UIButton* btn = [[UIButton alloc]initWithFrame:CGRectMake(0, 0, 70, 70)];
btn.center = CGPointMake(self.view.frame.size.width/2, self.view.frame.size.height/2);
This will make the button in the center no matter what the device is
CGRectMake just creates an stucture of (x,y, witdh, height).
It your part to set the correct values.

UITableView emerge from right on UIView

I'm trying to make my first animation. Currently I'm using animateWithDuration:animations and transitionFromView:toView:duration:options:completion:, but I'm not sure if I'm in "correct page".
What I want to do is to create such animation: in the left upper corner user taps on button and UITableView arrives from the left side of the screen.
I never did any animation in iOS SDK so any help will be appreciated: similiar problems in StackOverflow, some tutorials etc. I don't know where should I begin.
Assume you have a UITableView as subview of a UIViewController's view.
First, before the animation, set the UITableView out of the screen, use center or frame property:
CGRect screenFrame = [[UIScreen mainScreen] applicationFrame];
self.theTableView.frame = CGRectMake(-screenFrame.size.width, 0.0, screenFrame.size.width, screenFrame.size.height);
Then, complete the animation code:
[UIView animateWithDuration:0.5
delay:0
options:UIViewAnimationOptionCurveEaseInOut
animations:^{
self.theTableView.frame = CGRectMake(0.0, 0.0, screenFrame.size.width, screenFrame.size.height);
}
completion:nil];
Hope it will help you! :D

UIScreen bounds versus applicationFrame

Why do I see in some sample code from Apple (such as PhotoScroller) that I should do the following in loadView:
CGRect frame = [[UIScreen mainScreen] bounds];
instead of
CGRect frame = [[UIScreen mainScreen] applicationFrame];
Does it make a difference to get the main screen's frame?
ApplicationFrame is the screen size minus the size of the status bar (if visible), bounds is the screen size regardless of status bar.
So applicationFrame would return CGRectMake(0,0,320,460) assuming your app has the status bar set to be visible, while bounds would return CGRectMake(0,0,320,480) under the same conditions. Those numbers are assuming iPhone/iPod Touch screen sizes.
UIScreen Class Reference
iOS 9 Update
When using the Split View feature on the iPad, applicationFrame returns the size of your app window. bounds always returns the size of the device.

Resources