iPad - redrawing the arrow direction of a visible UIPopOverController - ipad

I have an object that is drawn near the first third of the screen. Imagine that there are 300 pixels between the top of the object (an image, for example) and the top of the screen.
When I show a popover, lets say, with 200x200 pixels and specify arrow direction as any, the popover may appear over the object, that is, between the object and the top of the screen.
If the popover for some reason, loads another view and is resized to more than the available space between the object and the top of the screen, it will not be able to fit there. iOS solves that, forbidden the popover to resize to more than possible. The result is that the content gets truncated and probably the popover will move a little bit and the arrow will point to nowhere.
Is there any way to make a popover that has increased to recalculate the best arrow direction?
thanks.

You can calculate the size of your needed future content (contentView) and compare it to your threshold and force the arrow direction. you may need to experiment with your threshold as the size of a content view isnt the entire height of the popover.
int popoverArrowDirection 15;//any
int threshold = 300;
if(viewThatWillbeInserted.frame.size.height>threshold)popoverArrowDirection = 1;//up
[myPopoverController presentPopoverFromBarButtonItem:myBarButton permittedArrowDirections:popoverArrowDirection animated:YES];
If you cant know this height before then you don't have many options.
The limitations of popovers drove me to mock-up a popover as Custom ViewController (like the page popover you see when you slide through the pages in a ibook; thats not an actual popover component). This would mean that if you had a down arrow, and pushed on a new bigger view you could even animate the view spinning around the origin of arrow tip or any other stupid animations..
I have only done this in enterprise apps, and am unsure weather this is app-store safe!

What happens if you dismiss the popover and then re-present it after the content size has changed?

Related

Creating an animation such as iOS 8 Weather App

I want to create a view in which I like to have animation such as the one present in iOS 8 Weather app.
I try to explain more what I have done. If anything is incorrect please guide me.
In the top I put a label for the temperature. (The big one)
Below that label, I put another label to show some text. In the Weather app, there is the horizontal scrollview showing the hourly forecast.
Next is the Table view.
What I want to achieve is that when I start scrolling, the first label disappear smoothly and the second one go to top of the screen and the TableView stretches to show more content.
When I scroll back to the top, I want the whole process to revert.
What is the best way to do this?
I've recently re-created the iOS8 Weather app's scrolling effect for an app I'm creating.
The complete code is too long to post here but for anyone who's interested, I've put it on GitHub. You can download and run the project to see how it looks. Improvements to the code are welcome:
UIScrollView with masked content.
It works like this:
You have one scrollview (the size of the screen), which contains a subview (the mask) which in turn has a subview (the content). We also add a large label to the top of the screen (in the Weather app, this displays the temperature).
Then you use the scrollViewDidScroll delegate method to keep the mask fixed to the screen as the user scrolls. You also use this method to stretch the mask upwards at first.
Fixing the mask to the screen means that the mask's subviews (our content) also becomes fixed. But we want it to scroll, so we do the opposite to the content of what we did to the mask (again, using scrollViewDidScroll).
We need the mask to actually behave as a mask, so we set clipsToBounds = YES on the mask.
Finally, we use the scrollview's offset during scroll to move and fade the big label at the top of the screen.
To make it behave exactly like the iOS8 Weather app, we need to also do the following:
Cancel any scroll touches that happen above the mask, i.e. over the large temperature display.
Ensure that the initial scroll that moves the temperature display is completed programatically if the user doesn't complete it.
Add a sideways-scrolling subview which is anchored to the top of the mask.
I haven't done these yet, though.

UIPageViewController rotation weirdness

I've added a UIPageViewController to my app to act as a manual for the app. When the user pops it up it shows one page in portrait and two in landscape with the spine in the middle. Since I have about 100 pages, there is a sibling view UICollectionView page selector view above it to allow jumping to a page quickly. Both the UIPageViewController and the UICollectionView sit on a backing view that contains them both.
The problem I am having with the UIPageViewController is that when the views are first rotated they seem to constrain themselves to the short dimension of the original layout. So, if it first appears in portrait, then when rotating to landscape the width of the two pages is the same as the old portrait width. Likewise, if it first appears landscape with two pages, rotating to portrait has the correct width, but the height is the height of the initial landscape height. This is consistent on any device.
When I create my content views they are all the size I desire, but for some reason they seem to be transformed by some component of UIPageViewController and I'm not grasping why it is only doing one of the two dimensions and why it is always the "short side" that is the problem.
This is one of those kinds of problem that makes me feel a bit nutty, any ideas on how I might debug it if it isn't some trivial misconfiguration?
I finally found it after a long period of debugging. The critical hint was seeing that the spine is set to the correct mid for the width of the view BEFORE the rotation for portrait to landscape. The solution was to reset the frame of the view to the new size given the orientation in willAnimateRotationToInterfaceOrientation.
I calculate the new size before I call an animation block that uses the duration passed into the method, then inside the block I have:
pageViewController.view.frame = newFrame;
When the page is rotated the view holding the content pages is shifted to the correct size and the spine is place correctly and the content fills the given area. I suppose that I ran into the problem because the complexity of the views required me to take over so many defaults, but this one was left hanging.

