UITableViewCell Image full-size with right aspect ratio - objective-c

I have created a tableviewcell. In it is a Image. I want to display the image over the full width of the column.
For that I have added constraints all set to zero for:
- Leading space
- Trailing space
- Top space
- Bottom space
I have also defined an Aspect Ratio constraint 8:6 to get the correct aspect ratio for the image.
In Interface Builder I get the "red arrow" error that "Need constraints for: X position of width".
When I run the code (it is compilable) it is displayed nicely. However I get runtime constraints warnings:
Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this:
(1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it.
(
"<NSLayoutConstraint:0x60800008cfd0 UILayoutGuide:0x6080001a5080'UIViewSafeAreaLayoutGuide'.bottom == UIImageView:0x7fc9fa90fa10.bottom + 8 (active)>",
"<NSLayoutConstraint:0x60800008d2a0 UIImageView:0x7fc9fa90fa10.centerY == UILayoutGuide:0x6080001a5080'UIViewSafeAreaLayoutGuide'.centerY (active)>",
"<NSLayoutConstraint:0x60800008d2f0 UIImageView:0x7fc9fa90fa10.top == UILayoutGuide:0x6080001a5080'UIViewSafeAreaLayoutGuide'.top + 7 (active)>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x60800008d2a0 UIImageView:0x7fc9fa90fa10.centerY == UILayoutGuide:0x6080001a5080'UIViewSafeAreaLayoutGuide'.centerY (active)>
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
I do not see what I'm doing wrong, can someone point me in the right direction?

The problem is that whenever your cell size does not have a ratio of 8:6 your constraints will conflict.
There are several ways to fix this, but I think the easiest is to replace the leading and trailing constraints with a center horizontally constraint. The image will now be centered, its height is set by the cell's height, and its width will be set by the aspect constraint. The only thing to watch out for is if the cell becomes narrower than 8:6, in which case the image will extend outside the left/right edges.

Related

AutoLayout warning after update tableview cell frame with UIWebView inside

I have a custom TableViewCell with image, label, and webview inside, after calculate webview size I update cell height only for cells which loaded web content.
(
"<NSLayoutConstraint:0x7ffa58c20680 UIImageView:0x7ffa58c1fe50.top == UILabel:0x7ffa588c9660'Nguy\U00ean Tuyen'.top>",
"<NSLayoutConstraint:0x7ffa58c20720 UILabel:0x7ffa588c9660'Nguy\U00ean Tuyen'.top == UITableViewCellContentView:0x7ffa588c94e0.topMargin>",
"<NSLayoutConstraint:0x7ffa58c20950 V:[UIImageView:0x7ffa58c1fe50]-(16)-[UIWebView:0x7ffa588c9ee0]>",
"<NSLayoutConstraint:0x7ffa58c20a90 V:[UIWebView:0x7ffa588c9ee0]-(NSSpace(8))-[UILabel:0x7ffa588c99d0'1 Tr\U1ea3 l\U1eddi']>",
"<NSLayoutConstraint:0x7ffa58c20ae0 UILabel:0x7ffa588c99d0'1 Tr\U1ea3 l\U1eddi'.bottom == UITableViewCellContentView:0x7ffa588c94e0.bottomMargin + 5>",
"<NSLayoutConstraint:0x7ffa58c295b0 'UIView-Encapsulated-Layout-Height' V:[UITableViewCellContentView:0x7ffa588c94e0(0.5)]>"
)
Please tell me how to fix this!
Thank you.
There are two cases when it comes to AutoLayout warnings:
1. Ambiguity
In this case, there are not enough constraints and so the Interface Builder can't resolve the position or the size of the subview.
2. Conflict
In this case, there are too many constraints. You can either resolve them manually or decrease the priority of the less necessary ones from 1000.
Constraints with a priority less than 1000 are considered optional.

xcode - autolayout - prevent overlap of logo + input with footer button

I am having trouble preventing the text inputs from overlapping the footer button.
The footer has been anchored to the bottom of the screen. All the elements up top (logo, title label, and 2 input boxes) all have relative constraints. I try to add a constraint between that last input and the footer button but it pushes the footer off the screen on the smaller iphone.
What do I do??
https://github.com/civilordergone/taskfort_ios
Your issue seems to be in landscape only (I ran your code), where you have, for example, 320 points of vertical space, and an image (128pt), a text label (120pt), two text fields (30 each, for 60pt in total) and a 30pt button at the bottom. Already that's 338pt used, and we haven't accounted for the vertical spacing between your objects.
There simply isn't enough vertical space for all of these items to be vertically positioned while retaining their heights, so something has to be flexible: something has to be able to be vertically shrunk/compressed. Your logo and app name (Taskfort) are two candidates.
Here are some of the changes and/or points of consideration:
An ImageView with a height and a width equality constraint will always be that size, but for your layout, it has to be able to be compressed. I removed the height & width constraints and added an Aspect Ratio constraint, so the logo keeps its aspect ratio, but can now scale. I added a relationship constraint between the logo's left side and the left side of the Taskfort label.
The image has a relationship to the top of the screen, saying it must be equal or greater (not less than) to 0. This just means "the image can't be pushed off the top", which "less than" would allow it to be. (For example, if the image is pushed off the top by -40 points, that's still "less than 20").
The image has to be allowed to be vertically compressed. There is a property for "Vertical Compression Resistance" that was 250, and is now 249. By setting it to 249, we're saying "If something has to give way, vertically, this object can be compressed." Since we defined an aspect ratio constraint, if it does get compressed vertically, it'll be reduced horizontally by a proportionate amount so as to maintain the proportions of the logo.
To prevent the text fields from overlapping, their relationships are set to "equal or greater than". Same for the Username text field to the label.
The challenge was in defining the relationship between Password and the Create Password button at the bottom. I added a constraint that says their vertical distance must be greater than or equal to 20. This has a priority of 1000 (by default), so at all times, you get 20pt or greater between those two. Without this, your password field and your button overlap.
While step 5's constraint solves the overlap problem, it creates a new one in portrait orientation, where the password is now 20pt from the button, instead of being lovely white space. To fix that, we add a second constraint between the password field and the button, and specify that the vertical distance is to be 228pt between them both. Now that creates a constraint conflict because you now have two constraints that are both trying to define the vertical relationship between the button and the text field. The 20-pt one is required, it has to be there. But the other one is just a "nice to have, if we can fit it".
So you set the priority of the new one (the 228pt) to be low, such as a Priority of 250. Then the layout engine will use the required one (must be 20 pt or greater) and then it sees the other one ("make them 228") and it tries to do that. If it can't, such as in landscape, then it doesn't do it and doesn't complain, because you have the other constraint already that provides positioning information. If you're in portrait and you have enough space such that it can also apply the low priority constraint, then it'll do that too, and your portrait layout now gets a bigger gap between top and bottom.
When testing these layouts, use the Assist Editor in Preview split-screen mode so you can see the affects of your changes without needing to run the simulator. Here's a guide on that.
Sounds like you're using an equality constraint, such as "the distance between lastInput.bottom and footer.top equals 20". Instead, try an inequality operator, such as "the distance between lastInput.bottom and footer.top is equal or less than 20".
The attributes inspector for a constraint can let you change an equality to an inequality. Alternatively, you can double-click the constraint line (the UI in the storyboard editor) to get a quick pop-up for that.

Embedded .xib appearing in wrong position

I was hoping this was an iOS 8 bug (it still might be; everything works fine in iOS 7) but I'm still seeing it in the iOS 8 GM Seed.
I have a CategoriesView.xib embedded in DetailView.xib. When the DetailView.xib is displayed, the placeholder UIView displays in the right location, but the contents of CategoriesView.xib appear exactly 72px above where they're supposed to. I'm using Autolayout. The 72px seems to be 20px status bar + 44px navigation bar + 8px auto layout constraint from the top of the image.
Inside CategoriesView.xib, there are actually 5 little icons representing each possible category. Each icon has a width/height constraint and a leading space constraint to add padding from its neighbor. Typically a screen will only show 1-2 categories, and I accomplish this with this code:
// all width constraints are part of the categoryViewsWidthConstraints Outlet Collection
// all padding constraints are part of the categoryViewsSpacingConstraints Outlet Collection
// loop through my outlet collection, and set all width and padding constraints to 0
for (int i = 0; i < self.categoryViewsWidthConstraints.count; i++) {
[self.categoryViewsWidthConstraints[i] setConstant:0.0];
[self.categoryViewsSpacingConstraints[i] setConstant:0.0];
}
// now, for the categories that need to show, add the width and padding constraints back
for (int i = 0; i < self.categoryIds.count; i++) {
NSNumber *categoryId = self.categoryIds [i];
[self.categoryViewsWidthConstraints[categoryId.integerValue - 1] setConstant:20.0];
[self.categoryViewsSpacingConstraints[categoryId.integerValue - 1] setConstant:8.0];
}
Again, this works fine in iOS 7.
I thought I had this working when, inside CategoriesView.m, I set:
self.contentView.translatesAutoResizingMaskintoConstraints = true.
That gives me the correct vertical placement I'm after, but unfortunately I get auto layout errors because it thinks CategoriesView needs to be exactly 132px wide. Because of this, the last category icon gets stretched:
I'm at a loss here. I know this is pretty nuanced, but any ideas?
I tried everything I could think of, and just could not get this to work.
My solution? I simply created a brand new file and reconstructed all the elements and all the constraints. And it worked perfectly.
So so frustrating, but things are finally back to normal. I think it had something to do with the transition from Xcode 5 to Xcode 6.

Two NSTextFields with interdependent widths in autolayout

I’m trying to put together what seems to be a simple case of two NSTextFields with dynamic width and fixed spacing in between. I cannot figure out an effective way to do so though.
I’m looking to get something like this:
The blue boxes are the NSTextFields. When more text is entered into one, it should grow and thus make the other one shrink, maintaining the lead space, trailing space and the spacing in between the fields. The first one should take the priority if both of the fields have too much text. Each field will also clearly have a maximum and a minimum possible width it can reach.
How would I go around handling this, preferably utilising IB autolayout as much as possible?
It seems to me that all of constraints you mentioned directly translate into interface builder --
First view has width >= something.
First view has width <= something
Same for Second view.
Space between views is fixed.
Second view wants to be as small as possible (have its width at 0) but this has lower lower priority than the previous constraints and lower priority than inner content size constraints.
The code I had to add to my view controller, after applying the constraints as per the ilya’s answer:
In controlTextDidChange (_controlWidthConstraint refers to the fixed width constraint of the input; it’s probably 0 by default for the second input):
// Get the new width that fits
float oldWidth = textControl.frame.size.width;
[input sizeToFit];
float controlWidth = textControl.frame.size.width;
// Don’t let the sizeToFit method modify the frame though
NSRect controlRect = textControl.frame;
controlRect.size.width = oldWidth;
textControl.frame = controlRect;
_controlWidthConstraint.constant = controlWidth;
The key lies in invalidating the intrinsicContentSize for the text field when text is input.
You can check a sample project here, to get you on the right track.

Zedgraph textobj X location depends on text length?

I have a Zedgraph textobj which I want to place always in the same x, y position (ASP.NET image). I noticed that the text doesn't always show in the same starting x position. It shifts depending on the text's length. I tried to have the text to have the same length by padding it with spaces. It helped a little but the result is not always consistent. I am using PaneFraction for coordType.
What's the proper method to have a piece of text to always show in the same x position. I am using textobj as a title because the native title property always shows up centered and I need my title be left aligned to the graph.
No, it does not depend on text lenght, however...
It depends on various other things:
Horizontal and vertical align of the text box (see: Location )
Current size of the pane. The font size is scaled dynamically to fit the changing size of the chart.
Counting proper positions to have TextObj (or any other object) always at the same place is quite hard. So you need avoid as much as you can any numbers/fractions in your location coordinates. ZedGraph sometimes calculates the true position in quite odd way then.
You haven't provided any code, so it's hard to tell if and where you made the mistake (if any). But, if I were you, I would do something like that:
TextObj fakeTitle = new TextObj("some title\n ", 0.0, 0.0); // I'm using \n to have additional line - this would give me some space, margin.
fakeTitle.Location.CoordinateFrame = CoordType.ChartFraction;
fakeTitle.Location.AlignH = AlignH.Left; // Left align - that's what you need
fakeTitle.Location.AlignV = AlignV.Bottom; // Bottom - it means, that left bottom corner of your object would be located at the left top corner of the chart (point (0,0))
fakeTitle.FontSpec.Border.IsVisible = false; // Disable the border
fakeTitle.FontSpec.Fill.IsVisible = false; // ... and the fill. You don't need it.
zg1.MasterPane[0].GraphObjList.Add(fakeTitle);
I'm using ChartFraction coordinates instead of PaneFraction (as drharris suggests) coordinates to have the title nicely aligned with the left border of the chart. Otherwise it would be flushed totally to the left side (no margin etc...) - it looks better this way.
But make sure you didn't set too big font size - it could be clipped at the top
Are you using this constructor?
TextObj(text, x, y, coordType, alignH, alignV)
If not, then be sure you're setting alignH to AlignH.Left and alignV to AlignV.Top. Then X and Y should be 0, 0. PaneFraction for the coordType should be the correct option here, unless I'm missing your intent.
Alternatively, you can simply download Zedgraph code, edit it to Left-align the title (or even better, provide an option for this, which should have been done originally), and then use it in production. Beauty of open source.