Making view resize to its parent when added with addSubview - iphone

I'm having a problem when using addSubview.
Example code:
ParentView *myParentView = [[ParentView alloc] initWithNibName:#"ParentView " bundle:nil];
ChildeView *myChildeView = [[ChildeView alloc] initWithNibName:#"ChildeView" bundle:nil];
//... parent frame resized with setFrame lets say to x:0, y:0, W:320, H:411
[[myParentView view] addSubview: [myChildeView view]];
My child when added is bigger then the parent, and does not resize its frame to parent bounds. I can't use "clip subviews" on the parent, and "Autoresize Subviews" seems not to work if the parent frame is not resized again. Is there a property that makes a subview resize automatically to its parent's bounds without using setFrame on every child?

If you aren’t using Auto Layout, have you tried setting the child view’s autoresize mask? Try this:
myChildeView.autoresizingMask = (UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleHeight);
Also, you may need to call
myParentView.autoresizesSubviews = YES;
to get the parent view to resize its subviews automatically when its frame changes.
If you’re still seeing the child view drawing outside of the parent view’s frame, there’s a good chance that the parent view is not clipping its contents. To fix that, call
myParentView.clipsToBounds = YES;

Just copy the parent view's frame to the child-view then add it. After that autoresizing will work. Actually you should only copy the size CGRectMake(0, 0, parentView.frame.size.width, parentView.frame.size.height)
childView.frame = CGRectMake(0, 0, parentView.frame.size.width, parentView.frame.size.height);
[parentView addSubview:childView];

that's all you need
childView.frame = parentView.bounds

Tested in Xcode 9.4, Swift 4
Another way to solve this issue is , You can add
override func layoutSubviews() {
self.frame = (self.superview?.bounds)!
}
in subview class.

Swift 4 extension using explicit constraints:
import UIKit.UIView
extension UIView {
public func addSubview(_ subview: UIView, stretchToFit: Bool = false) {
addSubview(subview)
if stretchToFit {
subview.translatesAutoresizingMaskIntoConstraints = false
leftAnchor.constraint(equalTo: subview.leftAnchor).isActive = true
rightAnchor.constraint(equalTo: subview.rightAnchor).isActive = true
topAnchor.constraint(equalTo: subview.topAnchor).isActive = true
bottomAnchor.constraint(equalTo: subview.bottomAnchor).isActive = true
}
}
}
Usage:
parentView.addSubview(childView) // won't resize (default behavior unchanged)
parentView.addSubview(childView, stretchToFit: false) // won't resize
parentView.addSubview(childView, stretchToFit: true) // will resize

You can always do it in your UIViews - (void)didMoveToSuperview method. It will get called when added or removed from your parent (nil when removed). At that point in time just set your size to that of your parent. From that point on the autoresize mask should work properly.

Related

UIScrollView scrolls on all the simulators but not on my iPhone

So after figuring out how scrollView works, I've implemented it with the following code:
self.scrollView.delegate = self;
self.scrollView.userInteractionEnabled = YES;
CGRect view = CGRectMake(0, 0, 320, 750);
self.scrollView.contentSize = view.size;
The above code works as intended on ALL simulators in Xcode 6. However, when I run it my phone (iphone4s on ios7), the scroll does not function at all. Are people experiencing the same problems since the new release? Or am I missing something I've learned from the documentation?
Had the same issue here. Just need to resize the scrollview's frame size in viewDidLayoutSubviews which overrides auto layout.
-(void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
[scrollView setContentSize:CGSizeMake(320, 2600)];
// Adjust frame for iPhone 4s
if (self.view.bounds.size.height == 480) {
scrollView.frame = CGRectMake(0, 0, 320, 436); // 436 allows 44 for navBar
}
}
In AutoLayout
In general, Auto Layout considers the top, left, bottom, and right edges of a view to be the visible edges. That is, if you pin a view to the left edge of its superview, you’re really pinning it to the minimum x-value of the superview’s bounds. Changing the bounds origin of the superview does not change the position of the view.
The UIScrollView class scrolls its content by changing the origin of its bounds. To make this work with Auto Layout, the top, left, bottom, and right edges within a scroll view now mean the edges of its content view.
The constraints on the subviews of the scroll view must result in a size to fill, which is then interpreted as the content size of the scroll view. (This should not be confused with the intrinsicContentSize method used for Auto Layout.) To size the scroll view’s frame with Auto Layout, constraints must either be explicit regarding the width and height of the scroll view, or the edges of the scroll view must be tied to views outside of its subtree.
Note that you can make a subview of the scroll view appear to float (not scroll) over the other scrolling content by creating constraints between the view and a view outside the scroll view’s subtree, such as the scroll view’s superview.
Here are two examples of how to configure the scroll view, first the mixed approach, and then the pure approach
Mixed Approach
Position and size your scroll view with constraints external to the scroll view—that is, the translatesAutoresizingMaskIntoConstraints property is set to NO.
Create a plain UIView content view for your scroll view that will be the size you want your content to have. Make it a subview of the scroll view but let it continue to translate the autoresizing mask into constraints:
- (void)viewDidLoad {
UIView *contentView;
contentView = [[UIView alloc] initWithFrame:CGRectMake(0,0,contentWidth,contentHeight)];
[scrollView addSubview:contentView];
// DON'T change contentView's translatesAutoresizingMaskIntoConstraints,
// which defaults to YES;
// Set the content size of the scroll view to match the size of the content view:
[scrollView setContentSize:CGSizeMake(contentWidth,contentHeight)];
/* the rest of your code here... */
}
Create the views you want to put inside the content view and configure their constraints so as to position them within the content view.
Alternatively, you can create a view subtree to go in the scroll view, set up your constraints, and call the systemLayoutSizeFittingSize: method (with the UILayoutFittingCompressedSize option) to find the size you want to use for your content view and the contentSize property of the scroll view
Pure Auto Layout Approach
To use the pure autolayout approach do the following:
Set translatesAutoresizingMaskIntoConstraints to NO on all views involved.
Position and size your scroll view with constraints external to the scroll view.
Use constraints to lay out the subviews within the scroll view, being sure that the constraints tie to all four edges of the scroll view and do not rely on the scroll view to get their size.
A simple example would be a large image view, which has an intrinsic content size derived from the size of the image. In the viewDidLoad method of your view controller, you would include code similar to the code shown in the listing below:
- (void)viewDidLoad {
UIScrollView *scrollView;
UIImageView *imageView;
NSDictionary *viewsDictionary;
// Create the scroll view and the image view.
scrollView = [[UIScrollView alloc] init];
imageView = [[UIImageView alloc] init];
// Add an image to the image view.
[imageView setImage:[UIImage imageNamed:"MyReallyBigImage"]];
// Add the scroll view to our view.
[self.view addSubview:scrollView];
// Add the image view to the scroll view.
[scrollView addSubview:imageView];
// Set the translatesAutoresizingMaskIntoConstraints to NO so that the views autoresizing mask is not translated into auto layout constraints.
scrollView.translatesAutoresizingMaskIntoConstraints = NO;
imageView.translatesAutoresizingMaskIntoConstraints = NO;
// Set the constraints for the scroll view and the image view.
viewsDictionary = NSDictionaryOfVariableBindings(scrollView, imageView);
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[scrollView]|" options:0 metrics: 0 views:viewsDictionary]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[scrollView]|" options:0 metrics: 0 views:viewsDictionary]];
[scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[imageView]|" options:0 metrics: 0 views:viewsDictionary]];
[scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[imageView]|" options:0 metrics: 0 views:viewsDictionary]];
/* the rest of your code here... */
}
I did not try Vishu's answer, but what I did was update to iOS 8 so it's compatible with Xcode 6 and it worked!

View isn't rotating properly

I have this code inside a UIViewController subclass:
- (id)init {
self = [super init];
if (self) {
self.view.frame = [PDToolbox screenFrame];
self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
self.view.backgroundColor = [UIColor redColor];
}
return self;
}
The only thing I have in terms of any rotation methods is this:
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
return YES;
}
Yet after the screen is rotated to landscape, doing an NSLog on the view shows this:
<UIView: 0x10061640; frame = (0 0; 320 480); transform = [0, -1, 1, 0, 0, 0]; autoresize = W+H; layer = <CALayer: 0x10061670>>
I don't understand why it's doing this transform thing, and not just rotating like normal? It means any views i place on top of it after the rotation and set to be the size of the view end up at a 320x480 position.
EDIT:
People aren't understanding. So I put a view on top of it, the same size as the UIView, using:
UIView *anotherView = [UIView alloc] initWithFrame:controller.view.bounds];
[controller.view addSubview:anotherView];
If I add anotherView in in portrait, anotherView appears in portrait, with the frame 320x480.
If i add anotherView in in landscape, anotherView appears in landscape, but still with the frame 320x480, becaus that's what the controller.view's frame is still, for some unknown reason.
What does your view/controller hierarchy look like? It looks to me like something is setting a 90° rotation transformation on your view, rather than changing the view's frame. If you're not doing that yourself, it's likely a parent view or view controller.
Frame and bounds are very different things. You should read Apple's guide to View Geometry - it contains a lot of information that's been invaluable to me.
Your bounds is always going to be 320x480 because someone is setting your transform (which affects the frame, but not the bounds).
Make sure your view controller's view's superview has autoresizesSubviews set to YES and that any subviews added have appropriate autoresizingMasks.

