I want display different UIButton/UILabel/UISlider sizes on an iPhone 4/4s screen. In the parent ViewController viewDidAppear: method I was able to set new button frames by calling my viewFormatting function.
- (void) viewFormatting
{
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
{
CGSize result = [[UIScreen mainScreen] bounds].size;
//iPhone 4
if (result.height == 480)
{
self.myButton.frame = CGRectMake(x, y, width, height);
self.myLabel.frame = CGRectMake(x, y, width, height);
//etc.
}
}
}
But when I try calling the same method viewFormatting inside initWithFrame: on separate UIView class the button/label frames do not resize. I also tried calling the function inside layoutSubviews. I put a NSLog inside viewFormatting so I know it is getting called correctly, but the button/label frames do not change.
Note: In both scenarios I have created the outlets in XIB files.
Any help is greatly appreciated!
Update: Thanks to #nburk I realized that the use AutoLayout was checked on my xib file. After removing that the code above works perfectly.
I'll leave it here for anyone who needs a sample.
Add this method:
-(void) viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
[self viewFormatting];
}
viewDidLayoutSubviews get called automatically.
Related
Since I am very new to ios programming I have more of a general-design question.
I have a ViewController which contains a GraphView (UIScrollView + UIView) which works fine. When I am rotating to landscape I want the GraphView to resize its height to the display height (so it fills the whole screen) but only 300pts when in portrait.
What I did so far is implementing viewWillLayoutSubviews in the ViewController and resetting the constraints:
- (void)viewWillLayoutSubviews{
_graphViewHeightConstraint.constant = ([[UIDevice currentDevice] orientation] == UIDeviceOrientationPortrait) ? 300:[[UIScreen mainScreen] bounds].size.height-self.navigationController.navigationBar.frame.size.height - 2*_distanceToTopView.constant;
}
and in GraphView.m:
- (void)layoutSubviews{
kGraphHeight = self.frame.size.height;
[self setNeedsDisplay];
}
(because I need the variable kGraphHeight in the code to draw the Graph). This does not seem like a very elegant solution so I wanted to ask what the better way would be? Many thanks for your inputs :)
In GraphView.m
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
kViewWidth = <GET_SCREEN_WIDTH_HERE>;
kViewHeight = <GET_SCREEN_HEIGHT_HERE>;
[self updateViewDimensions];
}
and updateViewDimensions method will set the frame of UIScrollView and UIView
- (void)updateViewDimensions
{
scrollView.frame = self.view.frame;
yourView.frame = CGRectMake(kViewXStartsFrom, kViewYStartsFrom, kViewWidth, kViewHeight);
}
after rotating view to Landscape viewDidLayoutSubviews will be called.
It's working for me.
I created a UICollectionView in the interface builder. I referenced it with
#property (strong, nonatomic) IBOutlet UICollectionView *contactList;
in my .h file and #synthesize contactList; in my .m file.
I tried to implement a slightly different layout in portrait and landscape using the following code:
- (void) adjustViewsForOrientation:(UIInterfaceOrientation) orientation {
if (orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown) {
UICollectionViewFlowLayout *flow = (UICollectionViewFlowLayout*)contactList.collectionViewLayout;
flow.sectionInset = UIEdgeInsetsMake(48, 80, 48, 0);
flow.minimumLineSpacing = 80;
} else if (orientation == UIInterfaceOrientationLandscapeLeft || orientation == UIInterfaceOrientationLandscapeRight) {
UICollectionViewFlowLayout *flow = (UICollectionViewFlowLayout*)contactList.collectionViewLayout;
flow.sectionInset = UIEdgeInsetsMake(48, 64, 48, 0);
flow.minimumLineSpacing = 64;
}
}
This works prefectly, but I also want to change the size (in landscape I have a 2*3 grid per page and in portrait it's a 3*2 grid). I tried setting the size like this:
CGRect frame = [contactList frame];
frame.size.width = 960;
[contactList setFrame:frame];
But it won't update. There is no error, but the view just isn't updated. It just stays at the same size as before. What do I have to do to update the view?
In my app I always using this:
[self.contactList performUpdates:^{
CGRect frame = [contactList frame];
frame.size.width = 960;
[contactList setFrame:frame];
[self.contactList.collectionViewLayout invalidateLayout];
} completion:nil];
This should set your frame and update your layout.
When are you modifying the frame of the contactList? At VC initialization time, outlets are nil. Your view controller gets a ViewDidLoad call after the outlets are connected.
I suspect that contactList is still nil when your resizing code is being executed. Move that code's execution into a ViewDidLoad method, and you'll be able to access the real deal.
You can easily test this theory by adding the following to where you resize the frame:
NSLog(#"contactList is: %#",contactList.description);
i think you try to do
[self.yourcontrollerview reloaddata]
when you modify the frame..
My universal app uses NIBs for its settings screens. I'd like to use the same NIBs for both iPhone and iPad.
Thus on iPad, I use a UIPopoverController in the MainViewController and for settings, simply display the iPhone-sized NIBs, to show what is called the SettingsViewController. The popover is sized 320x460 points.
This causes a problem, because the iPhone version draws a number of things above the status bar programmatically, and for the iPad version this is not necessary. Current situation on iPad:
As you can see, there's a big empty space above the "Settings" title. Thus what I want, is to shift the view controller up about 20 points, inside the popover:
The popover is instantiated as follows in the MainViewController:
settingsPopoverController = [[UIPopoverController alloc] initWithContentViewController:popoverNavigationController];
settingsPopoverController.popoverContentSize = CGSizeMake(320, 460);
settingsPopoverController.delegate = self;
popoverNavigationController.navigationBarHidden = YES;
In the SettingsViewController, I set the frame as follows:
- (void)viewDidLoad
{
self.contentSizeForViewInPopover = CGSizeMake(320, 460);
}
And later in the SettingsViewController, I try to create an offset as follows:
- (void)viewWillLayoutSubviews
{
// shift it up
CGRect frame = self.view.frame;
frame.origin.y = -20;
[self.view setFrame:frame];
}
This does not shift the content up a bit. How to go about?
To clarify: I want to move down the "viewport" that the popover shows.
Try to:
myPopover.autoresizingMask=UIViewAutoresizingNone;
Or:
myPopover.autoresizingMask=UIViewAutoresizingFlexibleHeight || UIViewAutoresizingFlexibleWidth;
You can also try to put your code in -(void)viewDidLayoutSubviews method.
If this answers did not help, try set popoverLayoutMargins (property) instead of setFrame: for example:
popover.popoverLayoutMargins=UIEdgeInsetsMake (
CGFloat 50, //top
CGFloat 50,//left
CGFloat 50,//bottom
CGFloat 50//right
);
Here is the desired outcome. The blue area is the UIView of interest. The UIView is not a UIImageView.
I've tried all sorts of arrangements with auto-resizing masks to no avail
This can only be done programmatically. One option is what #user2223761 suggests with subclassing. If you don't want to subclass UIView, then you need to set the frames on orientation changes and set yourView.center to be the center of the center.
- (void) willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration {
if (UIInterfaceOrientationIsLandscape(interfaceOrientation)) {
// Make sure that the frame is centered in the screen
NSInteger paddingLeftSide = (self.view.bounds.size.width - 480) / 2;
self.view.frame = CGRectMake(paddingLeftSide, 0, 480, 320);
} else {
self.view.frame = CGRectMake(0, 0, 320, 320);
}
}
Dealing with different screen sizes can be tricky. In your case it is not :)
since you want to center the view in the screen what ever size it is, all you need to do is set the center of the view to be the center of the screen.
CGRect screenBounds = [[UIScreen mainScreen] bounds];
view.center = CGPointMake(screenBounds.size.width/2,screenBounds.size.height/2);
This code assumes the view's superView's bounds is the same size as the screenBounds..
First: Subclass UIView (create a MYUIView).
Second: override the method
- (void)layoutSubviews {
[super layoutSubviews];
// .. put your code...
}
and perform the frame update manually inside that method by reading the screen size.
auto-resize mask must be set to UIViewAutoresizingNone.
I am using UIViewController for display my view. My view have been created in interface builder.
Right now these are next parameters for view:
width: 568
height: 320
Orientation: Landscape
in ViewController I have next code:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return ((interfaceOrientation == UIInterfaceOrientationLandscapeLeft) || (interfaceOrientation == UIInterfaceOrientationLandscapeRight));
}
in info.plist I have added just two interface orientation right and left.
but when I try to output width of my view in code I get 320 and when I try to output height it write down in console 568 but I expect 320 instead.
I don't know why it works like this. Any suggestions?
even if I add this:
[self.view setFrame:CGRectMake(0, 0, 568, 320)]; in viewDidLoad method. even then I have inccorect height
I need to know width size I use in this method:
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
CGFloat width = 0.0f;
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
width = 568.0f;
} else {
width = 1024.0f;
}
NSInteger page = scrollView.contentOffset.x / width;
NSLog(#"%d", page);
}
Right now I use hardcode variable of width, but how come. Why I can't use self.view.frame.size.width because the sides swop each other - because.
Maybe you're printing width and height in the viewDidLoad method before the orientation occurs. Try to print it on viewWillAppear or with performSelector:afterDelay:
Another thing that might affect the dimension of the view is how you set the autoresizing mask on the interface builder (the red arrows below the x,y,height,width section on the right panel)
Please add LaunchScreen.storyboard in your project and set it as your Launch Screen under
Targets > General > App Icons and Launch Images > Launch Screen file.