I have a View controller, in which the view has two image views and two text views. I turned off auto layout, and I programmatically set the distance between the first text view and the first image view by using this code:
The following code is in the viewDidLoad method of my custom view controller class. I have set the autoresizing mask to no in both cases, so I have no idea why the code doesn't work.
(tf2_logo is the image view and itemName is the text view)
self.tf2_logo.translatesAutoresizingMaskIntoConstraints = NO;
[self.backpackBackground addConstraint:[NSLayoutConstraint constraintWithItem:self.itemName attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.tf2_logo attribute:NSLayoutAttributeTop multiplier:1.0 constant:-1.0]];
[self.backpackBackground addConstraint:[NSLayoutConstraint constraintWithItem:self.tf2_logo attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.backpackBackground attribute:NSLayoutAttributeLeft multiplier:1.0 constant:17]];
Now I want to do the same thing with my other text view, basically I wanted to keep the distance between the itemName text view and the text view at a certain distance. I used this code:
(tf2 is my other text view)
self.tf2.translatesAutoresizingMaskIntoConstraints = NO;
[self.backpackBackground addConstraint:[NSLayoutConstraint constraintWithItem:self.itemName attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.tf2 attribute:NSLayoutAttributeTop multiplier:1.0 constant:-3.0]];
[self.backpackBackground addConstraint:[NSLayoutConstraint constraintWithItem:self.tf2 attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.tf2_logo attribute:NSLayoutAttributeRight multiplier:1.0 constant:20]];
After implementing this code, the tf2 text view doesn't even show up in the view controller. What is the problem?
EDIT: You can download the whole project here: https://www.dropbox.com/sh/u820u2ndyrncuz8/P4atI-9CAx
EDIT#2:
You mentioned that you turned off auto layout, because UITextView has that little gap on top in iOS7. To remove the gap, try this:
self.tf1.textContainerInset = UIEdgeInsetsZero;
When you log the original value of the textContainerInset it shows: {8, 0, 8, 0} . The two 8's are responsible for the gap (one at the top). The line above sets all values to zero and the content is nicely aligned to the top of the frame.
(EDIT#1: Completely changed the answer)
I assume you primarily want to have a flexible height of the imageName UITextView. First I suggest to use auto layout. You can set constraints in Xcode according to the following image:
The red lines are the constraints. The green line is special: It shall be a height constraint and you create an outlet for it in the view controller. (Open the document outline view, locate the height constraint in the tree and control-drag it to the code.)
Then in the viewDidLoad method:
CGSize size = [self.tf1 sizeThatFits:self.tf1.frame.size];
self.tf1Height.constant = size.height;
The height of the "lore ipsum" field now adjusts to its content.
Have you tried using frames instead of constraints? If your not using autolayout I think frames might be easier to read/implement.
sample:
// tf2 will be placed at (0,0) in superview and have width of 100 and height of 20
tf2.frame = CGRectMake(0, 0, 100, 20);
you can play around with different values to get your layout as desired.
Related
i have some problems sizing a detailCalloutAccessoryView that i added programmatically.
Here's the code for the view
HCSStarRatingView *annotationRating = [[HCSStarRatingView alloc] init];
annotationView.detailCalloutAccessoryView = annotationRating;
I tried to init the view with a initWithFrame but somehow that didn't work and i ended up with this.
I then discovered that i have to add NSLayoutConstraint programmatically to size the view correctly, so i added this code for constraints.
NSLayoutConstraint *width = [NSLayoutConstraint constraintWithItem:annotationRating attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:80];
NSLayoutConstraint *height = [NSLayoutConstraint constraintWithItem:annotationRating attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:45];
[annotationRating addConstraint:width];
[annotationRating addConstraint:height];
And the view now looks like this
Now i want to get rid of the white space around it. I think i have to add a top and bottom constraint but i don't know how to do it because I don't know what items i have to relate to.
The excess whitespace is a function of the height that you've chosen. Your image is roughly 5 times as wide as it is tall, but you've asked to render it in a box that 80 x 45 pts (i.e. a view whose height is over half the width, rather than one fifth). If you pick the dimensions of the image view to match (adjusting for scale) the size of the image, you get something more like:
As you can see, with judicious selection of the width and height, there will be less whitespace than in your example. Note, there is some inherent whitespace between the detail accessory view that you cannot control, but by making sure you set the width and height correctly, you can reduce it to these minimal values.
Here is my problem, I have a scroll view scrollExerciseIndex that I use only as a scrolling bar, in this scroll view I place a UIView indexesView and I want it to be always at the center of the scroll view. For this I use layout constraints :
UIView * indexesView = [[UIView alloc] initWithFrame: CGRectMake(xPosition, 0, dimension*numberIndexes, dimension)];
[self.scrollExerciseIndex addSubview:indexesView];
[self.scrollExerciseIndex setContentSize:CGSizeMake(dimension*numberIndexes, dimension)];
if (xPosition != 0) {
NSLayoutConstraint * xCenterConstraint = [NSLayoutConstraint constraintWithItem:indexesView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.scrollExerciseIndex attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0];
[self.scrollExerciseIndex addConstraint:xCenterConstraint];
}
Here is the expected result :
Don't pay attention to all the element, just the bar at the bottom of the screen is my problem.
I have to create view programmatically because sometimes I will activate the constraints, sometimes not and I have to set the frame of the view dynamically. So for now I initialise the view indexesView like so :
UIView * indexesView = [[UIView alloc] initWithFrame: CGRectMake(xPosition, 0, dimension*numberIndexes, dimension)];
(I know, not very original)
I would like to know if there is a way to initialize the view programmatically but to say to auto-layout that it has no constraints on the position because right now if the screen turns in landscape mode there is a conflict as the scrollview's frame changes so the distance between the center of the scroll view (on which I set a constraint) and the position of the subview's frame (xPosition) is no longer the same.
As you can see, the view is no longer at the center of the scroll view and I have some constraints broken.
Will attempt to recover by breaking constraint
NSLayoutConstraint:0x7bed6c50 UIView:0x7bed6ad0.centerX == UIScrollView:0x7e273200.centerX
Thanks for your help.
Ok, I found what I was looking for by reading a book about Audio-Layout.
My problem was that audio layout would create constraints behind my back automatically. When using AutoLayout a type of constraints is created from non-autoLayout specifications (The used to describe interface when auto layout didn't exist). So constraints are created using the initial frame of the view. The only thing I had to do was :
[indexesView setTranslatesAutoresizingMaskIntoConstraints:NO];
to disable this creation of constraints from the frame, and then recreate explicitly the constraints for width and height if needed (which wasn't the case for me, but I still made the test) like so :
`NSLayoutConstraint * widthConstraint = [NSLayoutConstraint constraintWithItem:indexesView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:0 multiplier:1.0 constant:widthValue];
NSLayoutConstraint * heightConstraint = [NSLayoutConstraint constraintWithItem:indexesView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:0 multiplier:1.0 constant:heightValue];
[indexesView addConstraint: heightConstraint];
[indexesView addConstraint: widthConstraint];`
When adding constraints programmatically, don't forget to call : [indexesView setNeedsUpdateConstraints]; so the constraints are recalculated only when needed.
Last info that I read and can be useful in general, when adding a lot of constraints, the apple doc specifies that it is more efficient to use the method :
[myView addConstraints:(NSArray<NSLayoutConstraints *> *)] than to call addConstraint: for each constraint.
Hope it can be useful to someone.
I have a view in an iPad app that on full screen mode expands to fill the entire screen and is available both in portrait and landscape.
This view also contains many subviews (like rectangular cards) and a scrollview.
[ I programmatically add these to a content view, that is created programmatically (in a scroll view) calculating frame size of the cards accordingly ]
contentView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 640, 2000)];
[contentView addSubview:firstCard];
self.formScrollView = [[UIScrollView alloc] initWithFrame:self.view.bounds];
self.formScrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
self.formScrollView.scrollEnabled=true;
self.scrollView addSubview:contentView];
self.scrollView.contentSize=contentView.frame.size;
My requirement is that despite orientation all the cards would be aligned one after the other with equal spaces from both the left and right margin.
The cards though of varying height are all equal in width.
So far, this is what I have tried to set them centered horizontally. I added this code snippet in the viewDidLayoutSubviews
[contentView addConstraint:[NSLayoutConstraint constraintWithItem:firstCard
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:contentView
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0.0]];
where contentView refers to the contentView in the full screen view controller and first card is the first subview card
I also set the property
firstCard.translatesAutoresizingMaskIntoConstraints = NO;
On running in the simulator, I get disastrous results. The view is weirdly offset and the other cards are all scattered everywhere else.
This does not happen when I do not set the constraints. They look ugly but they are still vertically aligned the way they have to be.
I am quite new to auto layout and iOS development.
I do wonder if any of these problems have to do with the fact that my contentView is a fixed frame?
I keep the contentView with such a fixed frame keeping in mind, the non full screen mode.
Where am I going wrong? I would really appreciate any help and advice.
Thanks.
EDIT :-
I also tried aligning my content view such that it remains centered to the scroll view. Here's code for that...
(That was also a disaster, the content view doesn't even appear on screen)
[self.formScrollView addConstraint:[NSLayoutConstraint constraintWithItem:contentView
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self.formScrollView
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0.0]];
}
[where formScrollView is the scroll View ]
You will also have to set the vertical constraint for card views. In your case each view's "top" (starting after first view) will have a relation with the earlier view's "bottom". So that they fall after each other vertically. Can be added as below.
float verticalSpacing = 20.0f;
nextCard.translatesAutoresizingMaskIntoConstraints = NO;
[contentView addConstraint:[NSLayoutConstraint constraintWithItem:nextCard
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:contentView
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0.0]];
[contentView addConstraint:[NSLayoutConstraint constraintWithItem:nextCard
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:previousCard
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:verticalSpacing]];
My task is very simple - just display vertically scrolling text inside custom UIView.
I have an UIScrollView with some container with one UITextView in it. Container is needed to add more items later. I use IB(xib file) to add autolayout constraints like shown below:
But everything I see is:
And it's scrolling horizontally :-(
I've tried setting contentSize of UIScrollView:
At initWithCoder, didMoveToSuperview, willMoveToSuperview = no effect
At custom method, called from main viewcontroller = no scrolling at all, and I see the same picture.
Thanks a lot!
Edit: Text View's and Container View's intristic size are set to "placeholder". I understand that I should limit width of ContainerView, but it should work with all screen sizes and orientations, so setting width in code, IMO, worse than setting constraints.
Yeah! I've found the solution!
If someone facing the same problem:
You should add left and right constraints not to UIScrollView, but to superview of UIScrollView (to super-super-view).
Unfortunately, this cannot be done in IB, but you can do it within code:
[self addConstraint:[NSLayoutConstraint constraintWithItem:self.view
attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual
toItem:self.containerView attribute:NSLayoutAttributeLeft
multiplier:1.0 constant:-30]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:self.view
attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual
toItem:self.containerView attribute:NSLayoutAttributeRight
multiplier:1.0 constant:30]];
Where self.containerView is view inside UIScrolllView and self.view is view outside UIScrollView
So:
You set vertical constraints to UIScrollView and horizontal constraints to top-level view.
In my screen I have two view that are horizontally near to each other. I want the width of first view be twice of the width of second view.
I man for example, if right view has width=200 the second one show by with=100.
As I search and look in auto-layout, it has options for alignments and spaces between views. Do it has option for defining such relationships too?
You can do this programmatically by adding manual constraints that work with autolayout. I'm sure using InterfaceBuilder is also an option.
UIView *firstView;
UIView *secondView;
[firstView addConstraint:[NSLayoutConstraint constraintWithItem:secondView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:firstView
attribute:NSLayoutAttributeWidth
multiplier:2.0
constant:0]];
Note the multiplier there is 2.0 which is where it forces the width to be double.