Convert UIViewController to UIScrollViewController

I am new to iPad developer,
I made one Registration form in my application, when i see my application in Portrait mode,
i am able to see whole form with no scrolling, but when i see same form in Landscape mode, i am not able to see part which is at bottom of page, for that a scrolling should be there to see bottom part.
:
In my .h file when i replace
#interface ReminderPage : UIViewController{
...
...
}
:UIViewController with :UIScrollView
and then when i add label in my .m file like this,
UILabel *Lastpaidlbl = [[[UILabel alloc] initWithFrame:CGRectMake(70 ,400, 130, 50)]autorelease];
Lastpaidlbl.backgroundColor = [UIColor greenColor];
Lastpaidlbl.font=[UIFont systemFontOfSize:20];
Lastpaidlbl.text = #"Lastpaid on :";
[self.view addSubview:Lastpaidlbl];
I am getting error on last line Property view not found on object of type classname.
i am unable to add label in my view.
Any help will be appreciated.
The question appears to be really asking how can all the components on the screen be placed inside a UIScrollView, rather than a UIView. Using Xcode 4.6.3, I found I could achieve this by simply:
In Interface Builder, select all the sub-views inside the main UIView.
Choose Xcode menu item "Editor | Embed In | Scroll View".
The end result was a new scroll view embedded in the existing main UIView, will all the former sub-views of the UIView now as sub-views of the UIScrollView, with the same positioning.
If you want to replace your UIViewController with a UIScrollView, you will have to go a bit of refactoring to your code. The error you get is just an example of that:
the syntax:
[self.view addSubview:Lastpaidlbl];
is correct if self is a UIViewController; since you changed it to be UIScrollView, you should now do:
[self addSubview:Lastpaidlbl];
You will have quite a few changes like this one to make to your code and will face some issues.
Another approach would be this:
instantiate a UIScrollView (not derive from it);
add your UIView (such as you have defined it) to the scroll view;
define the contentSize of the scroll view so to include the whole UIView you have.
The scroll view acts as a container for your existing view (you add your controls to the scroll view, then add the scroll view to self.view); this way, you could integrate it within your existing controller:
1. UIScrollView* scrollView = <alloc/init>
2. [self.view addSubview:scrollView]; (in your controller)
3. [scrollView addSubview:<label>]; (for all of your labels and fields).
4. scrollView.contentSize = xxx;
I think the latter approach will be much easier.
Please put all of your UIComponents to the UIScrollview and then it will start scrolling.
please look in to content size. please change it according to the orientation of device.
You're subclassing UIScrollView, so there is no self.view because already self is the view (of the scrollview). You dont need to subclass the scrollview, you can just embed your components in a ivar scrollview and set its contentSize (in your case, you have to enable the scrolling just when the device is in landscape mode). In interface builder you can embed the selected elements in one click, Editor-> Embed in-> scrollview.
First create scrollview
UIScrollView * scr=[[UIScrollView alloc] initWithFrame:CGRectMake(10, 70, 756, 1000)];
scr.backgroundColor=[UIColor clearColor];
[ self.view addSubview:scr];
second
change [self.view addSubview:Lastpaidlbl];
to
[scr addSubview:Lastpaidlbl];
third
set height depends on content
UIView *view = nil;
NSArray *subviews = [scr subviews];
CGFloat curXLoc = 0;
for (view in subviews)
{
CGRect frame = view.frame;
curXLoc += (frame.size.height);
}
// set the content size so it can be scrollable
[scr setContentSize:CGSizeMake(756, curXLoc)];
Finally
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Override to allow orientations other than the default portrait orientation.
if (interfaceOrientation==UIInterfaceOrientationLandscapeLeft || interfaceOrientation==UIInterfaceOrientationLandscapeRight) {
self.scr.frame = CGRectMake(0, 0, 703,768);
} else {
self.scr.frame = CGRectMake(0, 0, 768, 1024);
}
return YES;
}

