In my iOS app, my parent view has a child view which, in turn, has a number of UIButtons as children. Without constraints, touches on the buttons are recognized by the topmost view controller. However, when I add a constraint to center the child view (the one containing the UIButtons) horizontally within the parent, the parent stops recognizing the touches.
First of all, is this the correct/preferred way to do this (centering a group of views - e.g. buttons - by putting them in a View)? Should I be using a Container View, or stacked Stack Views, instead? (I tried a Container View, but (a) it generated its own controller, and (b) for some reason, I couldn't move the buttons into the container.)
Second, how do I get the view to recognize the touches while maintaining the constraint?
Apparently, the problem was, I needed to set a fixed width and height as well in order to get the layout set up correctly. Once I did that, it worked correctly.
Related
I am working in Xcode 7, using Autolayout and targeting iOS 9.3. I have a Main View Controller that holds a Container View. The Container View holds a Child View Controller.
The Container View has a leading and trailing constraint of -20 so that it covers the Main View Controller fully in the horizontal.
When the Main View Controller loads for the first time, however, the content from the Child View Controller that is displayed inside the Container is slightly cut off on the left and the right (almost as if it does not recognize the constraint of -20 on the left and the right).
When I rotate the device to landscape and then back again to the original portrait orientation the Child View Controller suddenly scales correctly and is no longer cut off on the left and the right.
So it looks like some layout method is being called when rotating the device sideways and rotating it back again that does not get called when the view is first loaded. What method could this be? Is there a way that I can manually call this method to force an update on the layout/size when the child is first loaded so that it looks the same as after a rotation and backwards rotation?
First of all, you don't need to set the margin for -20. The 0 margin every side of container view is fairly enough to make the child view to spread out of the main container view. I have tried your idea but there is no problem. You can download the project from the github link below;
The link
I found a solution to the problem:
Instead of setting a leading and a trailing constraint of -20 on the Container View, I set a constraint on the Container View for the same width as the Main View and to center it horizontally in the container.
With these constraints it works on first load although I cannot quite explain why this would behave differently to the original constraints. I guess the lesson is that with Autolayout if one way of sizing your container behaves awkwardly under certain circumstances, try another set of constraints to achieve the same result.
So I'm trying to get a layout to work using Scroll View.
Correct me if I'm wrong but from what I've been reading around the internet, it looks like to properly use Scroll Views and make it work with AutoLayout you need to have your root view, then put the scroll view inside it with constraints binding it to take the whole size of the root view (left/right/top/bottom constraints to 0) and then adding a view inside the scroll view and once again binding it to take up the whole space.
Afterwards, any ui elements or subviews would go in the innermost view.
My problem is that often I have experienced issues while settings my constraints within the scroll view where for example setting a trailing constraint to 0 wouldn't actually set to the end and so on, the numbers just wouldn't add up. In this case when I'm trying to make the innermost view take the whole space,it ends up messing it up more than anything; see image below.
Any help would be appreciated.
I just created this layout using the follow:
To test it, I added an image view to the content view and put a humongous image in it. It scrolls around quite nicely including bounce etc.
Update: You need to select your ViewController and uptick "Adjust Scroll View Insets"
Hope this helps.
I designed about 40 view controllers using a 5.5 inch storyboard layout. After all of that I tested it on the iPhone 4S...big mistake. everything is jumbled together being for a larger screen size. I was able to fix one view controller up using Size Classes. I am wondering if there is any way I can adjust all 40 at the same time, or at least avoid doing this for every single one. It is really frustrating finding this out now. Thanks!
This is a relatively complicated issue you are attempting to solve, but I have two potential solutions. Both suggestions are based on moving your current interface into containing UIScrollView instances
If you are using storyboards, then for each of your view controller scenes, put a UIScrollView as a descendent of the view controller's view. From there, provided your subviews are contained within other views (like a container view for a set of buttons), you can move those into your scroll view. You will have to setup constraints to define the size of the scroll view's content, but this will allow the size of the device to have a smaller impact on the interface as you will get scrolling as needed.
If you are using nib files (.xib) then it is essentially the same thing, but easier. In this case, move a UIScrollView onto the canvas, but not as a subview of the default view. Once that is out there, move the original view to be a subview of the scroll view and set constraints to be 0 from the subview to the scroll view. Finally, right click drag from the File's Owner icon to the scroll view and set that as the view outlet.
Hopefully one of these will help you.
I have an existing view with several elements, I was thinking of how to include a scrollview to contain all the existing elements without having to go through redesigning one by one the elements,
My objective is, that when my orientation changes to landscape, the elements behind can be scrollable specially when a keyboard is currently displayed.
Can this be done manually or programmatically, and how? Or is there any best approach for this type of scenario's?
*Edit (for clarity)
My apologies for the lack of clarity with the initial question;
I have a view with 3 Textfield, A button and 2 switch, Initially my app only supported the "Portrait" orientation, however, recently I have decided to add "Landscape" orientation support, I already did this. Now my problem is when I'm on landscape the view elements gets covered by the keyboard (specifically). So I was thinking if I could include a scrollview and put the views existing elements(objects) without having to re-design the nib, what I have done already;
I drag a scrollview into the view then making all the existing elements as children of the scrollview so the hierarchy looks like;
--view
--scrollview
--textfield
--button
The end product I get with this approach is that all the elements stacks on top of the other, so I've lost my original design.
So this is what Im asking, is there anyway, to add a scrollview without having to go through the design phase again.
TIA
If your view is designed in a nib, from IB you can select all the elements of the view and then go to Editor->Embed in->Scroll View from the menu.
Following are the steps-
1.Add the scrollview to the main view as subview.
2.create a new view which contains all your elements for the scrollview.
3.add the new view to the scrollview as subview.
4.set the content size of the scrollview as the size of the new view.
Change the frame of the newView accordingly on orientation and repeat step 4.
Thats all you need to do..
What I'd like to do is drag a component/view from one superview to another in Xcode's interface-builder without having its frame/position be reset.
Xcode's default behavior when doing this appears to be to center the view being moved vertically and horizontally in its new superview, while preserving its dimensions. This is extremely frustrating, as it means that the view needs to be manually repositioned in its new superview. But I had it positioned correctly before I moved it, so I'd like Xcode to just remember all attributes of its frame instead of just its width/height. Is this possible?
Another solution:
Select the items you want in your subview, then
(in the tool bar) Editor > Embed In > view type to embed in.
I found something that might help you guys!
The task is to regroup "child views" into "parent view" so they become children of parent view hierarchically and retain physical positions on display as before action.
First, adjust the parent view to physically covers area of child views. Second, make sure that all children are bellow it in the view list.
Now select all children with the mouse and move them e.g. one pixel up and one pixel down (just to say IB there is some change). After that release children and they will magically become children of the parent and keep their positions on display.
It works for me on OSX 10.8.2 and Xcode 4.6.
Good luck!
I managed to save a lot of time spent repositioning stuff and did this:
Add the parent view in Interface Builder on the same level as the would-be subviews.
Open the storyboard in a text editor and copy the would-be subviews inside the subviews tags of the parent view. XCode is going to update once you save it.
Not very elegant though, can't see why XCode doesn't support it with Shift or something.
Select all controls you want to move from one UIView to another UiView(nay be child) or ScrollView
Cut/Copy
Now after dragging new UIView/ScrollView to your existing UIView, Don't click once to select it, instead DOUBLE click on the new UIView/ScrollView and paste all controls.
Distance difference will remain same among all controls, but you may have to reposition controls again. So don't click anywhere until you have repositioned those, just reposition all controls by navigation arrows as those are all selected already, or you may ve to select those again.
NOTE: I m on XCode 4.2
I have done something similar to Stepan's solution, without using a storyboard. In the IB while the ViewController's view is open:
Create another view in addition to VC's main view
Move all subviews to the second view by dragging them from one view to another (dragging from the list on the left side resets their position) If you cannot select them from the IB using your mouse then select all from the list on the left side then select one final subview from the IB panel using "cmd" button.
Take them back to the final view on the initial main view.
Remove the added view, all set.
This is the best solution to copy subviews to another view and retaining the positions :
Select the items you want in your subview, then
Editor -> Embed In -> View
Copy this View (Cmd+C)
Undo (Cmd+Z) (Since you just wanted the subviews)
Go to the view you want the subviews in and paste it(Cmd+V)
Select the Embedding View that you copy-pasted and Editor -> Unembed
Step 6 would remove the embedding view and you'll have copied just the subviews.
Xcode Interface Builder messes when a Parent View is dragged and dropped into another View (UIView, ScrollView, StackView)
Q:
Embedding a View (which contains many other subviews within it) into a ScrollView or in another top level view is not straight forward with what I have seen so far. What happens soon after is all the subviews might seems to be misplaced due to it couldn’t find their original frame.
A:
Follow following steps and you will be able to resolve it easier as possible:
Select the items you want in your subview, then
Go to menubar, Editor -> Embed In -> View
Copy this new View (Cmd+C) with the subviews (for me currently all the constraints were preserved so far at this point)
Go to the view (be it a ScrollView or may be StackView) you want the subviews to be in and paste (Cmd+V) the copied view
Select the pasted Embedding View (which you newly created previously) and Go to menubar of Xcode, Editor -> Unembed
No, not finished yet! Sometimes, you may experience that there are few more UI Constraint related issues, you will have to resolve them accordingly.
I detected another approach. It is basically: Move = Cut + Paste
This way you do:
get all your subviews to be children of the new parent view (P')
keep (almost) all of your constraints in Auto-Layout based Storyboard
keep your subview's relative positions (frames) one to another
This way you do not:
edit Storyboard file in a text editor
Base the thing is that each view except one (root) in Storyboard has its parent view. Next, when you copy/move multiple subviews, you lose frames and constraints.
The answer is pretty simple. You make a copy of your subviews (SVs) by copying their parent view (P) into new parent view (P'). This way you may need to recreate only constraints from that parent new view (P') to its new parent view but not for every subview you wanted to move.
After you did make copy of parent view (P) into new one (P'), from that new view (P') you:
remove all the children except ones that you wanted to move
recreate new parent (P') constraints
recreate possible Interface Builder outlets to (SVs')
And from original parent view (P) you:
remove all the children that you wanted to move
Before:
View1
View2
P
SVs-you-want-to-move
SVs-you-do-not-want-to-move
View3
After:
View1
View2
P
SVs-you-do-not-want-to-move
View3
P'
SVs'-you-want-to-move
I should stress that this does not generalise well if you have e.g. UIScrollView as a parent view. Then a copy of it would be again a UIScrollView what may not be desirable.
Another thing is when you do remove some of the subviews (SVs) in original parent view (P), you may need to recreate some constraints if other (non-moveable subviews) reference them. But you should do that anyway.
What helped me to solve this issue was-
Create the desired parent view (scroll view or uiview) in the xib at the root level and resize it accordingly
Copy all the views that you want to be subviews of this parent view and paste them onto the new view you created in step 1
At this point you will have duplicated these views. The newly added views would be a misaligned but still in the same order and at the same distance with respect to each other, align them in the xib to match their bounds with the old copies of the same view (This assumes that the new parent view has same bounds as the old one)
The newly added views will lose some of the constraints, refer to the old views to fix those
Delete the old views from the xib