Necessary to remove ScrollView from Superview before changing and re-adding? - objective-c

I have a UIScrollView that of course contains information. Based on conditions I make changes to the height of the scrollview as such:
CGRect scrollFrame = self.scrollView.frame;
scrollFrame.size.height = scrollFrame.size.height + adMobBannerView.frame.size.height;
self.scrollView.frame = scrollFrame;
I then add the scrollview back:
[self.view addSubview:self.scrollView];
All of this works as it should. However, should I first be removing the scrollview from the superview before adding it again? While again what I am doing works, I am wondering if I am just layering scrollviews on top of scrollviews unnecessarily?

You don't have to add UIScrollView as subview after you change its height (if it is currently added as subview).
When you try to add view A as a subview of view B and view A has superview it would be removed from its superview so you don't have to call removeFromSuperview method yourself.
From Apple Documentation:
Views can have only one superview. If view already has a superview and that view is not the receiver, this method removes the previous superview before making the receiver its new superview.

Related

How to prevent certain object from scrolling in a UIScrollView

I don't know if this is possible and I highly doubt that it is but I'm wondering if there's a way where I can prevent a button for example from scrolling in a UIScrollView using Objective-C programming?
Sure. Simply update the button's origin as the scroll view scrolls.
In your view controller, implement the appropriate scroll view delegate method. If not done already, setup your view controller as the scroll view's delegate.
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGPoint offset = scrollView.contentOffset;
CGRect frame = self.fixedButton.frame;
frame.origin.y = offset.y + 40;
self.fixedButton.frame = frame;
}
This will keep the self.fixedButton button 40 points below the top of the visible portion of the scroll view. Adjust as needed.
The above all assumes the button is a subview of the scroll view.
Of course it may be a lot easier if the button and the scroll view share a common parent view. Then the button isn't a subview of the scroll view and won't scroll at all.

Subviews added to documentView of NSScrollView not showing up

I have a NSView wrapped in a NSScrollView using the IB. In the initialization function of the view (class is NoteView) containing the NSScrollView, I attempt to add subviews to the NSView as follows:
// Initialize custom view with width 802 and height 130, call it initialSubview
// Set initialSubview's frame origin to (20.0, 580.0). documentView of scrollView
// is size (842.0, 740.0)
// Let innerView be the documentView of the scrollView (I have an IBOutlet attaching
// the scrollView's document view to innerView)
[innerView addSubview:initialSubview];
When I do this, nothing shows up. Likewise, trying this:
[[[scrollView] documentView] addSubview:initialSubview];
doesn't work either. However, if I added it to the contentView:
[[[scrollView] contentView] addSubview:initialSubview];
The subview shows up fine. Any ideas?
As an addendum, if I add something like an NSButton to the documentView in the IB, nothing
shows up as well.
I figured out the issue. It seems NSScrollView and Auto-layout fight themselves.
The solution is to remove whatever you're documentView is (in my case innerView)
from their superview, setTranslatesAutoresizingMaskToConstraints to no, and re-add the view.
The code looks something like this:
[innerView removeFromSuperView];
[innerView setTranslatesAutoresizingMaskIntoConstraints:NO];
[scrollView setDocumentView:innerView];
Then you have to set any constraints you'd like manually
I am pretty sure contentView is the correct place to add it. You may also need to update the content size.
Adding views to a NSScrollView from IB adds the view to the NSScrollView's contentView(NSClipView).
According to your setup you have
NoteView is clip view(contentView) of the NSScrollView.
document view of the scroll view is innerview.
inner view(documentView)'s subview which is initialSubView is added from
-initWithFrame: of contentView.
In an NSScrollView a contentView represents the 'clipped' representation of the documentView.
Having the documentView initialized in init of the contentView is why nothing happens.
Do This
Add NoteView from -awakeFromNib or similar entry point as documentView of the NSScrollView.
Add initialSubView as a subview of NoteView.

How to keep UIView at relative distance from other after resizing?

