I am working on an diagramming application which displays boxes as subviews inside a larger view. The user can move the boxes around. I am persisting the positions of these boxes using core data into a sqlite database by holding the height, width, x and y (of the top-left corner). When I open up a diagram I am reading these values from the database and using them to set the frame of the subview within the main view.
In portrait mode this works fine and the boxes are repositioned at the correct points on the display. However, when I rotate into landscape, or start the application in landscape and open the diagram, the positions of the boxes are wrong.
I have traced through the code and can see that the correct values are coming back from the persistent store and being used to correctly set the frame. However, once the UIView for the subview is on screen it is positioned at a different location (clearly visible and confirmed by checking the values in the frame of the view).
Now the odd thing is that instead of being a fixed pixel offset, the x co-ordinate is always 8.5% larger than the value used to create the frame, and the y value is always 9.1% smaller.
Does anyone have any explanation as to why this might be and how I might solve the problem?
If it provides any clues, the main view is inside a UIScrollView.
Okay, I found the answer. I needed to set Autoresize Subviews to false on the UIScrollView. Having done that (by un-checking the appropriate box in IB) everything seems to be working fine.
Related
I'm using spritekit to make an iOS game, and I came across a problem I've never had before. I want my game to be available on multiple devices, so I'm dynamically sizing everything based on the screen size, which I'm obtaining by using UIScreen.mainScreen().bounds.size, as was recommended online.
It's returning a screen size of 667x375. However, when I place an object at half the height and half the width, expecting to see it in the middle of the screen, it's instead displayed in the lower left corner.
Curious, I had it print touch locations from mouse clicks and discovered that the top right corner returns 1024x764 when clicked.
I've never had this problem before, and this is my 3rd XCode project. Can anyone help me?
UIScreen.mainScreen().bounds.size returns the size of your screen.
Sprite Kit uses a coordinate system different from a UIView. The bottom left corner of the scene is (0, 0). The values increase as you move up and to the right, so the top-right corner will give you the maximal value.
A scene's contents are scaled to fit the view based on the scaleMode property.
I suggest you re-read the Building Your Scene documentation.
I have a UIViewController that overlays controls on a view presenting what the camera sees. I have a couple of scenarios I would like to allow.
For the iPad, I want to keep the controls on the right most edge of the device, by your right thumb, no matter what the device's rotation. The controls should rotate their content so that their top is always upwards (away from the ground). I don't want the camera view to rotate at all, because that would just be silly – its position & size should stay the same and its contents shouldn't rotate either.
For the iPhones, I want to keep the controls at the bottom of the device's screen, by to the home button, wherever the home button actually is. The controls should rotate their content so that up is always pointing upwards. Again, I don't want the camera view's frame or content to take part in any view rotation animation at all.
I'm using auto-layout.
I'm wondering if there is any way to describe some or all of this in a storyboard. In particular, it'd be great to be able to describe that some view positions need to autorotate (ie, the controls, on iPad), but that other views don't (the camera view).
A question from 2011 indicates this wasn't possible at the time, but perhaps things have moved on since then? If it's not directly supported, can you suggest an approach and are there some sensible places to be hooking in to autorotation to achieve this?
Ok, this isn't quite a complete answer, but I tried a few things which look promising.
First, you can create a separate set of constraints for portrait vs. landscape using the size specifiers: landscape is w Regular, h Any; portrait is w Any, h Regular (I think -- double-check these) This is accessible via the pop-up control in the bottom-center of the storyboard view. By installing different constraints for portrait and landscape, it should be possible to scale the width and height of your controls' container view so it appears to be in a constant position w.r.t. device orientation; in other words, the container doesn't actually counter-rotate -- it scales so it effectively looks like it has counter-rotated.
I got this close to working. It looks like it's doing the correct thing in the storyboard view, but when I actually run it, I get debug messages about conflicting constraints. Not sure how to fix this, but maybe play with the constraint priorities? That sometimes helps.
A second thing I (partially) tried was creating a custom container view class which counter-rotates itself to the correct position based on the device orientation (in the UIDevice class). You implement this by overriding layoutSubviews. For each orientation, you define a transform which puts it in the correct position, and set the view's transform property.
Another possible solution is to override updateConstraints in your view controller and add/remove constraints to position/scale your container to the correct place for each orientation.
For all of these, the idea is that you "force" the container to be in the correct place, but leave the subviews (the actual controls) alone. The controls should do the right thing if their constraints are independent of the specific orientation of the container view.
So, those are some ideas anyway... if they lead you to an actual solution, could you post it? I anticipate having a need for this myself.
My app consists of 2 screen (main and settings) both are filled with scrollview completely. Each has one view controller and is supposed to support landscape and portrait orientations. I'm using Autosizing to achieve that and it works fairly well (all elements are where they should be, size is also correct) but I'm getting strange artifacts when the screen is rotated e.g. picker frame remains the same when the actual "drum" area inside is resized properly, text field is partially overlapped by background, landscape graph remains in place and is overlapped by portrait graph.
All are just basic elements without modifications, there are no images or anything special (graph is exception, I'm reloading it in didRotateFromInterfaceOrientation:). Any ideas why would that happen, why aren't the basic elements redrawn properly?
Figured it out myself in the end. Had to implement workaround as iOS apparently can't do it itself.
1) Artefacts after automatic view resize. Solution here was to hide the view before changing orientation, reload the graph and show it again after orientation was changed. Doesn't look perfect but much better than before.
2) Other problems were caused by the pickerview. Autoresize apparently doesn't work at all. The solution here was create UIView instead of the picker which resizes without problem and again recreate the pickerview every time the orientation changes.
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.
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!