So, I am building an iOS app for an iPad. The app has video chat embedded in it. I have gotten video chat, notifications, etc. all to work. My problem is with the interface. I'm a noob when it comes to iOS programming btw; I only started doing this 2 weeks ago. Sorry if the post is a bit long I just attempted to highlight everything that might be at play here and my thought process. Any critique is welcome.
I have a UIWebView (call it webView) that displays most of the information. When a button is clicked, I want that to be resized and a small new view to appear, which has three items: the person you're chatting with (call it imageOne), your video chat (call it imageTwo), and a hang up button (call it buttonHangUp). If the device is in landscape orientation, I want the new view to appear on the right with imageOne, imageTwo, and buttonHangUp in a vertical position. If the device is in a portrait orientation, I want the new view to appear on the bottom, with imageOne, image Two, and buttonHangUp in a horizontal position.
Here is how my thought process went:
- I read the article http://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/RespondingtoDeviceOrientationChanges/RespondingtoDeviceOrientationChanges.html#//apple_ref/doc/uid/TP40007457-CH7-SW14 and thought about creating an alternate landscape view in the storyboard that gets called when the orientation changes. Then I realized that wouldn't work because the webView in each would be a separate entity and so when the user switches back and forth the navigation on the webView would be out of sync
- I realized I should just put in a different view that houses imageOne, imageTwo, and buttonHangUp. Call that viewTwo. viewTwo should start hidden and appear only when it is called from the webView, and should reposition and resize along with all the items inside it when the orientation changes.
I proceeded with the second option (if there is a simpler way of doing this or if I should have done something else, please let me know; I would love to learn the tips and tricks of the trade).
Here is how my code went:
- I made a global variable isLandscape a la apple tutorial up there
- I made 6 other global variables, CGRects, each to hold the position of the different items in portrait and landscape (imageOnePortrait, imageOneLandscape, etc)
I implemented awakeFromNib, setting the portrait variables to the initial positions and sizes of the items
(void) awakeFromNib { isLandscape = NO; imageOnePortrait = self.imageOne.frame; imageTwoPortrait = self.imageTwo.frame; buttonHangUpPortrait = self.buttonHangUp.frame; [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification object:nil]; }I implemented the orientationChanged method as described in the apple documentation. However, I replaced the UIDeviceOrientation with UIInterfaceOrientation because the UIDeviceOrientation was not sending the landscape/portrait orientations I was looking for, but faceup and facedown messages
- (void) orientationChanged:(NSNotification *)notification { UIInterfaceOrientation interfaceOrientation = [UIApplication sharedApplication].statusBarOrientation; if(UIInterfaceOrientationIsLandscape(interfaceOrientation) && !isLandscape) { CGRect temp = self.videoView.frame; temp.size.width = 360; temp.size.height = 748; temp.origin.x = 664; temp.origin.y = 0; self.videoView.frame = temp; self.imageOne.frame = imageOneLandscape; self.imageTwo.frame = imageTwoLandscape; self.buttonHangUp.frame = buttonHangUpLandscape; isLandscape = YES; } else if (UIInterfaceOrientationIsPortrait(interfaceOrientation) && isLandscape) { CGRect temp = self.videoView.frame; temp.size.width = 768; temp.size.height = 300; temp.origin.x = 0; temp.origin.y = 703; self.videoView.frame = temp; self.imageTwo.frame = imageTwoPortrait; self.imageOne.frame = imageOnePortrait; self.buttonHangUp.frame = buttonHangUpPortrait; isLandscape = NO; } }Under viewDidLoad, I set the coordinates for the Landscape coordinates (I assume these coordinates are loaded before any call to the orientationMade function is ever made, and that they are relative to the videoView - correct me please if I need to set them relative to something else; I see them set relative to videoView in the storyboard):
imageOneLandscape.origin.x = 20; imageOneLandscape.origin.y = 20; imageTwoLandscape.origin.x = 20; imageTwoLandscape.origin.y = 288; buttonHangUpLandscape.origin.x = 20; buttonHangUpLandscape.origin.y = 556;Under the function that initiates the video call, I resize webView, and show the videoView:
CGRect temp = self.webView.frame; if(isLandscape) { temp.size.width -= self.videoView.frame.size.width; temp.origin.x = 0; temp.origin.y = 0; self.webView.frame = temp; } else { temp.size.height -= self.videoView.frame.size.height; temp.origin.x = 0; temp.origin.y = 0; self.webView.frame = temp; } self.videoView.hidden = FALSE;and then I do the opposite in buttonHangUp function
Several wrong things are happening:
- When I switch orientations, videoView doesn't always move or resize, and when it moves the move is often delayed (happens a second after the rest of the items have rotated)
- When I switch to landscape, imageOne and imageTwo are squished horizontally, and are not in the alignment I have set them to be in
- When I switch to portrait, things seem to be working fine all the time. videoView always goes to the right place and so do its subviews (imageOne, imageTwo, and buttonHangUp).
- the imageOne and imageTwo disappear from portrait view when I lay the ipad flat, without changing orientation
- even if I set the views to display in a different layout in viewDidLoad, they are resetting to the layout they have in the storyboard
Could anyone explain to me what is happening here and why it is happening? This is very confusing to me. I think it has to do with coordinate systems switching between coordinates for webView and the app itself, the order of precedence of the different functions executing (awakeFromNib, the view coordinates being set for the first time from the storyboard, viewDidLoad, etc), and with the redrawing of the subviews, or with a combination of all these issues and possibly more. I am going to investigate those issues next.
I would also appreciate someone mentioning what the best practices are for achieving what I want; as I said I am new to this, and apple documentation unfortunately doesn't cover what is considered best practice when it comes to my case. Links to articles would also be appreciated.
I fixed my code after some hours of debugging yesterday. Here are all the things that were going wrong, and hopefully a helpful guide to how to handle switching orientation programmatically:
I still welcome any comments about how people handle landscape and portrait layouts!