I have five UIView on a UIScrollView. All of them with the same width. Each view has other subviews that resize its height according to the content assigned, thus making the parent UIView and the UIScrollView resizable as well. I am trying to keep the 5 UIView separated from each other at a certain "Padding" distance even after resizing. What I do right now is set the position of the origin.y and the height of each UIView when layoutSubviews is called. Is there an easier way to do this?
I have tried to set their position on creation like: CGRectMake(0, aboveView.frame.origin.y + aboveView.frame.size.height + Padding, width, 0) and setting its autoresizingMask to UIViewAutoresizingMaskTopMargin. Hoping that when I call sizeToFit on the main UIView, all the UView will set their positions relative to the view above them.
Overriding layoutSubviews is the right way to do this. UIKit doesn't have any built-in layout management that can do it for you.
However, you might not realize that UIScrollView sends itself layoutSubviews each time it scrolls - on every frame of the scrolling. That may be a lot more often than you need! You don't want to do a lot of work in a UIScrollView's layoutSubviews if you can avoid it.
To avoid doing extra layout, I suggest you set up your view hierarchy like this:
UIScrollView
ContainerView with layoutSubviews method
content view 1
content view 2
content view 3
content view 4
content view 5
Use a standard UIScrollView. Give it one subview, which is a custom UIView subclass (I called it ContainerView in my example). The ContainerView has your five content views as its subviews.
When you assign new content to one of your five content views, send sizeToFit to that content view. If the view's size changes, UIKit should automatically send layoutSubviews to its superview - the ContainerView. The ContainerView's layoutSubviews method adjusts the position of its subviews to maintain the padding between them, and then sets the contentSize of its parent - the UIScrollView.
- (void)layoutSubviews {
CGRect myFrame = CGRectZero;
for (UIView *subview in self.subviews) {
CGRect frame = subview.frame;
if (myFrame.size.height > 0) {
frame.origin.y = myBounds.size.height + Padding;
subview.frame = frame;
}
myFrame = CGRectUnion(myFrame, frame);
}
self.frame = myFrame;
UIScrollView *scrollView = self.superview;
scrollView.contentSize = myFrame.size;
}
This way, you don't do any extra work just because the scroll view scrolled. You only lay out your content views when the content actually changes.

Resize parent view if subview changes size

I'm new to Cocoa and I'm programming a custom InspectorView.
A parent view (InspectorView) contains several subviews (InspectorCategories).
If I uncollapse a category (subview) I have to resize/relayout my parents view?
I found out that this is not possible through autoresize masks - Is this correct?
I tried it with resizeSubviewsWithOldSize in my parents view but this gets not called while resizing the subview.
How can I achieve this behavior?
There are two parts to accomplish what I think you want:
(a) In the parent view, override the sizeThatFits: method so that it computes a new size that fits around the resized subview.
(b) In the subview, override the setFrame: method and after the frame size is changed, it calls [self.superview sizeToFit] to resize the superview, perhaps like this:
-(void)setFrame:(CGRect)newFrame
{
[super setFrame:newFrame];
[self.superview sizeToFit];
}
No, it is not possible to do through autoresizing masks. Autoresizing mask defines how the view is resized when its superview changes bounds.
The subview should let its superview know what size it needs, for example through a delegate call. The superview then should resize itself and the subview.

Make subview of a UIScrollView fixed while the other subviews scrollable

I want to make a View with three subviews stacked on top of each other with the middle subview scrollable with the others fixed.
How can I achieve this programmatically? I have tried
to set the contentsize of the root view to the size of the scrollable view but that makes all the views scroll.
-set the contentsize of the middle subview without setting any property for the root view but that makes all the views unscrollable.
Please help. I am new to iOS.
Thanks in advance
You can use the scrollViewDidScroll: delegate callback on the UIScrollView to adjust your view's position. In the callback, get the contentOffset of the scrollview and use that to set your fixed view's position.
For example, if you want your fixed view to always remain 100 px from the top of the scrollview, set its initial frame to (0, 100, width, height), and then in the callback set the frame to (0, contentOffset.y + 100, width, height).
The result is that the subview will appear fixed at a given height.
If your UIScrollView has a superview (i.e. a container view), you can add your 'fixed' view as a subview of the superview instead of the UIScrollView. You'll only have to calculate your frame coordinates once.
You can do it moving sub view from UIScrollView to super view of scrollview like:
Place/set your button over scroll view (not inside scroll view) as shown here in this snapshot. And also set button constraints (position) with respect to super view of your scrollview.
Here is ref. snapshot of hierarchy of position of each view over each-other.