I don't use IB. I am laying everything out with code.
I have a UIToolbar on top of a view.
I am setting its height to 64 or something and the width obviously to stretch horizontally to fit screen width.
When I first launch the app, everything is perfect. I change the orientation, toolbar resizes, all good.
Now comes the animation part.
When I swipe up on the view, the toolbar should move up on top of the screen and hide.
When I swipe down on the view, the toolbar should come back down.
I tried setting the constraints in the following manner.
Initially this.
// for width
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-[toolbar]-|" options:0 metrics:nil views:viewDict]];
// for height
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:[toolbar(toolbarHeight)]" options:0 metrics:metricDict views:viewDict]];
Now, during Swipe Up
[self.view removeConstraint:[NSLayoutConstraint constraintWithItem:self.toolBar attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1 constant:0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.toolBar attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1 constant:0]];
But it is breaking the constraint that is supposed to bring it back down and staying up.
Needless to say, it is driving me mad. Any solutions?
EDIT:
On closer analysis, the "removeConstraint" wasn't working as expected. Basically, it wasn't removing the constraint I wanted it to remove. self.view.constraints is an NSArray. Now I need to find a simple way to remove the exact constraint I want.
So you just need to create your heigh constraint using the long form for creating a single constraint. And then assign it to a property.
Then all you have to do is change the constant value.
So swipe up would set the height constraint constant to zero. Swipe down would change the height constraint constant to desired height.
You don't need to add and remove that constraint every time.
Related
I’m facing a trouble with a UILabel in a reusable UICollectionViewCell.
The label can be placed in the UICollectionViewCell frame in different positions.
It can have different font sizes and it must be maximum 3 lines (Truncate Tail).
In order to do it I remove constraints (potentially inherited from another dequeued cell) programmatically like this:
[self.lblPadName removeConstraints:self.lblPadName.constraints];
for (NSLayoutConstraint *constraint in self.contentView.constraints) {
if (constraint.firstItem == self.lblPadName || constraint.secondItem == self.lblPadName) {
[self.contentView removeConstraint:constraint];
}
}
And I programmatically add the center alignment in contentView, the distance from the bottom, the vertical and horizontal constraints using a priority of 500 for the vertical one (Content Hugging Priority Vertical is 1000 and Content compression Resistance Priority vertical is 1000).
Here how i add the vertical and horizontal constraints.
[self.contentView addConstraint:[NSLayoutConstraint
constraintWithItem:self.lblPadName
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:self.contentView
attribute:NSLayoutAttributeWidth
multiplier:multiplier //0.92f
constant:0.0]];
NSArray *lblPadName_constraints_Height = [NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:#"V:[%#(%##500)]", kTitleViewKey, kTitleKeyHeight] options:0 metrics:self.metrics views:self.viewsDictionary];
[self.lblPadName addConstraints:lblPadName_constraints_Height];
In the storyboard i also set the preferredmaxlayoutwidth of the label and its maximum number of lines.
Each cell is provided by an handle user can use to resize the cell (The UICollectionView uses a flow layout).
The data source for the collectionView is provided by a NSFRC which has a delegate that reload the changed items when the model is updated.
In the cellForRowAtIndex the setup method of the dequeued cell is called and since now no problems: the text is correctly on two lines.
The frustrating problem comes out when I try to resize the cell and the system saves on CoreData the new size.
The NSFRC call its delegate, the UICollectionView reloads its data but the UILabel now has the height i passed as a constraint and the text is forced to be in one line.
It seems that the Content Hugging Priority Vertical and Content compression Resistance Priority don't affect the label's height.
I'm using iOS8.
How can I make the UILabel bound perfectly fits the internal text using constraints, Hugging Priority Vertical and Content Compression Resistance Priority?
I am having a lot of problems understanding constraints made in code. I have this container view that is created and set in IB and then in that container NSView's initWithFrame I add the child NSView like this (self is the container view):
childView = [[NSView alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, tabContainerHeight + tabContainerTopSpace)];
[childView setTranslatesAutoresizingMaskIntoConstraints:NO];
[self addSubview:childView];
NSLayoutConstraint *tabContainerConstraint = [NSLayoutConstraint constraintWithItem:childView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1.0f constant:0.0f];
[childView addConstraint:tabContainerConstraint];
tabContainerConstraint = [NSLayoutConstraint constraintWithItem:childView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeading multiplier:1.0f constant:0.0f];
[childView addConstraint:tabContainerConstraint];
tabContainerConstraint = [NSLayoutConstraint constraintWithItem:childView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTrailing multiplier:1.0f constant:0.0f];
[childView addConstraint:tabContainerConstraint];
The problem right now is that the child view is not visible at all, I don't know what happens to it. What I want to do is to have the child view to always have its top exactly at the container view's top and the same goes for left and right, so the child view must have a fixed height but always placed at the top of the container view and then stretch to the sides with the container view (like in the attached image if it explains it).
How is this done from code?
Thank you
Søren
There are a few problems here.
First, you're using initWithFrame: and then turning on autolayout - this means your frame information is going to get discarded. You need a height constraint for your child view.
Second, you're adding the constraints to the child view instead of its superview. The autolayout system may be able to figure this out but the constraints should really be added to self in this case.
You can check the frames of your views in the debugger or an introspection tool like Reveal to see where things might be going wrong - I'd guess in this case you have a height of zero in your child view.
Thirdly (this one isn't necessarily a problem), the code you're using is unnecessarily verbose. The individual creation format is good to help understand the constraints you are making and good for complex cross-hierarchy constraints but it can leave you with ambiguous layouts or adding constraints to the wrong views. The layout you are after is well suited to using the visual format language - it would only be two statements:
For your horizontal layout:
#"|[childView]|"
For your vertical layout:
#"V:|[childView(==height)]"
Where height is either a key in your metrics dictionary, or you replace it with the hard coded height number.
I've written in tedious detail about the various ways to create constraints in code: visual format language and individual constraints. These are iOS focused but autolayout is very similar on both frameworks.
I have an NSImageView in a NSView set up in IB. The NSImageView is exactly the same size as the NSView.
Everything works fine and the NSImageView have the same size as the NSView when resizing the window.
BUT, now I've added an animation (move from A to B) to the NSImageView and that will mess up the constraints that's been set up in IB. So I have to do this programmatically.
How could I programmatically set NSLayoutConstraint to have my NSImageView have the same size as my NSImageView (the superview)?
UPDATE:
Just to give you guys some more information. My app uses a split view (three views) and instead of adding the NSImageView in IB I now add it programmatically. I add my new view (which shall be scalable to it's parent view) to the third view in the split view.
Do you think the split view is causing these issues?
UPDATE 2:
Ok, I'm closer to fixing this. I removed the NSImageView from the view, and added a NSView instead. The NSView scaled fine, but as soon as I added the NSImageView it stopped working in the way that the NSImageView won't scale after resizing the window.
In other words, the problem lies in the NSImageView itself. It won't scale after resizing the window...
SOLVED
I solved it by using PDF View instead of image view (it was a PDF I wanted to show). I set the autoScales property to YES on the PDF View.
I assume you already have references to the views in the example below:
NSView * parentView;
NSImageView * imageView;
[imageView setTranslatesAutoresizingMaskIntoConstraints:NO]; //Required to opt-in to autolayout
[parentView addSubview:imageView]; //Subview must exist before adding constraint.
NSDictionary * views = NSDictionaryOfVariableBindings(imageView);
[parentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[imageView]|"
options:0
metrics:nil
views:views]];
[parentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[imageView]|"
options:0
metrics:nil
views:views]];
Simply, I have an NSView with a bunch of subviews. In the awakeFromNib method (inside the view's controller), I decided to add the following:
[_backgroundImageView setWantsLayer:YES];
[[_backgroundImageView layer] setShadowOpacity:1.0f];
[[_backgroundImageView layer] setShadowOffset:NSMakeSize(-3, -3)];
The backgroundImageView is at the back of all the subviews. But, when I added the previous code, it draws the shadow correctly, but also draws the backgroundImageView above all other layers. Why? How I can Fix that?
You need setWantsLayer:YES in code for the superview.
Turn's out I should enable the layer for the superview (self.view), too. Not only that, but I should tighten up the imageView's frame, or else it will be scaled "axis independently" even though it is set to "Proportional up or down".
I've created in Interface Builder a NSSplitView with two subviews. I want the left-side view to have fixed width. I've tried to define autosizing rules for both subviews but the left subview still changes width on window resizing (split view fills up a window). May be that caused by NSSplitView's Autoresizes Subviews property? (I can't uncheck it). What can I do?
The best way I found to do this in Interface Builder:
Drop the NSSplitView on the window
Select the Custom View you want fixed
Go up to the Xcode menu and select Editor > Pin > Width
Adjust the Constant in the Attributes Inspector to the size that you want the panel to be fixed at
Of course, you can also add this layout constraint through code as suggested above if you're feeling adventurous.
The behavior that you want required some code that you can do on the NSSplitView's delegate. However, you can have the same result using BWToolKit.
I think it should work with a NSLayoutConstraint, I work at the moment on at :).
EDIT:
Maybe to provide more details on my answer based on the comment hayden. You can define a constraint either by code or in the the IB.
In the IB select your left subview and click on the constraint buttons in the lower right corner defining a width constraints. If you select this new constraint now you can setup the the width an say it should be equal and set the size you like.
The seconed way is to create in code a NSLayoutConstraint object, i do it like this (this is just an example, and define not a fix width).
// define for the view: Constraint and AutoresizingMask option
NSView *view = self.view;
[view setTranslatesAutoresizingMaskIntoConstraints:NO]; // disable AutoresizingMask
NSDictionary *views = NSDictionaryOfVariableBindings(view);
[view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"[view(>=140,<=220)]" options:0 metrics:nil views:views]];
In general you find documentation to this topic under the term Auto Layout. To use it you have to enable auto layout and this featuer replace the old autosizing functions. (therefore i disable autosizing mask in the code).
This feature is quit new and you can do complex stuff with it but i think I is worth to study.