a UIScrollView works just fine by it's self (in IB). However, once you put the UIScrollView inside of a UIVIew in IB, it no longer works. I'm doing this with no subclassing so what's the deal?
Answer
You have to make sure Autoresize Subviews is checked on the containing UIView.
The next part is a bit of a hack. You need to assign a new frame to the containing UIView as well. However, the new frame CANNOT be the pre-existing size of your UIView. It must be a different size for this to work.
If you want the size contained on your UIView in InterfaceBuilder then you need to do something like this:
self.frame = CGRectMake(0,0,0,0);
self.frame = [put your desired rect size here];
Have you tried returning NO in touchesBegan if the touch falls inside your scroll view's frame?
Edit:
Make sure you set the scroll view's content size ([[self scrollView] setContentSize:CGSizeMake(320,480)]; - the values do not matter) and make sure you check "Bounce Horizontally" and/or "Bounce Vertically" (depending on which you want) as well as "Bounces":
Have you tried to set contentsize property of UiScrollView like this
self.scrollView.contentSize=CGSizeMake(320,860);
Related
My viewController has one view with images and labels and one textView
Im new in objective c.
My problem is to add ScrollView in my ViewController with 2 custom views(UIView and UITextView).(image in the link) I have tried many things posted here in Stack but nothing works for me.
Thank YOU!
Here is what i have :
self.scrollView.contentSize=self.scrollView.frame.size;
self.scrollView.frame=self.view.frame;
[self.view addSubview:self.scrollView];
Adjusting view's frame was the technology of 5 years ago. You should never set the frame manually, not anymore. Instead start learning Autolayout and Constraints.
These tutorials may help:
https://www.raywenderlich.com/115440/auto-layout-tutorial-in-ios-9-part-1-getting-started-2
https://www.appcoda.com/auto-layout-guide/
You are setting the content size equal to the frame size before you actually set the frame, so it's probably just 0.
You need to just switch the calls around:
self.scrollView.frame=self.view.frame;
self.scrollView.contentSize=self.scrollView.frame.size;
[self.view addSubview:self.scrollView];
The other thing to keep in mind is that because you are setting the frame of a nested view to the frame of its superview, your layout will break (or at least not do what you expect), if the origin of your superview ever changes. If the origin is 0, 0, then you are fine for the moment, but otherwise you may want to set the subview (scrollView) frame to be equal to the superview (self.view) bounds instead of the frame, like this:
self.scrollView.frame=self.view.bounds
I'm facing very weird issue, I have UIView grandWrapper namely in which I'm adding many subviews now when i animate the height of my grandWrapper to zero, ideally height of grandWrapper should be zero and all the inner views should disappear since they were existing inside that grandWrapper View but It animates the height to zero and all the subviews are still there. Can anyone help?
P.s. Im creating subviews programmatically. Thanks in advance
Make subview's autoresizingMask property contains UIViewAutoresizingFlexibleHeight if you want the subviews resize its height according to their parent's height.
Or you can set the view's clipsToBounds property to YES.
Little bit confused from your question
1.If you want to remove your grandWrapper sub views then call below function
-(void)clearReportContent
{
if(grandWrapper!=nil)
[[grandWrapper subviews] makeObjectsPerformSelector: #selector(removeFromSuperview)];
}
2.If sub views are appearing on screen when you do the grandWrapper height to zero,
then set grandWrapper.cliptoBounds=YES; at start where you add the sub view on grandWrapper.
My app has a UIView called stepView that needs to grow and shrink, always expanding down and to the right, and always shrinking up and to the left. It has a subview, durationLabel, which runs along the entire width of the stepView and has a fixed height.
When the stepView is animated to grow larger, the label grows properly along with it: the text and the label's background slide to the right in sync with the growing stepView. However, when the stepView is animated to grow smaller, it immediately snaps to its new size, leaving a gap between the stepView's shrinking right edge and its right edge until the animation completes.
The label initialization code in stepView.m:
CGRect duration_frame = CGRectMake(0, 0, self.frame.size.width, HEADER_HEIGHT);
self.durationLabel = [[UILabel alloc] initWithFrame:duration_frame];
[self.durationLabel setAutoresizingMask:UIViewAutoresizingFlexibleWidth];
[self addSubview:self.durationLabel];
And the animation code:
[UIView animateWithDuration:ANIM_DURATION
animations:^{
[stepView setFrame:newFrame];
}
];
Using bounds/center instead of frame produces the same effect. I've considered using a transform instead, but the code for calculating "newFrame" is somewhat involved, so I'd rather avoid rewriting it if possible. I've also tried manually changing the label's frame in the same animation block, but that simply makes it disappear entirely (possibly because I was trying to animate both a view's frame and its subview's frame in the same animation block?). I've also confirmed stepView and its subviews aren't undergoing any other animations at the same time, although there are animations happening to unrelated views in separate animation blocks.
I'm at a loss for why the label should animate perfectly when the stepView grows but fail to animate at all when it shrinks. I haven't seen anything in the documentation that indicates there would be a difference. Thank you for any help you can provide.
I think this is an issue with UILabel - using another UIView as subview instead of an UILabel the animation works fine also when you shrink.
If I understand correctly what you need to obtain as result, however, I would suggest you to try the following:
don't set the autoresizingMask property
// [self.durationLabel setAutoresizingMask:UIViewAutoresizingFlexibleWidth];
set the stepView clipToBounds property to YES
self.clipToBounds = YES;
This way the UILabel frame will not change but only the part which is actually within the stepView bounds will be visible. I hope this might help.
Update: just done a quick research and found that the question is already answered here resize uiview with UILabel and animate it correctly - the answers provided seem to be aligned to what I've suggested above.
I've got a UIViewController with an iPad xib in portrait orientation. When my iPad is in landscape orientation and I put that view controller into my UISplitViewController's detail pane, it gets automatically resized to fit which is great.
However, when I'm configuring my views in -viewDidLoad, the final size of the views is not yet in landscape orientation/size.
The -didRotateFromInterfaceOrientation: method and the other methods associated with it do not get called when the UIViewController is loaded already in landscape, so when and where am I able to properly set the contentSize of the scroll view and it's contents?
I only want my scroll view to scroll vertically, so I want to make sure that my contentView inside the scrollView is re-fit to the width of the view controller in whatever orientation it is in.
No matter what .frame or .bounds I check, whether it's on my view, my scroll view, or even the detail view controller of my SplitViewController show me what my ACTUAL size is. When in landscape using a UISplitViewController, the left hand side is 320px wide which means the right hand side shouldn't be more than 704px wide, but whenever I check the frames and the bounds of my view and my scrollview, they report as 768px wide which is not correct.
My scrollview is CLEARLY only 704px wide because I can see the scroll indicators correctly.
What am I missing?
Here is my code in -viewDidLoad...
CGSize textSize = [self.purchase.textDescription sizeWithFont:self.labelTextDescription.font constrainedToSize:allowedSize lineBreakMode:UILineBreakModeWordWrap];
CGRect textFrame = self.labelTextDescription.frame;
textFrame.size.height = textSize.height;
self.labelTextDescription.frame = textFrame;
CGRect contentFrame = self.contentView.frame;
contentFrame.size.height += textSize.height;
if (contentFrame.size.width > self.scrollView.frame.size.width) {
contentFrame.size.width = self.scrollView.frame.size.width;
}
self.contentView.frame = contentFrame;
[self.scrollView addSubview:self.contentView];
self.scrollView.contentSize = self.contentView.frame.size;
The proper time to lay out your views and set your scroll view's contentSize is during the layout phase of the run loop. During this phase, UIKit sends the layoutSubviews message to any view that has been marked as needing layout and is in a window. A view is automatically marked as needing layout when various things happen, including when it is first added to a window hierarchy, when it is given a new subview, and when its size changes. You can also manually mark a view as needing layout by sending it the setNeedsLayout message.
By the time a view receives the layoutSubviews message, UIKit has already sent layoutSubviews to any of the view's ancestors (its superview and up) that needed it, and it has already had its frame adjusted based on its autoresizing mask or autolayout constraints, and its own subviews' frames have already been adjusted based on their autoresizing masks or autolayout constraints.
If self.view is already a custom subclass of UIView, the best approach is simply to override layoutSubviews in that class. Put your layout code there, and set the scroll view's contentSize there.
If you're not using a custom subclass, and you don't want to create one, then you can do the layout in your view controller's viewWillLayoutSubviews or viewDidLayoutSubviews method, if you're deployment target is iOS 5.0 or later. You can probably guess when these messages are sent. :)
During autorotation, all of these messages (layoutSubviews, viewWillLayoutSubviews, and viewDidLayoutSubviews) are sent inside the autorotation's animation block, so if you do your layout in one of these methods, you also get the benefit that the changes to your layout will be animated during the autorotation animation.
First of all, if you don't want to get the view resized when rotating check the autoresize mask. If you built the view in the interface builder then check that it's not changing it's size when the superview does:
You can check the current interface orientation of your UIViewController with self.interfaceOrientation. This might help you if you want to set up you view manually.
Furthermore, if you need to adjust the sizes manually then set the desired frames to your views before (or after) the rotation is performed:
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration;
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation;
I would recommend query the status bar orientation to get the current rotation in viewDidLoad I would recommend not relying on auto-resizing for scroll views as it tends to get tricky. Check the status bar the resize proportionally based on that.
[UIApplication sharedApplication].statusBarOrientation
my UIView has a dynamic amount of views inside of it and also has a background color to it. I'm trying to tuck the UIView in around all the items, but it's not working.
[self sizeToFit] Seems to work just fine on a UILabel, but not on a UIView.
I know I can calculate the area manually by looping through all the subviews, but that just seems like too much work for something like this.
I'm hoping someone knows a simpler way.. Thanks
UPDATE
If you're using auto layout, you can make your container view fit its subviews snugly. Set up constraints between your container and its subviews, and set up constraints between the subviews and the container's superview, but do not set up constraints between the container and its superview.
ORIGINAL
There's no built-in support for automatically shrink-wrapping a view around its subviews.
The sizeToFit method works by sending [self sizeThatFits:self.bounds.size], then resizing itself based on the size returned by sizeThatFits:.
UILabel overrides the sizeThatFits: method to compute the size of its text in its font.
You will need make a custom UIView subclass and override sizeThatFits:. It's pretty simple:
- (CGSize)sizeThatFits:(CGSize)size {
CGRect rect = CGRectZero;
for (UIView *subview in self.subviews)
rect = CGRectUnion(rect, subview.frame);
return rect.size;
}
I don't think there is a "dynamic" way. You see, resizing only works the way around, a subview ca be made to dynamicaly change it's size when a superview does.
Anyway, what you are describing as "too much work" is exactly (more or less) what sizeToFit does...