How to make UIPopoverController change its arrow direction automatically

I've encountered strange problem in UIPopOverController.
Normally, I present popover this way:
[popoverVC presentPopoverFromRect:sender.frame
inView:sender.superview
permittedArrowDirections:UIPopoverArrowDirectionLeft
animated:NO];
However, sometimes there is no enough space on the right side of the button (sender) and the popover is displayed below the button with UIPopoverArrowDirectionUP. It make sense - if popover can't be displayed properly, controller trys to display it with different arrow.
But when I moved my button (sender) about 10 pixels to the left, popover doesn't behave this way. There is still no enough space to display it properly but it doesn't change its arrow although popover is ~20px wide so it's way too small.
Is there any way to say popovercontroller: "If popover does not have enough space to display all content, change arrow direction" ?
Why not use UIPopoverArrowDirectionAny, which Apple recommends anyway, or, if you absolutely must, UIPopoverArrowDirectionLeft | UIPopoverArrowDirectionUp? The exact orientation of the popover's arrow seldom matters that much.
If that doesn't work, I guess the only choice is to do some math in the action method. (Disclaimer: I've never tried this, but I don't see why you couldn't do it if you absolutely had to.) First convert the sender's bounds to the top-level view's coordinate space. Depending on the specifics of your app's view hierarchy, you may need to convert the bounds/frame to/from an appropriate view. Unless you've got a something weird going on, this should work:
[self.view convertRect:[sender bounds] fromView:sender]
Then check whether the resulting rectangle is more than X points away from the right edge of the screen, where X is the width of the popover (including the black border and arrow). If there is enough room, present the popover as you say above. If not, use UIPopoverArrowDirectionUp instead.

UIButtons non-responsive after being moved in from off iPad screen

The description might be a bit confusing, I've added pictures to try to illustrate what I'm describing. Please let me know what I can clarify to help.
I have an iPad application with a main view that is a xib. The size of the xib is 1024 by 1384 and is meant to be viewed in landscape mode. There is a row of buttons that are visible at the bottom of the iPad screen. When one of the buttons is pressed I move the frame so that these buttons are now at the top of the visible portion of the screen. There are additional elements that start out offscreen but then come onscreen after the move.
The problem I'm having is that the UIButton that starts offscreen is not calling the IBAction associated with it.
I have tried to setUserEnabled to YES for it but that doesn't seem to be making any difference either. I've also tried setNeedsDisplay after the animation is complete.
Anyone have any ideas?
When you add the view to the screen, it changes the view's size to fit the visible portion on the screen. As such, your frame is smaller than the total content area of the view. Moving the frame won't do anything for you; it will move the existing visible content up, but it won't change the view to show new visible content.
Instead, you want to be changing the view's bounds.origin, which will change the visible portion of the view's content.
Edit:
Note that even though the view was shrunk, I suspect that the clipsToBounds property on your main view was set to NO. That means that it will actually continue displaying content outside of the bounds, which is why it shows up. However, hit-testing only works on the actual frames of the view. All that stuff that shows up outside the bounds is still visible, but it's not interactible.

UIView coordinate transforms on rotation during keyboard appearance

iPad app; I'm trying to resize my view when the keyboard appears. It amounts to calling this code at appropriate times:
CGRect adjustedFrame = self.frame;
adjustedFrame.size.height -= keyboardFrame.size.height;
[self setFrame:adjustedFrame];
Using this technique for a view contained in a uisplitview-based app works in all 4 orientations, but I've since discovered that a vanilla uiview-based app does not work.
What happens is that apparently the uisplitview is smart enough to convert the coordinates of its subviews (their frame) such that the origin is in the "viewer's top left" regardless of the orientation. However, a uiview is not able to correctly report these coordinates. Though the origin is reported as (0,0) in all orientations, the view's effective origin is always as if the ipad were upright.
What is weird about this is that the view correctly rotates and draws, but it always originates in the literal device top left. How can I get the view to correctly make its origin the "top left" to the viewer, not the device's fixed top left? What am I missing? Please, for something so trivial I've spent about 6 hours on this already with every brute force technique and research angle I could think of.
This is the original source which doesn't work in this case:
move up UIToolbar
OK, I don't know what the ACTUAL answer is to the original question, but I can say with certainty that one way to resolve the issue is to always ensure that you don't manipulate a viewController's view directly. Always wrap your view inside a container view inside the main "view", then have that container view adjust its position etc as needed. Works exactly as the splitview does, probably because in both cases now the view in question is a subview of the main "view". What a relief!

Resources