Probably a very trivial Swift question.
I've got a view on my storyboard with various UIelements (labels, images etc).
What I want to do is change the position of some of these elements through code (so not using the storyboard or autolayout features).
When I create my elements dynamically I can just type:
distanceLabel.frame = CGRectMake( 100, 200, 50, 50); // set new position exactly
or
distanceLabel.frame.origin = CGPoint(0,0)
However this doesn't work for elements on my storboard (I'm calling them through the IBOutlets I've created). Any simple trick / tip / hint to do this?
Many Thanks
You can use outlets to modify constraints. Set constant property by code to modify the layout.
Related
I create a XIB in Xcode and add a simple view as a subview:
What I want to achieve is that the subview has a fixed size and the rootview automatically resizes to the size of that subview, leaving a margin of 20.0 around it:
So I add a fixed width and a fixed height constraint to the subview. Then I add the four constraints for the 20.0 margin:
As the superview does not have any constraints there should be neither ambiguity nor conflicting constraints: I would expect the superview to shrink down in order to match the constraints. However, Xcode complains:
These constraints would only be conflicting if the rootview had a fixed size and that appears to be the case. So my question is: How can I make the rootview of a XIB flexible so that it dynamically adjusts its size to match its contents?
(Is that even possible with Interface Builder?)
How can I make the rootview of a XIB flexible so that it dynamically
adjusts its size to match its contents?
Not possible Interface builder.
As the superview does not have any constraints there should be neither
ambiguity nor conflicting constraints
Its not just a super view. Its also an objet in nib. We define simulated size for such views. This could be used to silence the errors. But again these are just simulated.
Is this rootView a view controllers view ? If yes i don't understand why are you trying to fix its withd to 280 and height to 168.
If this view is a custom view that you are going to add to another 'parent' view. Then you should change you simulated size to with 280 and height 168, and when adding this as subview you need to add two more constraints to position this rootview in the 'parent' view.
I had a same issue. I have a view in xib, which had dynamic content and it needed to fit into other superviews. so here is the answer how I achieved that
First you need to
myViewFromXib.translatesAutoresizingMaskIntoConstraints = false to prevent translating autoresizing mask into constraints. Then add subview superViewForMyViewFromXib.addSubview(myViewFromXib). And just add your constraints to superview like this:
NSLayoutConstraint.activate([
(myViewFromXib.topAnchor.constraint(equalTo: superViewForMyViewFromXib.topAnchor, constant: 0))!,
(myViewFromXib.bottomAnchor.constraint(equalTo: superViewForMyViewFromXib.bottomAnchor, constant: 0))!,
(myViewFromXib.leadingAnchor.constraint(equalTo: superViewForMyViewFromXib.leadingAnchor, constant: 0))!,
(myViewFromXib.trailingAnchor.constraint(equalTo: superViewForMyViewFromXib.trailingAnchor, constant: 0))!
])
superViewForMyViewFromXib.setNeedsLayout()
You can do this by editing the xib manually, for example to set a height constraint (in my case it was an inequality to set the minimum height):
add a constraint to a subview for the height
open the xib as a text file
find the constraint you added (eg by Cmd-F'ing to the value of the height)
cut and paste it into the root view's constraint section
Open the xib in interface builder again
The constraint appears and you can edit it like normal.
OMG, I cant believe you accept that this is not possible and change your way , if this was not possible then Xib would be useless. please don't provide wrong info to others your question is well detail but answer is more than poor:
answer is more than easy :
subview.frame.size.height = rootView.frame.size.height
subview.frame.size.width = rootView.frame.size.width
I'm using an NSToolbarItemGroup to group a set of NSToolbarItem's together. Currently there is a 2pt space between each item in the group, ideally I would like them to be completely merged visually similar to an NSSegmentedControl.
After inspecting the Mail application it looks like they are using a custom NSToolbarItem containing an NSSegmentedControl. I have tried this in the past but I cannot figure out how to get individual labels under each component and to have each component show up individually in the 'overflow' menu.
Current Look:
Desired Look:
I know 'Centered' is being clipped, this is just a quick implementation.
You can add an NSToolbarItem object to the toolbar, and then set the NSViewController like this (using Swift):
runStatus.view = RunStatusView()
where "runStatus" is the name of the #IBOutlet for the NSToolbarItem, and "RunStatusView" is an NSView object with an override on the drawRect method. You can also specify the width and height of the NSView; for example, force the width to be constant at 125:
runStatus.minSize = NSSize(width: 125, height: 32)
runStatus.maxSize = NSSize(width: 125, height: 32)
This can make the NSToolbar items appear closer to each other, depending on what you are drawing on them.
Finally, if you still cannot get exactly what you want, then make the group of buttons a single NSToobarItem, and in "RunStatusView" (using the above example) draw it however you want, and override the mouseDown event (also in "RunStatusView") to see where exactly the user is clicking. Then there's one NSToolbarItem that essentially acts like multiple buttons, and you have total control and can make it behave however you want.
I can suggest you to use NSSegmentedControl added to a NSToolbarItem like in a picture below.
You need some labels under the buttons (like "Reply" etc.).
To achieve this you can set NSToolbarItem label-property and play with space between words.
I am attempting to change the coordinates of an NSButton that is contained within a parent NSView and something is clearly not working, because the button position does not change. Both elements are defined in a nib file and the parent view has animation applied to it using CoreAnimation.
I have tried the following.
button.frame.origin.x = 500
and...
var frame:CGRect = button.frame
frame.origin.x = 500
button.frame = frame
Even with the animations disabled, I can not seem to dynamically position the subview. Is there some feature that prevents children views from being positioned programmatically?
Please note that I am using Swift with XCode 6.3.1.
I'm guessing you're using AutoLayout constraints, given you're using the latest tools.
If so, setting a subview's frame directly won't work the way you're expecting (if it does anything at all, it'll cause strange drawing glitches / flashing when mixed with animation). You have to create outlets for your layout constraints and modify them.
If you're not using AutoLayout, I suggest having a look at your button outlet to make sure it's actually connected (ie, you're not talking to nil). Even if the outlet is connected, make sure it's not nil at runtime - you may be trying to talk to the button before the nib is loaded and the outlet / action connections are restored.
I'm using Xcode 6 beta 5 at the moment, eager to try out the cool self-sizing collection view cells functionality introduced in iOS 8. It was introduced in the WWDC 2014 session 226: "What's New In Table Views and Collection Views". Links:
https://developer.apple.com/videos/wwdc/2014/
http://asciiwwdc.com/2014/sessions/226
http://blog.indragie.com/
All you gotta do, they said, is that you have to set auto-layout constraints on the contentView of your collection view cell or implement sizeThatFits:. The former sounds easier, so I definitely want to use auto-layout.
When got into Storyboard editor (or IB) though, it appears that you you cannot access the contentView property of a prototype collection view cell. Is this true?
I did set a few constraints between a label (direct subview of the prototype cell) — I pinned its four edges to the cell's bounds itself, hoping that the label's intrinsicSize would provide the needed width for the cell. No avail: I verified that none of these pinning constraints were applied onto the contentView:
- (void)awakeFromNib
NSLog(#"%s... contentView.constrants == %#", sel_getName(_cmd), self.contentView.constraints);
}
... prints out...
awakeFromNib... contentView.constrants == (
)
... no matter what constraints I set in Storyboard.
Am I missing something or must I do this auto-layout in code?
I have a view that needs to have its frame manipulated programmatically - it's a kind of document view that wraps to its content which is then scrolled and zoomed around a superview by manipulating the frame origin. Autolayout fights with this at runtime.
Disabling autolayout completely seems a bit harsh because it could reasonably be used to handle layout for the other views. It seems like what I might want is some kind of "null constraint".
I had the same problem. But I have resolved it.
Yes, you can disable auto layout at runtime for a specific UIView, instead of disabling it for the whole xib or storyboard which is set by default in Xcode 4.3 and later.
Set translatesAutoresizingMaskIntoConstraints to YES, before you set the frame of your subview:
self.exampleView.translatesAutoresizingMaskIntoConstraints = YES;
self.exampleView.frame = CGRectMake(20, 20, 50, 50);
I had a similar issue where Autolayout was overriding some of my frame-setting at run time (I had a dynamic view that in some cases pushed a new view controller...pushing and then pressing Back would reset the initial view).
I got around this by putting my manipulation code in viewDidLayoutSubviews of my View Controller. This seems to get called after whatever constraint mojo gets called, but before viewDidAppear, so the user is none the wiser.
Perhaps just setting translatesAutoresizingMaskIntoConstraints to YES (and not adding additional constraints affecting that view) will let you set the frame without fighting the auto layout system.
In iOS 8 you can set an NSLayoutConstraint to be active or not. So if I'm using interface builder, I add all my constraints to an OutletCollection and then activate or deactivate using:
NSLayoutConstraint.deactivateConstraints(self.landscapeConstraintsPad)
NSLayoutConstraint.activateConstraints(self.portraitConstraintsPad)
The particular application I'm using it for here is having different constraints in portrait and landscape mode and I activate/deactivate based on the rotation of the device. It means I can create some complex layout changes all in interface builder for both orientations, and still use auto layout without the verbose auto layout code.
Or you can activate / deactivate using removeConstraints and addConstraints.
I don't know if this will help anyone else, but I wrote a category to make this convenient because I find myself doing this a lot.
UIView+DisableAutolayoutTemporarily.h
#import <UIKit/UIKit.h>
#interface UIView (DisableAutolayoutTemporarily)
// the view as a parameter is a convenience so we don't have to always
// guard against strong-reference cycles
- (void)resizeWithBlock:(void (^)(UIView *view))block;
#end
UIView+DisableAutolayoutTemporarily.m
#import "UIView+DisableAutoResizeTemporarily.h"
#implementation UIView (DisableAutoResizeTemporarily)
- (void)resizeWithBlock:(void (^)(UIView * view))block
{
UIView *superview = self.superview;
[self removeFromSuperview];
[self setTranslatesAutoresizingMaskIntoConstraints:YES];
__weak UIView *weakSelf = self;
block(weakSelf);
[superview addSubview:self];
}
#end
I use it like this:
[cell.argumentLabel resizeWithBlock:^(UIView *view) {
[view setFrame:frame];
}];
Hope it helps.
You can set the translatesAutoresizingMaskIntoConstraints type Boolean, Value Yes in the User Defined Runtime Attributes of the UIView you want in the xib/storyboard.
In my view I had a Label and a Text. The label had pan gesture. The label moves around fine during drag. But when I use the text box keyboard, the label resets its position to the original location defined in auto layout. The issue got resolved when I added the following in swift for the label. I added this in viewWillAppear but it can be added pretty much anywhere you have access to the target field.
self.captionUILabel.translatesAutoresizingMaskIntoConstraints = true
Open project in 4.5
Select storyboard
Open the file inspector
Under Interface Builder Document uncheck 'Use Autolayout'
You can split across multiple storyboards if you want to use autolayout for some views.
For me it worked to create the subview programmatically, in my case the auto layout was messing with a view that I needed to rotate around its center but once I created this view programmatically it worked.
I've encountered a similar scenario, where I joined a project that was initiated with auto-layout, but I needed to make dynamic adjustments to several views. Here is what has worked for me:
Do NOT have views or components laid out in interface builder.
Add your views purely programmatically starting with alloc/init and setting their frames appropriately.
Done.
This happened to me in a project without storyboards or xib files. All 100% code. I had an ad banner at the bottom and wanted the view bounds to stop at the ad banner. The view would resize itself automatically after loading. I tried every resolution on this page but none of them worked.
I ended up just creating a sub view with the shortened height and placed that in into the main view of the controller. Then all my content went inside the sub view. That solved the problem very easily without doing anything that felt like it was going against the grain.
I am thinking if you want a view that is not the normal size that fills the window then you should use a sub view for that.
Instead of disabling autolayout, I would just calculate the new constraint with the frame you are replacing. That appears to me to be the appropriate way. If you are adjusting components that rely on constraints, adjust them accordingly.
For example, if you have a vertical constraint of 0 between two views (myView and otherView), and you have a pan gesture or something that adjusts the height of myView then you can recalculate the constraint with the adjusted values.
self.verticalConstraint.constant = newMyViewYOriginValue - (self.otherView.frame.origin.y + self.otherView.frame.size.height);
[self.myView needsUpdateConstraints];
For those of you who are using auto layout, please check out my solution here. You should be making #IBOutlet's of the constraints you want to adjust and then change their constants.
if it's xib file:
select the .xib file
select the "File's Owner"
show the Utilities
click on: "File Inspector"
Under "Interface Builder Document" disable: "Use Autolayout"