iPad question:
We have views that we're initializing from .xibs, with each .xib containing both landscape and portrait layouts.
The first view we load respects the orientation of the device, but any subsequent views seem to have confusion over which orientation they should be using. Or, rather, they seem to ignore orientation altogether and go with whichever orientation the .xib file was saved with. (i.e. We saved a .xib file in landscape, and even though the device was held in portrait position, it loaded the view from the .xib with a landscape layout.)
This is how we're calling in these views:
Settings *settingsTEMP = [[Settings alloc] init];
self.settings = settingsTEMP;
[self.view insertSubview:settings.view atIndex:0];
[settingsTEMP release];
The first of the calls (the one that respects the device's orientation) is in the viewDidLoad. The second, which uses a different view (the one that doesn't respect the device's orientation) is in a method that's called after a button is pressed, but uses the same syntax.
If we put both into viewDidLoad, they both respect the orientation.
We've tried searching for anyone having similar issues but have been thus far unsuccessful. Thanks in advance for any help you can provide.
I use the following
UIInterfaceOrientation toInterfaceOrientation = self.interfaceOrientation;
if ((toInterfaceOrientation == UIDeviceOrientationLandscapeLeft) ||
(toInterfaceOrientation == UIDeviceOrientationLandscapeRight))
{
NSLog(#"vSettings UIDeviceOrientationLandscape");
CGRect contentRect = CGRectMake(0,0,1024,768);
vSettings.bounds = contentRect;
CGRect myFrame = vSettings.frame;
myFrame.origin.x = 0.0;
myFrame.origin.y = 0.0;
vSettings.frame = myFrame;
UIImage *image;
image = [UIImage imageNamed: #"Default-Landscape.png"];
[backGroundSettings setImage:image];
}
I hate having to do this as it seems a right fudge but it works for me. Called just after I create the view.
Related
I have a static table view with cells that have a rounded border. I have noticed when testing on different simulators that whilst my auto layout constraints work, the border isn't always the right width. This particular screen consists of a view controller with a UIView containing an embedded tableViewController
I have done some investigating and found that the width of the border actually depends on the width of the storyboard phone. This means if I have a storyboard for an iPhone 8, the 8+ will have cells too short and vice versa, an 8+ storyboard results in cells that are too long (and extend off screen) for the 8.
Currently I am setting the cell borders in the viewDidLoad, here is the code I am using to configure the cells border:
- (void)configureCellThree {
//Add Border
CALayer *borderLayer = [CALayer layer];
CGRect borderFrame = CGRectMake(0, 0, (_contentCellThree.frame.size.width), (_contentCellThree.frame.size.height));
[borderLayer setBackgroundColor:[[UIColor clearColor] CGColor]];
[borderLayer setFrame:borderFrame];
[borderLayer setCornerRadius:_contentCellThree.frame.size.height / 2];
[borderLayer setBorderWidth:1.0];
[borderLayer setBorderColor:[kTextColor2 CGColor]];
// [borderLayer setOpacity:0.5];
[_contentCellThree.layer addSublayer:borderLayer];
}
Now if I run this code within the viewDidAppear, everything will work across both devices. I added some logs to my main view controller to find out how things were being set.
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"VDL - SELF.VIEW = %#", self.view);
NSLog(#"VDL - CONTAINER VIEW = %#", self.profileScrollingContainerView);
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
NSLog(#"VDA- SELF.VIEW = %#", self.view);
NSLog(#"VDA - CONTAINER VIEW = %#", self.profileScrollingContainerView);
}
I had suspected that viewDidLoad was using the sizing information from the storyboard instead of the view itself (which doesn't seem right). This logging confirms this. If I look at the UIView responsible for displaying my tableview, when the storyboard is set to 8+ it has the following frame attributes: X = 0, Y = 349, W = 414, H = 338. Now lets look at the results of the logging:
VDL - SELF.VIEW = <UIView: 0x7fa545401f10; frame = (0 0; 375 667);
VDL - CONTAINER VIEW = <UIView: 0x7fa545401b50; frame = (0 349; 414 338);
VDA- SELF.VIEW = <UIView: 0x7fa545401f10; frame = (0 64; 375 603);
VDA - CONTAINER VIEW = <UIView: 0x7fa545401b50; frame = (0 285; 375 269);
So when the view loads the tableview is getting the wrong information about the views size. When the viewDidAppear gets called it has the correct sizing of the view and will work properly. My issue here is that I don't want to be calling initialising code in my viewDidAppear.
I read here that I should be putting my UI Geometry code into the viewWillAppear however I have tried this and I get the same issues.
VWA - CONTAINER VIEW = <UIView: 0x7fec04d97700; frame = (0 349; 414 338);
So to consolidate my question, How can I get the properties of my view before the view has loaded/appeared so I can correctly setup my UI?
I have read that I will need to subclass UIView and potentially use setFrame however I don't really know how I'd actually go about doing this.
Subclass UITableViewCell and implement layoutSubviews, i.e. see the docs:
"Subclasses can override this method as needed to perform more precise layout of their subviews. You should override this method only if the autoresizing and constraint-based behaviors of the subviews do not offer the behavior you want. You can use your implementation to set the frame rectangles of your subviews directly."
So it turns out I was using the wrong method to do this. I found this question which solved my whole issue. Basically if you need to perform UI calculations (such as adding custom views) you should be performing them in -(void)viewDidLayoutSubviews. This method is called after the view has worked out all of its sizing and constraints so anything you do in here will be executed using the right properties of your view!
When I am setting a background image on a SKScene. I have written the code below:
#import "JTEDMyScene.h"
#define IS_IPAD (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
#interface MyScene()
#property BOOL isContentCreated;
#end
#implementation MyScene
-(void) didMoveToView:(SKView *)view
{
if(!self.isContentCreated)
{
self.isContentCreated = YES;
[self createSceneContent];
}
}
-(void)createSceneContent
{
[self addChild:[self createBackground]];
}
-(SKSpriteNode *)createBackground
{
SKSpriteNode *backgroundSprite;
SKTexture *textureImage;
if (IS_IPAD) {
textureImage = [SKTexture textureWithImageNamed:#"home_ipad1.jpg"];
backgroundSprite = [SKSpriteNode spriteNodeWithTexture:textureImage];
}
backgroundSprite.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
return backgroundSprite;
}
Device orientation modes are only Landscape left and landscape right. My image size is width = 1024 and height= 768 and 264 dpi. But the image is not showing fully a portion of image is showing.
Maq has the right idea. I think what he's saying is, the problem lies in your view controller .m file, instead of in your Scene. Instead of creating your SKView and SKScene and presenting the SKScene from within the viewDidLoad method of your VC, put that code in the viewWillLayoutSubviews method instead. Something along the lines of this:
-(void)viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
SKView * skView = (SKView *)self.view;
SKScene * scene = [YourScene sceneWithSize:skView.bounds.size];
scene.scaleMode = SKSceneScaleModeAspectFill;
[skView presentScene:scene];
}
Apparently, viewWillLayoutSubviews gets called later than viewDidLoad. When viewDidLoad is called, the view hasn't even been added to the view hierarchy yet.
Ray Wenderlich's Sprite Kit Tutorial for Beginners quotes this answer from SO as to why this happens.
Try to present and create MyScene in viewWillLayoutSubviews - if you haven't done it already.
It may work if you just rename viewDidLoad to viewWillLayoutSubviews and rename the super call too.
I started a blank project and copy-pasted your code into it and it works fine. I know you said you set your device orientation, but did you do that in your project settings? That's the only problem I can think of. Select your project, general tab, and under Deployment Info, there's a "Devices" drop-down box. Select iPad and make sure "Landscape Left" and "Landscape Right" are the only two checked. My guess is that the project thinks it's supposed to be starting in portrait mode, so it's stretching your 768-tall image vertically to 1024 at start; then when your app determines that it's in landscape orientation, it just rotates that stretched image accordingly, which would result in the image being cut off.
yes, to control and resize background image (in my case) correspond to device orientation, you have to use -(void)viewWillLayoutSubviews
but don't forget, it will start from first scene by default, so you need to use some "sceneNumber" selector in this function to point to actual scene
Okay guys, maybe you can help me out with this one. I'm about ready to pull my hair out.
Recently I decided to upgrade my app and make it look better, and with that I wanted to move it into full support for iPad platforms as well. For a while everything worked great. Just press copy MainWindow.xib for iPad, add the views that I used on the iPhone configurations, and everything should be great, but that didn't work too well. Take a look:
Here is the iPhone screenshot:
Here is the iPad screenshot:
Where's the tab bar? I don't understand! I added the initial view when I was first putting it together, but when I linked all of the IBOutlets to the proper pieces, the tab bar no longer shows up.
Screenshot of IB:
Tab Bar properties:
Tint: A bluish color
Image Tint: A goldish color
Mode: Scale to fill
Tag: 0
User Interaction Enabled: (Checked)
Multiple Touch: (Unchecked)
Alpha: 1
Opaque: (Checked)
Hidden (Unchecked)
Clears Graphic Context: (Checked)
Clip Subviews: (Unchecked)
Autoresize Subviews: (Checked)
Stretching: (x,y,w,h):(0,0,1,1)
The viewController.h file is a delegate for UITabBar, UITextField, and UITextView
ViewDidLoad (bar is the IBOutlet for the tab bar):
- (void)viewDidLoad
{
[super viewDidLoad];
[self playMovieIntro];
NSURL *url = [NSURL URLWithString:#"http://www.faithlifefellowship.us/Audio/Sermons/NewSermonBanner.png"];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:data];
if(!image == NULL)
{
NewSermonBanner.image = image;
}
series = [[Series alloc] init];
SeriesName = #"";
NSRange range = [[[UIDevice currentDevice] name] rangeOfString:#"iPad"];
int i = 0;
if(range.location != NSNotFound)
i = 1;
bar.selectedItem = hometab;
//set delegates
[bar setDelegate:self];
[personalName setDelegate:self];
[personalEmail setDelegate:self];
[content setDelegate:self];
[prContent setDelegate:self];
[prName setDelegate:self];
[prEmail setDelegate:self];
}
I'm stumped. If you have any ideas or need any more information, let me know.
Thanks!
I'm going to give you a few things I'm getting in order to fix this. It will be tons easier if you could upload the source code for me/us to download and be able to pinpoint the problem.
Sometimes (I can't remember exactly when) I've had my navigation bar not show up because it was missing a connection.
Make sure you are not hiding the tab bar anywhere in code, though it doesn't seem to be the case since it shows up on iPhone.
Otherwise I'm gonna take a guess and say it's something in the NIB. Here are some things you can try:
Check all your connections to outlets
Make sure your objects in the NIB are of the correct class
Verify that the tab bar's "hidden" property is not check in Interface Builder
Compare and verify all the structure of the NIB file between iPhone and iPad
These are just some ideas :) again if you can post the code it would be fantastic.
Let us know how it goes,
Felipe
I had this problem with a app that support both iPhone and iPad. Make sure 'is initial view controller' is checked for the UITabBarController when you examine the view controller using the object inspector. When you do this, xcode will display a 'inbound' arrow on the left side of the view controller if you're using storyboards.
I am using a UIPopoverController and populating it with a MPMediaPickerController to choose songs from iPod library. I have got it working just fine. However, I added a completely unrelated feature ( touch a button and image scale to large size ) and now the UIPopoverController behaves strangely only after using the new feature.
After using the button scale feature, the UIPopoverController appears in a strange manner. It looks like it is animating from a rotated state off the screen and lands in the correct place, but the expected behavior is that it should just appear in the right location.
// code for if the interface is a an iPhone, do not use popup
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
[self presentModalViewController:picker animated:YES];
// code if not iPhone uses popover media picker
else {
UIPopoverController* pop =
[[UIPopoverController alloc] initWithContentViewController:picker];
self.currentPop = pop;
// checks if the iPad is portrait or landscape and displays the popover media picker accordingly
if (vertMode == TRUE)
{
// if in portrait mode
[pop presentPopoverFromRect:CGRectMake(668.0f, 846.0f, 10.0f, 10.0f) inView:self.view permittedArrowDirections:UIPopoverArrowDirectionDown animated:NO];
// otherwise if in landscape mode
}
else if (vertMode == FALSE)
{
[pop presentPopoverFromRect:CGRectMake(900.0f, 580.0f, 10.0f, 10.0f) inView:self.view permittedArrowDirections:UIPopoverArrowDirectionDown animated:NO];
}
[pop release];
}
}
OK, well I feel a bit silly answering my own question, but I hope that it may help someone else in the future.
I am not exactly sure why, but in my function for the button that scales the image to a large size, I forgot to add:
[UIView commitAnimations];
the intention of that was to complete the animated movement of the scaling image, I am guessing because I never commit the animation, that it was still in some state of trying to animating things. Then when I called my popup , it made the weird animation occur.
So I fixed this by just adding the above one line!
I feel SO much better figuring this one out! I hope it helps someone else out there.
I'm trying to add a view to my controller, which is put into landscape mode programmatically with the follwoing code:
- (void)viewDidLoad {
[super viewDidLoad];
//EpisodeView *nextEpisode = [self getNextEpisode];
UIImageView *nextEpisode = [[UIImageView alloc] initWithImage:[UIImage imageNamed: #"default-background.png"]];
CGRect selfBounds = self.view.bounds;
nextEpisode.frame = selfBounds;
[self.view addSubview:nextEpisode];
}
The problem is that the added view draws itself in portrait mode, not in landscape. Can anyone please point out what I could have missed?
When I'm adding the same view using Interface Builder, all works perfectly fine. So, I think, I have missed some property or something like that.
You probably haven't added autoresizingMasks which are by default UIViewAutoresizingNone. IB has different defaults. Set them as needed.