iOS UIView Not Resizing Subviews? - ios

I'm loading a view from a storyboard programatically, but there's an issue with my subview heights (I'm using Autoresize Subviews etc).
When the view loads, the main UIView appears to be the correct size, but the subviews that depend on the constraints to dynamically calculate their final height don't seem to be resizing from the sizes they were set at in interface builder.
Loading the view like so:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
ApplicationRecordingViewController* recordingController = (ApplicationRecordingViewController*)[storyboard instantiateViewControllerWithIdentifier:#"recordView2"];
[self presentViewController:recordingController animated:NO completion:nil];
Orange area's height is from top of main view to top of grey area. Grey area is fixed height
The strange thing is, if I set the simulated size in interface builder as the correct view for my phone, the sizes work out. I guess the initial heights for subviews are 'baked' into the view, but then (usually) resized when the view actually loads?
Note: The orange area should be completely filled by the camera view I'm loading into it.
Incorrect height
Correct height if I change simulated layout
Would love to know what I'm doing wrong!
Edit 1: Constraints
Camera is the orange bit. The Camera bottom constraint is currently set as the bottom of the view + enough room for the gray bar. Have also tried setting the bottom to match the top of the gray bar!
Link to Storyboard with Scene

I know you're all better than me, but I experienced the same in my last project. My Camera View inside a UIView is not in full screen or resizing and fitting the whole UIView, and I also posted it on my daily blog.
Implement viewDidLayoutSubviews -- Inside that method, layout again your video preview layer.Do not alloc init anything inside that method, just re-layout your views. After that, your video preview will fill the height and width of its parent, or whatever you've been targetting.
The issue also has something to do with the hierarchy of the constraints and views.

You already got the answer.
'if I set the simulated size in interface builder as the correct view for my phone, the sizes work out.'
You may call some functions to get height in viewDidLoad or viewWillAppear.
Change Code like this
- (void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.view setNeedsLayout];
[self.view layoutIfNeeded];
CGFloat height = [self getHeight];
}
or
- (void) viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
CGFloat height = [self getHeight];
}

As i can see in your storyboard constrain you have set bottom space to bottom layout guide 150 . i think this is the issue . if you give fixed height to bottom view then no need to set constant as from bottom layout guide --> 150 .
Your old constrain :- >
Just set bottom space of orangeview from greenview = 0.
Check new constrain ,
Here is your storyboard link ,
Storyboard Download link
Here is your output,

After investigating the layout a little more, I found the camera view (orange) seemed to be the correct size, but the live camera preview wasn't.
Solution was to move the camera library (SCRecorder)'s init method into viewDidAppear (was in viewDidLoad before).
My thinking is iOS doesn't autolayout the camera preview view in the same way as normal UIViews, etc.
#interface ApplicationRecordingViewController () {
SCRecorder *_recorder;
}
#end
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
_recorder.previewView = _previewView;
}

Perhaps you can try to get rid of these two hook.

Related

IOS - UIScrollView Refusing to scroll