Need UIView to autoresize

I have made a custom UIView which is shown when the user hits a button in the navigationbar. I make my view's in code. In my loadview I set the autoresizing masks and the view loads correct on screen. However the UIView which is shown when the user taps the button does not resize even when I have set the autoresizing masks.
UIView *blackView = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 416.0)];
blackView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
Do I need to use self.view.frame.size.width and self.view.frame.size.height instead? And if I do why? Does not resizing masks work outside of loadView?
Thank you for your time:)
the autoresizingMask affects how a view will behave when its superviews frame changes. if all you are doing is showing theblackViewwhen you tap a button, thenblackView` will have whatever frame you initially set for it.
If this isn't enough info, please post some more code around how you are configuring and displaying blackView and it's superview and explain more about what situations you are expecting blackView to resize in. Rotation is one of them, if that's what you're concerned with.
First things first, I hope you've done this:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
Let's say the view that needs resizing is: view2
The view that has view2 as a subview is: view1
While creating view1 you would declare it as:
view1 = [[UIView alloc] init];
[view1 setNeedsLayout];
Now in view1's .m file you need to overload the layoutSubviews method as shown:
- (void)layoutSubviews
{
CGRect frame = view2.frame;
// apply changes to frame
view2.frame = frame;
}
In case view1 is a view controller's view, you need to do that same thing as above in the willRotate method as shown
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
[super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
CGRect frame = view2.frame;
// apply changes to frame
view2.frame = frame;
}
This is a tried and tested method that I use to handle orientation changes.

How to make a subview automatically resize with its superview?

I have a view which contains one sub-view; this sub-view itself contains another sub-view, which is meant to be slightly smaller than its superview.
I am creating the first subview full-screen size then shrinking it to a very small size on the screen. When the subview is tapped, I animate it from its small size to full-screen.
The problem is that my second subview never resizes itself during this animation - it is always rendered full-size and overflows the bounds of its superview.
Is there a simple way to get a subview to keep itself sized proportionally as its superview changes size?
you could add the autoresizing-behavior programmatically
Objective-C
subview.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
Swift 3.x
subview.autoresizingMask = [.flexibleWidth, .flexibleHeight]
Swift 2.x
subview.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
In Interface-Builder navigate to tab 3 and click on the arrows in the middle ;D
Another workaround could be to implement the setFrame-method and always adapt it to the size of the superview (not the given frame.size). Don't forget to set up the origin as you need it.
- (void) setFrame:(CGRect)frame
{
CGRect rect = self.superview.frame;
rect.origin.x = 0;
rect.origin.y = 0;
[super setFrame:rect];
}
this does the trick for me
subview.frame = subview.superview.bounds;
If you're using only [.flexibleWidth, .flexibleHeight] for your autoresizing mask, your subview will not get resized proportionally. The right answer is:
autoresizingMask = [.flexibleWidth, .flexibleHeight, .flexibleTopMargin, .flexibleLeftMargin, .flexibleBottomMargin, .flexibleRightMargin]