Autolayout Constraint Error with a single constraint - iphone

I have a scence with a bunch of labels and buttons. When you tap on a button a view slides up from the bottom with controls in it, a kind of keyboard so to say. It "looks" like this:
-----------------------------
| |
| [Button 1] [ Slider 1 ] |
| |
| [Button 2] [ Slider 2 ] |
| |
-----------------------------
This "keyboard" is created at the very beginning when the view loads and the animation is done switching its heigth from 0 to its instrinsic content size. This escene only supports landscape mode and it took me quite a while to keep the "keyboard" on the view when the device rotates 180 degrees.
The problem I see pops up with either of the two following situations:
The device rotates 180 degrees.
The "keyboard" is called.
This problem as follows:
Unable to simultaneously satisfy constraints...
.
.
.
.
(
"<NSLayoutConstraint:0x718c6c0 UIButton:0x717e0d0.centerY == UISlider:0x717d9d0.centerY>",
"<NSLayoutConstraint:0x7190a00 UIButton:0x717e0d0.centerY == UISlider:0x717d9d0.centerY>"
)
The error log gives me this error twice, once for each set of button-slider.
What I think is weird is that the conflicting constraints are exactly the same. I thought I did some copy-paste mistake and added the same constraint twice, but it's not the case.
I'm guessing it has something to do with updateViewConstraints being called upon rotation and also whe I perform the animation, but I cannot see why only these constraints are affected since there are some more in this "keyboard" view.
All and all, this Autolayout is beign quite more difficult than Apples whants to claim. In my opinion, of course.
Any ideas?
EDIT: the constrains are set all in code using mainly the visual language format. The constrains of the controls inside the "keyboard" are added into the "keyboard" view which is the normal thing to do, I believe.
Just to try it out, I changed the problematic constraints and, instead to adding them to the "keyboard" subview, I added them to the self.view ("keyboard" superview). All the sudden, no more errors are shown.
Despite of that, I'd really like some discussion on the matter because I still don't know what's wrong and I just had a lucky shot. I'd really like to undestand it.

The fact that the conflicting constraints are exactly the same is in fact the error. With Auto Layout, you can't have a constraint twice. That will generate the error you see above.
Definitely, you have added the constraint twice. You can see this from the memory addresses. You have two different NSLayoutConstraint instances, 0x718c6c0 and 0x7190a00. However, the instances each refers to are both the same. That being that the vertical center centerY of your UIButton instance 0x717e0d0 should be in the middle of the UISlider 0x717d9d0.
Possibly your updateConstraints method has been called and you haven't checked to see if a constraint already exists before adding it again.

I don't know if this may help you but I just used this tutorial for setting up constraints to buttons and labels in my app

Related

Constraints from code behave differently from interface builder

I'm moving part of UI to code from Interface Builder. After finishing, I'm comparing different branches in Debug View Hierarchy mode - the set of constraints look the same, except different constraints are grayed:
Before:
After:
What does this gray color mean? They all active. The issue is that the grayed constraint on the second picture doesn't work
The gray color highlights the active constraints that Auto Layout is not using due to conflicts or because there are other higher priority constraints it is using.
The problem is that your constraints aren't quite the same.
Before:
superview.bottom = self.bottom + 200 # 750
After:
self.bottom = superview.bottom + 200 # 750
Those aren't the same. To fix the After case, you either need to switch the self.bottom and superview.bottom items or change the constant to -200.

Swift Autolayout warnings and other warnings i do not understand

The app allows users to post images/follow others etc.
So it works fine but i get the following warnings:
(I know some has to do with AutoLayout constraints but how do i know which is causing the problems?)
2015-07-05 17:19:37.701 Pixym[1271:72192] CUICatalog: Invalid asset name supplied:
2015-07-05 17:19:37.702 Pixym[1271:72192] Could not load the "" image referenced from a nib in the bundle with identifier "HP.Pixym"
2015-07-05 17:19:37.705 Pixym[1271:72192] 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.
(Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints)
(NSLayoutConstraint:0x7fa83b822a40 H:[UIImageView:0x7fa83b8529a0(300)],
NSLayoutConstraint:0x7fa83b85ccb0 H:[UIImageView:0x7fa83b8529a0]-(10)-| (Names: '|':UITableViewCellContentView:0x7fa83b871ff0 ),
NSLayoutConstraint:0x7fa83b8643d0 H:|-(10)-[UIImageView:0x7fa83b8529a0] (Names: '|':UITableViewCellContentView:0x7fa83b871ff0 ),
NSLayoutConstraint:0x7fa83b80ab00 'UIView-Encapsulated-Layout-Width' H:[UITableViewCellContentView:0x7fa83b871ff0(375)])
Will attempt to recover by breaking constraint
NSLayoutConstraint:0x7fa83b822a40 H:[UIImageView:0x7fa83b8529a0(300)]
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.
Any help will be appreciated.
From the constraints, it seems you have an imageView with a width of 300 and a left and right padding of 10. That would work fine on iPhone 5(where the screen width is 320) but it will crash on iPhone 6/ 6 Plus because there the width is bigger.
What you need to do, is figure out how would you want the image to look like on all screens. Is the 10 pixels padding more important than the width or you would like it to always have a width of 300?
If you want the width, remove the other 2 constraints and add a center horizontal in container constraint for the image.
In the other case, just remove the width constraints and all should work.
Good luck!