I have built a large IOS app and whilst testing noticed that a uiScrollview within a static page has stopped scrolling - to explain the setup of the page - the structure is as follows -
the scrollview is connected to the header file as scwollMa (as in above doc).
it has the following properties in storyboard -
I have applied the following into the .m page -
- (void)viewDidLoad
{
[super viewDidLoad];
//Set Scroller
[_scwollMa setScrollEnabled:YES];
self.scwollMa.contentSize = CGSizeMake(320, 1100);
Yet it does nothing! no error either - big head scratcher! Any advice at all?
You have set the height of the scrollview at the same height as the content size. To scroll set the height of the scroll view to fit into the visible screen area (like self.view.frame.size.height).
If the scroll view and the content view have the same height, there's nothing to scroll for.
contentSize.Height must be greater to actual.height:
Change the following line of code to
self.scwollMa.contentSize = CGSizeMake(320, 1500);
will work for you.
and in interface builder keep height which is visible inside your view.

imageView centered inside scrollView

How can I vertically center an image inside a scrollView?
I'm using storyboards in Xcode 5. The main view is embedded inside a navigation controller, and "Adjust scroll view insets" option is enabled in main Storyboard. This main view has a scrollView which size is equal to the main view size.
The imageView is inside the scrollView and it's the same size as the scrollView. Content mode is set to AspectFit.
So, hierarchy is as follows:
- UINavigationController
- UIView
- UIScrollView
- UIImageView
The image may be landscape or portrait, and can be any size (it's loaded at runtime). This is why imageView is the same size as the scrollView.
How can I vertically center the image inside the scrollView?
EDIT:
As commented before, I have set imageView's contentMode to AspectFit because the image may be too big, so I need it resized. The problem I have is that the image is not center of the scrollView.
You can check screenshot at link and download source code at link.
It will be good to use auto layout as mentioned by #Douglas. However, if you prefer the traditional way, you can also make it work.
I'll first give you the answer and then explain it to you. You should first delete the image view from the storyboard ( I'll explain it later), and then add the viewWillAppear method.
- (void)viewDidLoad
{
[super viewDidLoad];
// 1. Add the image view programatically
UIImageView * imageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:#"portrait.jpg"]];
[_scrollView addSubview:imageView];
_imageView = imageView;
}
- (void)viewWillAppear:(BOOL)animated
{
// 2. calculate the size of the image view
CGFloat scrollViewWidth = CGRectGetWidth(_scrollView.frame);
CGFloat scrollViewHeight = CGRectGetHeight(_scrollView.frame);
CGFloat imageViewWidth = CGRectGetWidth(_imageView.frame);
CGFloat imageViewHeight = CGRectGetHeight(_imageView.frame);
CGFloat widthRatio = scrollViewWidth / imageViewWidth;
CGFloat heightRation = scrollViewHeight / imageViewHeight;
CGFloat ratio = MIN(widthRatio, heightRation);
CGRect newImageFrame = CGRectMake(0, 0, imageViewWidth * ratio, imageViewHeight * ratio);
_imageView.frame = newImageFrame;
// 3. find the position of the imageView.
CGFloat scrollViewCenterX = CGRectGetMidX(_scrollView.bounds);
CGFloat scrollViewCenterY = CGRectGetMidY(_scrollView.bounds) + _scrollView.contentInset.top / 2 ;
_imageView.center = CGPointMake(scrollViewCenterX, scrollViewCenterY);
}
Here is the explanation:
You should not put the imageView in the storyboard, otherwise the frame of the imageView will be fixed by the storyboard, and will not change with the size of the image. Even if you choose UIViewContentModeScaleAspectFill, the frame of the imageView is still not changed. It just add some white space around the image.
Now the imageView has the same size as your image. If you want it to be fully displayed, you need to calculate the frame yourself.
Pay attention to the _scrollView.contentInset.top / 2, this is why you need to put the codes in viewWillAppear instead of viewDidLoad. The _scrollView.contentInset.top is the height of the navigation bar and is calculated automatically for you before willViewAppear.
You put your image view in a scrollView, I guess you want to zoom in and out. If this is true, add self.imageView = imageView; and the bottom of viewDidLoad. Set the delegate of _scrollView to self and add the following method:
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return _imageView;
}
I made a comment, but then took a look at your project. You are almost there. I ran through the following steps and have gotten the result you are looking for.
First, make sure you have auto layout turned ON!!!
In your storyboard click on your scroll view. You had a scroll view that was the same size as the view. You are going to put on some constraints. Down at the bottom of the story board you will see some icons.
The fourth one over looks sort of like an I-beam on its side, it is the pin button. After selecting the scroll view, click on this and it will bring up a pop up menu.
For the scroll view click on all the bars around the middle block so you pin the scroll view to the sides of the main view.
You will notice they are all red now.
Then go and click on the imageview. Once again you had it set to the size of the view. Using the pin button again, you are going to pin just the Width at 320 and the Height at 568. When you are done you are then going to use the next button over.
This is the align button. Click on that after you have selected your image view. You are going to click on Horizontal Center in Container, and Vertical Center in Container.
Next you will need to add one method to your ViewController.m file.
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
[_scrollView setContentSize:CGSizeMake(self.view.frame.size.width, self.view.frame.size.height)];
}
Start up the simulator and let her rip! You will get one warning though. It says the content size is ambiguous for the scroll view. But that's OK, because you will set it on viewDidLayoutSubviews.
Hope that helps, or helps someone out. Autolayout and scroll views are a bit tough!!
EDIT#1
if you want to then make the image view scalable, by pinch zooming you can do the following.
Make sure you made the .h file follow the UIScrollViewDelagate.
#interface ViewController : UIViewController <UIScrollViewDelegate>
This will allow the scroll view to be able to access the delegate methods of the scroll view. The method you are looking for is called..
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return self.imageView;
}
Then in the viewDidLoad method of your .m file do the following.
_scrollView.minimumZoomScale = 0.5;
_scrollView.maximumZoomScale = 4.0;
_scrollView.delegate = self;
The underscore and the variable name is the same as self.variable. Either will work.
That should do it. Let me know if it works or if you have any other questions. ENJOY!
These are the ones u can use, the 3 modes of ImageView content display.You can do this by dynamically setting them or u can set them in storyboard too, click on the ImageView and go to properties tab-bar and choose from there, run them and select which output u want.
imageView.contentMode = UIViewContentModeScaleAspectFit;
imageView.contentMode = UIViewContentModeScaleToFill;
imageView.contentMode = UIViewContentModeScaleAspectFill;
Hope this helps
If you want to center image in an imageview use
imageView.contentMode=UIViewContentModeCenter;
image retains it's size in this this content mode. Alternatively you can use other content modes as per your requirement.
UIViewContentModeScaleToFill,
UIViewContentModeScaleAspectFit, // contents scaled to fit with fixed aspect. remainder is transparent
UIViewContentModeScaleAspectFill, // contents scaled to fill with fixed aspect. some portion of content may be clipped.
UIViewContentModeRedraw, // redraw on bounds change (calls -setNeedsDisplay)
UIViewContentModeCenter, // contents remain same size. positioned adjusted.
UIViewContentModeTop,
UIViewContentModeBottom,
UIViewContentModeLeft,
UIViewContentModeRight,
UIViewContentModeTopLeft,
UIViewContentModeTopRight,
UIViewContentModeBottomLeft,
UIViewContentModeBottomRight,

