I am updating an application for iOS 7 and have decided to use Auto Layout.
When I try to add constraints to any of the elements in the below screenshot :
i.e. View Controller, Table View, View, Table View Section, Table View Cell, Content View, Label.
I am unable do to so, as no item in the Add New Constraints panel ( as seen below ) is interactive.
(Apart from the Update Frames Item)
In my attempts to resolve this issue I have researched that
"When using Auto Layout you may no longer set the frame of a view directly. This line either has no effect, or it may directly interfere with what Auto Layout is doing."
also
"When setting the contentSize of a scrollview with Auto Layout, the content size is automatically derived from the constraints that you set on its child views."
The problem is still there when I update the ViewContoller code to accommodate this advice.
I had a similar issue. I was able to add constraints for items on a Table View Cell - Content View (e.g. UILabel, UIImageView), once I switched the Table View Cell Style to Custom.
If I added images or UILabels on top of a default Table View Cell type (e.g. Subtitle), I could position them on the Content View, but couldn't set constraints on them.
Changing to Custom Table View Cell Style was the solution for me.
To set the constraints you need to select the items and then set the constraints with either the constraints menu or with ctrl+drag.
However, there is no way to set constraints for a tableViewController as it is a already completely set up.
There might be set Autoresizing Mask as layout in Size inspector.
Try switching it to Constraints:
Related
Similar question: How to resize a parent view based on the size of subviews layouted with Autolayout
I got an NSStackView which loads DisclosureViewControllers (NSViewController subclasses) just like in the Apple Example InfoBarStackView.
Those can expand and retract views of arbitrary height.
I would like the parent view containing the NSStackView to resize its height according to the contents of the NSStackView. In the Apple example that works.
However, unfortunately, Apple is resizing a NSWindow and I am using a CCNStatusItem (CCNStatusItem Github), a view that attaches to the status item in the Apple menu bar. That window resizes to the contents of the NSStackView when it loads, but doesn't resize when the contents change.
When I expand a section, the content overflows and gets clipped on the bottom edge of the view.
I went through all the constraints and tried to reproduce it exactly, but couldn't get it to work. In the Apple example, they are adding everything programmatically, whereas I added a NSStackView in Interface Builder.
Here are the constraints of the NSStackView:
My question would be: What constraints do I have in the Interface Builder (with what priorities), so that the parent view (the window) resizes with the contents of the stack view dynamically?
Do I have to call some method of the view to make it work?
Please let me know if I missed to provide some necessary information.
UPDATE
The accepted answer was the right way to do it. Here's the result. My forked version of CCNStatusItem can be found at https://github.com/julianvogels/CCNStatusItem.git
When using auto layout constraints, you don't need to call a view method to cause this effect, but just make sure that:
the views inside the stack view have constraints that will cause them to grow
the container has constraints to the stack view that indicate the container should grow with the stack view
the container doesn't have any constraints that would prevent it from growing
The screenshots seem to indicate it's not the first -- the views are growing as expected. So it could be either the second or third. The screenshot from interface builder seems to show that the bottom StackView<>Container constraint is optional (it's dashed). Depending on what the priority actually is, that could be your problem. Based on the design you described, there should be no reason for that constraint to be non-required.
The problem is that CCNStatusItem is not auto-layout-compatible. It sets the content view of its window to an instance of one of its own view classes (CCNStatusItemWindowBackgroundView). Your view is a subview of that view.
When it creates and adds its view, it does not turn off translatesAutoresizingMaskIntoConstraints or use constraints to position it relative to its superview. That basically means it can't be forced to a different size by constraints.
Likewise, when it adds your view to the background view, it does not turn off translatesAutoresizingMaskIntoConstraints on your view nor does it set up constraints to relate your view to the background view.
Since you've got the source, you can make those changes.
In order to implement scroll view I do:
Create Cocoa Application
Go to XIB
Drag scroll view to the view window and set its constraints to 0
Everything seems fine until now
Under Bordered Scroll View (in the Document Outline) I press on Clip View and then View and resize that to any large number (under size inspector)
I add a button (for the sake of it) to the view (under clip view) (in the Document Outline) and sets its constraints
After this I immediately get the "Ambigious Layout. Position is ambigious for "View".
What am I doing wrong? Is this the proper way to add scrollview? It also seems rather difficult to add items to the scrollable area as I dont see the entire scrollable area in the xib.
Please help a noob.
In general this is a correct way to add a scroll view. (You can also create a view or set of sibling views, select them, and choose Editor > Embed In > Scroll View.)
If a view has no constraints, then Xcode will add sufficient constraints at build time. These constraints are not necessarily the ones that cause the view to behave like you want as things change size, but they're good enough to maintain the current layout of the canvas when things have their current sizes.
However, once you add constraints, Xcode will start insisting that the constraints are mutually-compatible (no conflicts) and sufficient to be unambiguous.
So, that explains why you get that warning. You have added some constraints, but not enough to make the layout unambiguous. You need to add enough. Xcode should explain in more detail what's needed, although there will necessarily be multiple possibilities for how to resolve the ambiguity.
In your case, I'm guessing that the size of the view in the scroll view is ambiguous. For example, you may have added constraints to position the button relative to the top and leading edge, and the button likely has intrinsic size, but you haven't constrained the view's bottom or trailing edges to the button. So, the size of the view could be anything.
Of course, rather than constraining the view's bottom and trailing edge to the button, you could just add explicit height and width constraints to it. Or whatever.
You may also need to constrain the view to the clip view.
You can also use Editor > Resolve Auto Layout Issues > Add Missing Constraints and see what Xcode adds. You can then change things from there if what Xcode added is not what you want.
For my Mac OS X app, I selected the controls on xib to embed in scroll view ( Editor > Embed In > Scroll View ) and applying the following constraints to Custom View (inside Scroll View -> Clip View) did work.
Where hight is to accommodate controls.
I have established constraints to like buttons, timestamp button, etc. below bottom of textfield a certain distance. You can see the issue in the image; if the textfield doesn't have enough letters, they overlap, how do I fix this? Here's a link to image:
https://docs.google.com/document/d/1_btZBSsL3SQA1IulFTasMFBghF_2hJYzrFlbuQPkKrM/edit?usp=sharing
The problem is setting the constraints with respect to the bottom of textfield. That bottom moves depending on the amount of text the field has and if that bottom position is above the bottom position of the icon to the left of the text field, you'll get the overlap you see. The solution, you might think, is to set the constraints with respect to the bottom of the icon but that won't work when the text field has a lot of text. You should try that just to understand the problem more clearly.
The actual solution is to set this particular constraint programmatically, as text is entered into the text field. You want to set that constraint with respect to the bottom of the view (icon or text field) that has the lowest bottom. That way, with little text, the constraint is set relative to the bottom of the icon but when there's enough text for the text field to vertically extend below the icon, the constraint is set relative to the text field instead.
Where would you set this constraint programmatically? Probably in the textField:shouldChangeCharactersInRange:replacementString: delegate method of UITextField.
Alternatively - and perhaps a better solution - you could have a view containing the icon and the text field and set the constraint in question with respect to the bottom of the container view. That way you can set the constraint in IB rather than have to do it programmatically.
To clarify my answer, after the discussion in the comments below, here's a picture of what I mean by having container views and setting constraints between them to avoid the observed overlap.
Set appropriate constraints within each of the container views then set constraints between the container views and between them and the cell content view (I'm assuming, from your picture, that you have all of this in a table view so you have some template table view cell).
I have a UITableViewCell defined in a XIB with auto-layout enabled. It contains multiple UILabels, one of which often runs to more than one line. I am able to appropriately adjust the height of the cell based on its content. The layout is similar to the example below:
What I would like to now implement is an additional UILabel that may not be present at initial render time, but is then populated when a user presses the action button.
What is the best way to accomplish this using auto layout?
UPDATE:
I am attempting to hide/show the dynamic label by adding/removing a constraint with height = 0, but am experiencing issues related to placement/size of the other labels. I have provided an example project showing these issues here: https://github.com/markdorison/AutoLayoutExample
You can animated the constraint by creating an outlet to it and just changing the constant followed by a call to setNeedsUpdateConstraints - all within an animation block
Application requires more than one window (Lets call A,B,C). Each window has more than one view (table views, image views as well as web view). Lets say window A has three views (x, y,z) and window B has three views (d,e,f). Application needs to display images of different size on orientation change.
I have achieved the same using gesture event listener and looping through windows for views and replacing the view with new images. The problem I have is when we navigate from one window to other and the orientation changes, the loading of view after looping goes for a toss. Is there a better way to achieve the same ?
Is there a method in titanium like following code to replace a view ?
var self=Ti.UI.currentWindow
var newView=Ti.UI.createImageView({image:'abc.png'})
self.replace(self.children[1],newView )
Unfortunately there is now replace method.
You need to remove the whole view and add it again but this can cause a wrong layout if you have more than one view on a same level. The implementation then depends on the layout which was set (vertical, horizontal, composite etc).
For example in vertical layout removing an item and simply add a new one would remove your specified item but appends the new one at the end since you can't specify in which order it should be added.
If you have a composite layout you can specify absolute positions but adding a new view causes a higher zIndex for this view so that it will hide views that were previously added at the same/similar position.
Why not simply change the image link ?
var self = Ti.UI.currentWindow;
self.children[1].image = 'bcd.png';
Well you could always lock the orientation of your window. But this isnt exactly good practice (especially for iOS).
Generally orientation changes are handled pretty well if you define the width and height of your views to be percentages or Ti.UI.FILL, if you have a composite layout. Check that you are not giving the views absolute coordinates as this could cause layout problems. If you have a vertical or horizontal layout you usually don't have to worry about orientation change, unless you did not nest your views in a main container correctly.
Prasad,
If this is about just ensuring that the images look good on different orientations,you can make use of the different folders provided by Titanium in the android/images folder.You can just make different images for each of the orientations and device sizes.For IOS you can change just the images on orientation change as you are already doing.
https://wiki.appcelerator.org/display/guides/Using+density-specific+resources+on+Android
If you are concernced about the layout there are couple of things you can do:
1.Give all the height or width values in percentages.This way all elements will be re sized once the orientation changes automatically.
2.On each window open check if the orientation is vertical or horizontal by default and accordingly set the image attribute of the imageView.
Ti.UI.orientation
This property will give you the orientation of the window by default.Values of this property could be this
Ti.UI.PORTRAIT
Ti.UI.UPSIDE_PORTRAIT
Ti.UI.LANDSCAPE_LEFT
Ti.UI.LANDSCAPE_RIGHT
Use "if else" and accordingly set the images.