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..
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 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.
I've searched a lot about how can I determine the actual view size dynamically in the viewDidLoad method.
Here is my approach which seems to be work on both iOS6 and iOS7 with both Landscape and Portrait mode.
Is there a better solution for that?
Here is my code:
- (CGSize)actualSize {
CGFloat widht;
CGFloat height;
// Determin height and widht
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
if (orientation == UIDeviceOrientationLandscapeRight || orientation == UIDeviceOrientationLandscapeLeft) {
widht = kHeightSelfView;
height = kWidthSelfView;
} else {
widht = kWidthSelfView;
height = kHeightSelfView;
}
// Determin navigationbar height
CGFloat navigationBarHeight = self.navigationController.navigationBarHidden ? .0f : (MIN(self.navigationController.navigationBar.frame.size.height, self.navigationController.navigationBar.frame.size.width));
// Determin navigationbar height
CGFloat statusbarHeight = [DeviceCompatibility isIOS7] ? (MIN(SharedApplication.statusBarFrame.size.width, SharedApplication.statusBarFrame.size.height)) : .0f;
return CGSizeMake(widht, height - navigationBarHeight - statusbarHeight);
}
Typically you should only perform view-based geometry in viewWillAppear. Your view's frame is not yet set in viewDidLoad, but it will be set correctly before viewWillAppear is called.
Instead of picking height & width, you can pick the frame of view like this:
// Adjusts the frame of the child view.
CGRect frame = self.view.frame;
CGRect linkedFrame = scene.view.frame;
linkedFrame.origin.x -= frame.origin.x;
linkedFrame.origin.y -= frame.origin.y;
and then you can make them flexible so that they will resize properly :
// The scene's main view must be made flexible so it will resize properly
// in the container.
scene.view.autoresizingMask = (UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleHeight);
Let me know if this is not what you need :)
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.
I am writing an iPad app that needs to know the usable area of the view for drawing purposes. The view is added into a Navigation controller, so I have the status bar plus the navigation controller both taking up a certain number of pixels. My app happens to be in landscape mode, although I don't think that's relevant.
I am able to get the correct view size AFTER rotation using didRotateFromInterfaceOrientation. But I can't figure out how to do it without the screen being rotated.
- (void) didRotateFromInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
[self.view setFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
NSLog(#"drfi %d %d", (int)self.view.frame.size.width, (int)self.view.frame.size.height);
}
^^ that works after rotation. Not before. Can't figure out how to get accurate numbers. And I REALLY don't want to hard wire this.
I will also need this function to be device independent -- it should work on the NEW iPad as well as the older iPad resolutions. I can handle the scaling issues once I know the exact usable area. Why is this so hard? Help!!
I don't think you need to specify your frame's view within the didRotateFromInterfaceOrientation what i will suggest instead is setting some properties to your view autoresizing mask so that it automatically resize itself according to your view orientation.
By setting this for example to your view when your view is loaded (viewDidLoad method):
self.view.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
you specify that your view will change its width and height automatically and can get the right values you need to get from there.
You should read this: http://developer.apple.com/library/ios/#documentation/WindowsViews/Conceptual/ViewPG_iPhoneOS/CreatingViews/CreatingViews.html#//apple_ref/doc/uid/TP40009503-CH5-SW1
for a better understanding of views in iOS
EDIT
Also you probably want to spot what is the orientation of your device which can be accomplish with [[UIApplication sharedApplication] statusBarOrientation];
Your application looks like: there is a start up view, then in this view you will load and add a main view into window, right? Then you should do as below in your main view:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
CGRect frame = self.view.frame;
frame.origin.y = frame.origin.y + 20.0;
self.view.frame = frame;
}
return self;
}
Try this.
CGRect frame = [UIScreen mainScreen].bounds;
CGRect navFrame = [[self.navigationController navigationBar] frame];
/* navFrame.origin.y is the status bar's height and navFrame.size.height is navigation bar's height.
So you can get usable view frame like this */
frame.size.height -= navFrame.origin.y + navFrame.size.height;
You can get this dynamically by combining an instance method with a category method:
Instance method:
This assumes that your view controller (self) is embedded within a navigation controller.
-(int)getUsableFrameHeight {
// get the current frame height not including the navigationBar or statusBar
return [MenuViewController screenHeight] - [self.navigationController navigationBar].frame.size.height;
}
Class category method:
+(CGFloat)screenHeight {
CGFloat screenHeight;
// it is important to do this after presentModalViewController:animated:
if ([[UIApplication sharedApplication] statusBarOrientation] == UIDeviceOrientationPortrait ||
[[UIApplication sharedApplication] statusBarOrientation] == UIDeviceOrientationPortraitUpsideDown){
screenHeight = [UIScreen mainScreen].applicationFrame.size.height;
} else {
screenHeight = [UIScreen mainScreen].applicationFrame.size.width;
}
return screenHeight;
}
The above will consistently give you the usable frame height after the status bar and navigation bar have been removed, in both portrait and landscape.
Note: the class method will automatically deduct the 20 pt for the status bar - then we just subtract the navigation header variable height (32 pt for landscape, 44 pt for portrait).