Mechanisms to move a view partly offscreen - ios7

I have a problem that nobody has yet offered any help with so let me ask a technical question to help me diagnose it on my own.
What mechanisms does the system have for moving a view so it appears to be partly off screen besides changing the view's frame (i.e. bounds/center) or transform?
This is an app which needs to run on iOS 5/6 still so I'm not using auto layout.
I have a fullscreen view reached via a push segue.
After a pause I hide the (translucent) status and navigation bars.
When the bars hide with animation they slide up off the screen.
In iOS 5/6 this just exposes the top of the view (which is an image). In iOS 7 it moves the entire view up "offscreen" a corresponding amount (i.e. 64 points if I hide both bars) showing a bar of content "below" the view at the bottom of the screen.
When I un-hide the bars (via a tap) the bars appear and the view moves back down to occupy the whole screen.
Whether the VC is set to extend the view under bars or not doesn't affect the behavior.
I have not been able to reproduce this behavior in a simplified app.
In either state, i.e. partly offscreen or fully onscreen, the top-level view frame remains {0, 0} 320 x 480 and the transform matrix remains {1, 0, 0, 1, 0, 0}. I have no idea what property of what object the system is changing to visually move the view. Perhaps if I knew what object/properties to examine I could deduce something about what is going on. Can anybody tell me how the system might be doing this?

The answer is that the "view" that was being moved was being presented by a UIPageViewController and I wasn't thinking about that. The UIPageViewController is presenting the child views inside a UIScrollView (subclass, I think) and so the scroll insets for the containing UIScrollView were being changed by iOS 7. Since the whole "presenting as a child" thing actually works -- of course I couldn't see the problem in the child view.
The "fix" was to un-check the View Controller setting for Adjust Scroll View Insets for the UIPageViewController view.

Related

How do I efficiently manage screen size changes and redrawing with storyboards, initWithCoder, viewDidLoad and viewDidLayoutSubviews?

I am using storyboard layouts to set up view layout.
I am supporting both iPhone and iPad layouts.
When the view is created with initWithCoder:, it is initially created with the frame size of the device I was last looking at in Interface Builder.
If I am designing with the iPhone X layout in interface builder and then build and run on an iPad, the view is initially created with iPhone X screen dimensions. Then viewDidLayoutSubviews: is called and it updates the screen dimensions to the correct iPad size.
The subviews are using drawRect inside UIViews to draw the view graphics. I am doing this so I can change graphic colors via code. I change the color variable and then call setNeedsDispay on the view to redraw the view with new colors using CGGraphicsContext commands.
It also allows me to draw any graphic image at any size. And with lots of graphics that means I don't have to include all the different images at 1x, 2x and 3x sizes in my bundle. It's all drawn dynamically.
Some of these images are laid out when the view loads and not in Interface Builder. So I check the screen size and draw the button size and position accordingly.
What happens is, viewDidLoad is called and it draws the graphics based on the initial screen size.
Then viewDidLayoutSubviews is called and I have to update the drawing of the subviews I placed manually repositioning them based on new screen dimensions and then calling the drawRect on them. I feel like this is just unnecessary extra work for the device.
In addition to that, viewDidLayoutSubviews is called for other reasons then just resizing the view on initial load of the viewController. So then each time it's called it will go redraw the subviews, even if they don't need it.
And, if the device I am running on is the same as the device I was using in Interface Builder, it doesn't call the viewDidLayoutSubviews. I can't just let the view layout the subviews there because there is no guarantee it will be called.
My solution so far is creating a variable to track the screen width. I set the variable in viewDidLoad. If it creates the view at iPhone X size, my screenWidthTracker = 1125. When viewDidLayoutSubviews is called I compare the current screen size to screenWidthTracker.
if (self.view.frame != screenWidthTracker) {
[[NSNotificationCenter defaultCenter] postNotificationName:#"updateView" object:self];
};
if the view has changed size, it sends a message to redraw views. Any views I have placed manually as subviews are registered to listen for #"updateView".
Is there a better way to manage this? Is there a method that gets called ONLY when screen dimensions change and not when its updating the position of other subviews? Should I be utilizing viewDidAppear? I feel as though that is too late in the chain and I don't want the user to see button size updates.
In general, from the description you've given, I'd say that at the very most, you should be doing as much size work as possibly by using autolayout (which you can configure entirely within the storyboard) and then implementing only drawRect and viewDidLayoutSubviews — and the latter only if you need to.
A very common strategy is to use a boolean flag to set up initial conditions in the first call to viewDidLayoutSubviews, and not use it thereafter. Screen size changes after launch (not at launch), such as rotation, are detected by implementing willTransition(to:with:) — and even then you should check to see that the old size and new size are not the same (180 degree rotation) and do nothing if they are.

Strange UIContainerView autolayout rotation behavior

I have a view controller that consists of two child UIContainerViews, one of which is fixed-width, and the other which dynamically adjusts its width based on portrait vs landscape mode. Both contain UITableViews.
For some reason, if the screen loads in portrait orientation it renders fine. However if it loads in landscape and then rotates to portrait, the second (dynamic) table gets all screwy and thinks it's wider than it is/should be, letting you scroll it horizontally which it should not be doing.
The cells of the tableView all size properly and stick to the left side of this "too wide" tableView. However, if I color the background of the tableview pink, I can see the whole thing is extending into this too wide zone.
It's baffling me what's going on here. Shouldn't autolayout be the same regardless of which orientation the view controller was loaded as?
If I log the widths in a viewDidRotate... handler, everything appears to have the correct width, yet it's still rendering in this bizarre way.
Is there perhaps I way I can just force the container view to re-lay it self out?
Update: It is the contentSize of the tableView that is getting messed up. All the other widths are correct when logged, but the contentSize.width is way off. The good news is I can just manually set this back to what it should be and everything works great! However it doesn't answer the question as to why it's happening in the first place or what I'm doing wrong (if anything).
Here's a screenshot:
In order to force a UITableView to (re)calculate its content size, you may use layoutIfNeeded method. It traverses through the view hierarchy and lays out the subviews immediately, so content size is set properly.
Instead of setting the size manually, call this method for your table view.

iOS page based application clear color issue

I'm trying to make a page based application in iOS where the actual page is a non-rectangular image (contains clear color). However, the shadow that appears when I turn the page doesn't seem to ignore the transparency of the image (see below).
Screenshot http://img543.imageshack.us/img543/9730/pagecurl.png
Does anyone know if it's possible to modify this behavior?
Thanks in advance.
Have you tried setting your UIPageViewController's view's frame so that it sits just within the border defined by your custom page image?
(So in your case, the largest rectangle that fits inside your white page image)
The way UIPageViewController handles a page curl animation with views that extend beyond its own view's frame can be thought of as follows:
Think of the overhang as rigid. it does not bend like the rest of the page, but it does maintain the angle at the edge of the UIPageViewController's frame. If the overhang (i.e. parts of your image or view that extend beyond the UIPageViewController's frame), is small, the fact that the overhang animates as rigid (instead of the bendy, flexible page) is visually negligible.
However, without any further modifications, the pages will only flip when a touch is started INSIDE the UIPageViewController's view's frame. But it would be better if it could react to touches anywhere on your white page image. If you want the pages to react to touches inside another view's frame (e.g. the view holding your white page image), try the following:
otherView.gestureRecognizers = myPageViewController.gestureRecognizers;
The problem is that the iOS framework puts a shadow over the entire bounds of the view controller you specify for the page, so any transparent areas will look shadowed. You could try masking your view controller (viewController.view.layer.mask and viewController.view.layer.masksToBounds) and see if that helps.
Hopefully Apple improves this framework for a future iOS release. It sure would be nice to disable that shadow or have a way to do it yourself but there you go.