UITableView Header Gap and Resizing Programmatically

I have two questions related to UITableViews.
1) The first one is, what is the gap at the top of the UITableView? My app always starts with the top cell not flush with the top of the tableview (as shown in the second image), it starts about one cell lower, i.e. where that gap is in the interface builder. I can't find where that is coming from, or why.
2) I can't seem to resize the uitableview programmatically, I'm trying to reduce the height after a popup appears. I've shown an example of it not working in the second picture.
Here is (an example of) what I am trying at the moment:
- (void)viewDidLoad
{
[super viewDidLoad];
self.table_view.delegate = self;
CGRect tableBounds = self.table_view.bounds;
tableBounds.size.height -= 100;
self.table_view.bounds = tableBounds;
CGRect tableFrame = self.table_view.frame;
tableBounds.size.height -= 100;
self.table_view.frame = tableFrame;
}
Thanks!
UITableView Selected:
Simulation:
In your xib (or storyboard) put your UITableView at position (0,0). ( the same position as the navigation bar).
The first image shows that your table view has problems even in Interface Builder. It looks as if you've set the top inset incorrectly; check your edge insets.
The reason your resizing code is not working is probably that it is too early (viewDidLoad); put it in viewDidAppear: and see if that works, and if it does, try moving it back to viewWillAppear: so the user doesn't see the resizing. If it doesn't work, it might be because you're using auto layout; you can't manually alter the frame of something whose frame is dictated by auto layout. (Your resizing code is also silly; you want to set the frame, not the bounds.) But it might also be because you're using a UITableViewController in a UINavigationController; if you do that, the table view is under the navigation controller's direct control and its size is not up to you.