Resizing large UITable grinds app to a halt

I have a UIViewController that contains a UIScrollView which itself contains both a UITableView and another UIScrollView. Inside the nested UIScrollView is another UITableView.
When the in ViewDidAppear of the UIViewController I calculate how big the tables should be (much bigger than the screen) and set their sizes and then set the content size of the UIScrollView to match the tables they contain (the UIScrollView will provide the scrolling rather than the table itself). This all works fine in the simulator, but on an actual device, it grinds to a halt, pegging the processor at ~100% for tens of seconds. This is obviously unacceptable. Does anybody have any idea why? Or how I can work around it?
The code looks something like this:
OuterScrollView.ContentSize = new SizeF (View.Frame.Width, tableHeight);
InnerScrollView.ContentSize = new SizeF (InnerTable.Frame.Width, tableHeight);
InnerScrollView.Frame = new RectangleF(InnerScrollView.Frame.Location,
new SizeF(InnerScrollView.Frame.Width, tableHeight));
// So far so good
OuterTable.Frame = new RectangleF(OuterTable.Frame.Location,
new SizeF(OuterTable.Frame.Width, tableHeight)); // this slows everything down!!
InnerTable.Frame = new RectangleF(InnerTable.Frame.Location,
new SizeF(InnerTable.Frame.Width, tableHeight)); // and so does this
Removing both of the table .Frame setting statements and everything works quickly enough, but with them in it's very slow. And the slowness doesn't come directly here, but somewhere after the call to the base ViewDidAppear.
Update: I had an epiphany and thought if resizing the table is the problem, just make the tables big enough that they don't need resizing. In the setup I have, the scrolling is being handled by the scroll view not the table itself, so I could just set the table as really big and let the scroll views ContentSize take care of clipping the blank part of the table. This works, in the sense that it displays how I want it to, but it's actually even slower! So my conclusion is that it's not the table resize that is the problem, but rather the presence of really long (in this case I set the height to 4,000 - the resize was setting it to 2,354) tables.
Background: To add a little more to what I'm trying to do. Since Apple, in their wisdom, decided that nobody needs a grid like control, I'm trying to set up a situation where I have a grid-like view where the left most columns stay in place, but you can horizontally scroll the right-most columns, and, when you scroll vertically, everything will stay in sync. After some searching, I came across a solution (sorry, can't remember exactly where), which with a little tweaking works (in the simulator). Basically, you embed tables in a scroll view so that the scroll view can handle the scrolling. The layout looks something like this:
+-------------------------Outer Scroll-------------------------+
| +---------------Inner Scroll---------------+|
|+--Fixed Table--+ |+---------Scrolling Table----------------+||
|| | || |||
|| | || |||
|| | || |||
|| | || |||
|| | || |||
|| | || |||
|+---------------+ |+----------------------------------------+||
| +------------------------------------------+|
+--------------------------------------------------------------+
The fixed table has a custom cell with a couple of columns while the scrolling table has another custom cell (wider than the screen) with the rest of the columns. You can scroll the scrolling table horizontally (thanks to the inner scroll view) and you can scroll everything vertically thanks to the outer scroll view.
Another Update: So it seems the problem is with the table not reusing cells when you set it large. I guess the cell reuse logic only extends to determining if the cell is within the frame of the table and not if that part of the table is actually visible. So with 50 items, instead of displaying 6-7 and then re-using those cells, it creates all 50 regardless. So I abandoned my earlier attempt and tried to synchronize the scrolling between two tables like this:
OuterTable.Scrolled += (sender, arg) =>
{
InnerTable.ContentOffset = new PointF(InnerTable.ContentOffset.X,
OuterTable.ContentOffset.Y);
};
InnerTable.Scrolled += (sender, arg) =>
{
OuterTable.ContentOffset = new PointF(0, InnerTable.ContentOffset.Y);
};
This almost works, except iOS doesn't like horizontal scrolling for tables, so the inner table still needs to be wrapped in a scroll view (set with the ContentSize to cover the width I need to scroll). At this point it almost works. It will usually keep seemlessly in sync, but with a bit of messing around you can get, for example, the inner table to scroll diagonally (despite setting direction lock on everybody) and in some cases it's possible to get them out-of-sync, which looks really stupid. So it doesn't quite work as well visually, but at least it doesn't hang up the UI thread as badly.
Have you tried doing this with autolayout? There you are not responsible for when the views actually get resized, just setup the constraints in viewDidLoad and let the rest be taken care of by the system.
But in the terms of manual layout - I don't see why this would actually happen. When you profiled it with Instruments, what was the slow portion in Time Profiler?
From the documentation:
Important: You should not embed UIWebView or UITableView objects in
UIScrollView objects. If you do so, unexpected behavior can result
because touch events for the two objects can be mixed up and wrongly
handled.
Your interface might appear slow because touch events are getting handled by the wrong objects. This can make scroll views appear to jump around, act laggy, or not respond at all.
Can you describe the behavior you're going for? Can you achieve what you want using only a UITableView with a UIScrollView in it, or perhaps a UICollectionView?
It appears that the only way for your proposed implementation to work is to load ALL the UI at initialization, which eliminates the performance benefit of using a UITableView at all. It will be considerably more efficient (from a memory perspective) for you to have a top level UITableView that scrolls normally, and contain a horizontally scrolling UIScrollview within each cell.
+-------------------------Table View---------------------------+
|+-----------------------Table View Cell---------------------+|
||+--Fixed Section--+ +---------Synched Scroll View---------+||
||| | | |||
||| | | |||
||+-----------------+ +-------------------------------------+||
|+-----------------------------------------------------------+|
|+-----------------------Table View Cell---------------------+|
||+--Fixed Section--+ +---------Synched Scroll View---------+||
||| | | |||
||| | | |||
||+-----------------+ +-------------------------------------+||
|+-----------------------------------------------------------+|
|+-----------------------Table View Cell---------------------+|
||+--Fixed Section--+ +---------Synched Scroll View---------+||
||| | | |||
||| | | |||
||+-----------------+ +-------------------------------------+||
|+-----------------------------------------------------------+|
+--------------------------------------------------------------+
The important step is synching the horizontal scroll views, which you can do by sending NSNotifications or custom delegate messages on -scrollViewDidScroll:
It may feel wasteful to be creating 10+ scrollviews within table view cells, but in practice it ends up being fairly efficient.

How to insert UIButton through code with AutoLayout feature enabled - iOS

I have been trying to insert a UIButton programatically, as I am using Autolayout I have done something like that...
[self.add_scroll_view addConstraints : [NSLayoutConstraint constraintsWithVisualFormat : #"V:[date_picker_btn]-[button(==date_picker_btn)]"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(date_picker_btn, button)]];
I have two questions here...
i) Button inserted is not the same width as date_picker_btn even though I mentioned button(==date_picker_btn).
ii) I have inserted properely, however below views should align accordingly down to accommodate new button... How to do that...
Thanx
When using the visual format language, the superview of the view for which the constraint is being described is represented by the | character.
Example:
V:|-20-[mybutton1(>=70#500)]-[mybutton2(==mybutton1)]-30-[mybutton3]-|
Refer this link
For first question I have mentioned V: so it means (==) will assign height not width. To set width it should start with H:.
Next question, To insert a button between two existing button need to handle already existing constraints, here above I have added new constraints only not handle old existing, so I have to delete the existing constraints, so that it avoid conflicts. Works fine.. Happy coding :)

Hide a UITableView by setting row height to 0?

I just inherited code which hides/shows rows a UITableView by using the delegate heightForRowAtIndexPath method and returning height 0 for "hidden rows".
The code works, but it has me concerned there might be fraught with unforeseen complications. Can someone either ease my concerns or give me good reasons why this could cause problems (I couldn't find any issues with initial testing).
The table is fairly small <10 rows total and would require custom row heights even without this hidden row solution.
I do the same thing in the code I just worked on. I am not happy with different behaviour for different table view settings.
The alternative in my case is more complex (a model that adapts to what is visible or not).
For now, I put a //HACK comment on it and document a few peculiarities.
This is what I have found (iOS 5.0 tested):
Set tableView.rowHeight = 1; Zero will give a cell with zero height (as returned by tableView:tableView heightForRowAtIndexPath:) some default height.
You must have a cell separator. If none is selected, then a default height is assigned to zero height rows. The height of 1 is included with the separator.
If your code works in a different way, it would be interesting to know how it is set up.
It would be cleaner to add and remove the rows between two beginUpdates and endUpdates calls, but I don't see why this 0-height method should not work.
If there are no UI-artifacts, that is (e.g. the Delete button showing up overflowing to the next cell).
I use this method of setting hidden cell heights to 0. It works well and also means I can animate the inclusion of new cells by expanding the cell height (such as adding a DatePicker Cell like the calendar app does).
A few things I have had to watch out for in iOS 7.1 are that very squashed text does still appear even when a cell height is = 0 so I've needed to remove cell text in that case. Also, I have change the size of the cell's separatorInset as that was appearing as well.