Storyboard editor layout confusion

I am having layout problems with the storyboard editor with a fairly simple screen. I have a UIViewController to which I have added a 320x440 UIScrollView at 0,0 followed by a 320x20 UIProgressBar at 0,440. It looks fine in Storyboard editor. I'm not entirely sure how the 20 pixel status bar at the top of the screen is accommodated given the CGRect frame coordinates that Storyboard calculates.
On loading ( in -(void)viewDidLoad ), the UIScrollView frame seems to be set to 320x460 pixels at 0,0 but the UIProgressBar is still 320x20 at 0,440.
When I add subviews to the UIScrollView, (UIImageViews in particular), they get stretched and get clipped on the screen because although the UIScrollView thinks it is 460 pixels high, it only has 440 pixels of screen to display in.
Can anyone point me to a solution?
Thanks
OK - I have identified what was going on - there were a number of issues, nearly all to do with mutually incompatible settings in storyboard attributes on various view controllers.
In summary, the main view controller containing the UIScrollView had the 'wants full screen' checkbox ticked - goodness knows how, but it appears that I had then gone through other views trying to compensate for that initial error by clipping, resizing, setting layout constraints etc. which resulted in rather confusing outcomes.
My advice would be to not touch ANYTHING in storyboard editor unless you know what it's effect will be - it is a dangerous place. I found the issue by going back to basics and creating a trivially simple replication of my app and then observing the differences between that app and my own. Sorry if I wasted anybody's time researching an answer.
Thanks

Resizing an NSView smaller than its subviews?

Couldn't find anything on the net about this and wondered if anyone on SO has a solution.
I have an NSView with several subviews that are centered by removing the left and right anchor points. When I resize my view, programatically or with the mouse, to a smaller width than the subviews: it pushes them off center. Has anyone come across this before and do you have a solution?
EDIT: I want to be able to resize my view to a zero width. The reason being, the view is actually part of a split view and I have hooked up a button to 'collapse' it. When it collapses all of the subviews are pushed off-center and aren't re-centered when the view is resized, effectively un-collapsing it.
I have solved my problem now and thought I would share incase anyone comes across this issue in the future.
No amount of playing with autosizing options or view layouts in Interface Builder seemed to stop my subviews from getting moved off center. I did manage to find this link here and from this page, the advice:
Springs and struts, as currently
implemented, are really no good for
anything but keeping either one or
both sides of a view "stuck" to the
nearest edge. Any sort of centering
behavior, division of gained/lost area
between multiple views, etc. has to be
done by hand.
Based on this I overrode my view's setFrame: method and manually laid out my subviews using their setFrame: method. This works great and gives me the results I'm looking for.
There is the same issue using NSSplitView, resizing here one Subview to be smaller than the Subview Subviews makes sense,e.g. having small charts in the upper subview, and an rss reader in the lower subview.
If you want to show only the rss reader in the lower subview, you can "hide" the upper subview, but after resizing the upper subview the NSImageView are not layed out the same as in the beginning. Check this nib/xCode Project and the following screenshot to see this behaviour.
Only workaroung is to override the resize function to stop getting smaller.