Vertical centering view, autoresizing and iPhone 5 4" screen

I have some custom buttons I add to the view in -viewDidLoad. I want them centered vertically inside the view, like so:
self.customButton.center = CGPointMake(98.f, self.view.center.y);
However, the view height is 504.0 even on a 3.5" device, where I expect it to be 416 (480 - 20 (status bar height) - 44 (nav bar height)).
The view in xib is using "Retina 4 Fullscreen", but setting it to freeform does not help. I certainly don't want two xibs just to account for the height difference.
I know I can use UIScreen but I would prefer that the view be aware of the height difference.
EDIT: the odd thing is, in -viewWillAppear, view height is correctly set to 416.0. Why this isn't handled after [super viewDidLoad] is beyond me.
How are people handling this? Autolayout would probably handle this but I need a iOS5 compatible method. Can autoresizing handle "centering" somehow?
You don't have Autolayout in iOS5, but you do still have the autoresizing mask. If you center a view vertically in IB, go to the inspector and deselect the vertical struts and springs in the autolayout masks, the view will stay centered vertically on both 4" and 3.5" screens.
Or you can do this in code in your viewDidLoad method. Just center the view as you are now and set the autoresizingMask like this:
self.customButton.autoresizingMask = (UIViewAutoresizingFlexibleBottomMargin | \
UIViewAutoresizingFlexibleTopMargin);
EDIT: the odd thing is, in -viewWillAppear, view height is correctly set to 416.0. Why this isn't handled after [super viewDidLoad] is beyond me.
Because resizing the view is not part of loading the view! -viewDidLoad gets called from -view in a method that probably looks a bit like this:
-(UIView*)view
{
if (!_view)
{
[self loadView];
[self viewDidLoad];
}
return _view;
}
-(void)loadView
{
// Some code to load the view from a nib/storyboard...
}
The view will get resized with a call like yourViewController.view.frame = ..., but this can only happen after the view is loaded (and thus after -viewDidLoad is called).
Set some autoresizing masks. That's what they're there for.

Why is a view not filling the entire frame of a scroll view?

thank you for reading. I appreciate any insights you could share.
I have scroll view. I call it myTopScrollView.
This scroll view has a width of 1024 pts and a height of 340 pts.
It draws the subview of another view controller, which I dragged into Storyboard from the objects library. I identify this view controller as topScrollViewPage1.
I go to the Size Inspector to specify a Frame Rectangle with the width of 1024 pts and a height of 340 pts (see Figure 1)
// Point to the main storyboard.
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
// Point to the first scroll view for myTopScrollView.
UIViewController *myViewController = [storyboard instantiateViewControllerWithIdentifier:#"topScrollViewPage1"];
// Add the subview to the scroll view.
[self.myTopScrollView addSubview:myViewController.view];
// Define the content size - width and height.
self.myTopScrollView.contentSize = CGSizeMake(1024, 340);
// Add the scroll view to the view.
[self.view addSubview:self.myTopScrollView];
Now, it compiles successfully, and it loads.
However, the subview with a red background does not fill the entire width of the scroll view frame, even though the four buttons I used to mark the four corners of the subview are drawn exactly where I put them in Storyboard (see Figure 2).
The question is why?
Interestingly, the subview's red background stops at 768 pts (the width length of an iPad in portrait orientation).
This leads me to think maybe this is a default value of a drawing property in a UIView or UIViewController class. I am still checking but nothing yet.
Do you know the why the view background is not filling the entire width of the scroll view (even though I specified the contentSize of the scroll view to be the entire width of 1024 pts)?
Ok, the answer has to do with the view controller with identifier, "topScrollViewPage1".
The "Frame Rectangle" size of the view in this view controller was still in the default value.
To change the size of the view, highlight the view controller, go to "Attributes Inspector", under "Size", change "Inferred" to "Freeform".
This will let you change the frame size of the view inside this view controller.

Resources