Supporting both AutoLayout and traditional layout - iphone

I have a custom subclass of UIButton that I want to re-use in multiple projects, some of which use interface builder and storyboards, and some of which may not. It involves setting the button's frame in several places.
If I add
self.translatesAutoresizingMaskIntoConstraints = YES;
in the initialization, everything looks and works right, however, I get:
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)
Will attempt to recover by breaking constraint…etc
logged to the console. However, if I set
self.translatesAutoresizingMaskIntoConstraints = NO;
none of the button sizing works and the button is completely broken.
Is there a way I can suppress the error since it seems to degrade to the right thing or can I somehow manually remove the offending constraint?
I've tried dumping the constrains after the button is initialized, however, it does not seem to contain the constraint AutoLayout ends up breaking.
Edited: Below are links to a sample project and then my button code. It works great when auto layout is turned off in the storyboard, however, when auto layout is turned on, the buttons seem to position at the origin (seems to be because when initWithCoder is called, the buttons don't have superviews or any position information).
http://www.kudit.com/dump/KFB.zip
http://www.kudit.com/dump/KuditConfirmButton.zip

Your guess is correct, in that when the buttons are initialized from the storyboard (using initWithCoder:) the frame is zero - this is expected for views using autolayout - frames don't get assigned until later on.
I have your sample project mostly working under autolayout by creating a boolean ivar called hasSetup, which get set to YES inside the setup method. The setup method doesn't run if the frame is zero. I also call it again from layoutSubviews. This gets around the not-working-when-using-autolayout in storyboard problem.
The various layers still aren't the correct size though. You may want to look into resizing them from layoutSubviews.
You also can't use setFrame under autolayout - you need to make sure any constraints on your view (like the sizing constraints from the storyboard) are adjusted instead. It's going to get quite messy dealing with both possibilities.
They look really good though - hope to see them on GitHub when you've sorted these problems.

Related

Is there an easy way to convert the constraints that are already defined in storyboard into Swift code?

I have designed a ViewController in my Storyboard and I have adjusted all of its constraints respectively.
Now, I would like to animate most of these constraints.
So :
I should define them again using Swift codes
and write some codes to do the animations.
But it is very annoying to define the constraints again in Swift code while I already have them in Storyboard.
So, I was hoping someone could introduce me an easy way to achieve this automatically.
No, there are no built-in ways to render the IB constraints into Swift code. You could iterate through them and grab all their properties and do something like that, but that will get messy. There are too many different ways to create constraints programmatically, and even if some automated tool existed, I bet the code wouldn’t be very elegant. (As a general rule, tools that generate code programmatically don’t result in very good code.)
I wonder about the whole concept. We often animate constraints generated by IB without going through all of this. The typical approach is to give these IB constraints #IBOutlet references and then you can programmatically change their constant values and then put the call to layoutIfNeeded in the animation closure. Or, if you must, you can deactivate them (again, using the outlets) and then do whatever animation you want and, if appropriate, re-activate those constraints later, if needed.
But we can’t advise on to how to best achieve your animation in an IB view with constraints without more details about the nature of the animation.
But this is an example of how you can animate change the position of a view that has constraints defined in IB: https://stackoverflow.com/a/28329399/1271826

Set default Fixed Space UIBarButtonItem width

Basically, the title says everything. I'm trying to do some customization and i need to use less-than-zero width to make buttons be closer to each other.
I've learned it from this answer.
I can do it by manually setting every fixed space width, but how can I do it via [appearance] or something to make it default?
Something like this:
// works for every button not only Fixed Space
[UIBarButtonItem appearance] setWidth:-10];
!!! OR !!!
How can i set less-than-zero width in XCode? I'm creating everything using Storyboard anyway, it says that's not a valid value to set.
Any help would be really great.
I normally solve this kind of problem by subclassing the container and overriding layoutSubviews or didLayoutSubviews. This gives you a lot of control of all kind of styling behavior. In this particular case you would determine the widths programmatically and adjust the frames accordingly.
Make your instance class a subclass of this subclass, and you will have the layout code neatly separated from your implementation.

Subview randomly changes location by 40 pixels?

I have a subview that covers the full screen of the iphone 5, and whenever I build and run all of a sudden its frame is (0,-40,320,586) instead of (0,0,320,586). So it like moves up for some reason. Right now I unchecked 'use autolayout' in the file inspector. This gets rid of all those annoying constraint thingies which I don't understand what they do.
Whenever I check 'use autolayout' enabling the constraints I notice this fixes the problem, and the subview doesn't randomly move up 40 pixels.
However, I can't keep these constraints on because I do animations with the subview, which don't work whenever the constraints are enabled.
What can I do?
If you use autolayout at any point read and learn about the autolayout system and constraints. If you don't want to, turn it off and don't use it.
In your case, if you want to get rid of it for a single view, perhaps it is enough to remove all constraints from that view. That can be done like this:
[view removeConstraints:view.constraints].
Autolayout reference.

iPhone Autorotate: Replace rotation animation with fade-in/fade-out?

Someone else asked a similar question previously, but I am interested in knowing whether the autorotate feature of the iPhone SDK will allow us to replace the rotation animation with another transition, such as a fade-in/fade-out. For a modal view, we can set the modalTransitionStyle but there is no such property for autorotate.
If I can't leverage the built-in functionality, how else can I implement this functionality?
There's the willAnimateRotationToInterfaceOrientation:duration: method, from the docs:
The default implementation
of this method does nothing. If you
override this method, you should not
override either the
willAnimateFirstHalfOfRotationToInterfaceOrientation:duration:
or
willAnimateSecondHalfOfRotationFromInterfaceOrientation:duration:
method.
This method is called from within the
animation block that is used to rotate
the view. You can override this method
and use it to configure additional
animations that should occur during
the view rotation. For example, you
could use it to adjust the zoom level
of your content, change the scroller
position, or modify other animatable
properties of your view.
I guess you can modify it from here, and before and after with – willRotateToInterfaceOrientation:duration: and – didRotateFromInterfaceOrientation:.
This seems inefficient and sub-par to me, as it does not actually replace the transition at all.
I would make a category on UIView, that includes methods such as -willRotateUsingTransition: and pass a parameter that will tell it to fade, then set the view's alpha to zero. In each subclass override this to include any subviews that need their alpha changed, if that is applicable. Call this method when the views are about to be rotated (with the methods above) and then a clean-up method that restore the alphas when they will appear again.
Edit: Docs Docs Docs. A quick look, again, reveals this method: - (void)willAnimateSecondHalfOfRotationFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation duration:(NSTimeInterval)duration, which I thought to be deprecated. As part of the discussion it has the text from the second paragraph I posted from the docs earlier.
I achieved something similar by attaching the auto-orientation behaviour to a hidden view, and responding the relevant events by implementing my own custom effect. It was quite fiddly, and I don't remember all the details, but I did manage to exercise complete control over the behaviour.
I should say, though, that in my case, I wanted to have control over how the rotation was implemented. I wanted the primary layout to remain fixed, while rotating several subviews in concert. I can't think of a good reason to completely replace the rotation with a fade-out-then-in; it'll just confuse users for no good reason. The only reason I can think of for using a fade effect is that you want to swap to a substantially different UI, but even then, there's no reason to suppress the rotation effect.

Broken cell with an odd strikethrough?

I'm having a weird issue with a particular UITableView in my iPhone devel experience here. If you look at the following screenshot:
alt text http://dl-client.getdropbox.com/u/57676/brokencell.png
you'll notice a strike through going through the middle of the 'Jane Aba' cell.
Any idea what might be causing this odd graphic display? It's true for both the simulator and for the actual device running 2.2 SDK.
As requested, here's my -tableView:cellForRowIndexPath: method:
* EDIT *
I've located the problem. I'm not entirely sure why this is the problem, but it is. In my RootViewController, I have the following line of code in my -initWithCoder: method:
self.navigationController.navigationBar.barStyle = UIBarStyleBlackTranslucent;
When I comment that out, the cell (which is not in the RootViewController, but a secondary controller) it's resolved. Any idea why this might be the case?
I've had a similar problem. For me, the single line was caused by a superfluous view that was created but never sized or placed correctly and so was 1 pixel high, floating over everything else. You can also cause this by confusing a UINavigationController about its set of subviews (by adding views directly to its layout container).
Look through your UI (xib files and programmatically created views) for a view that shouldn't be there or is otherwise not being used. It might be helpful to write some code to dump a UI Hierarchy, so you can see what views are where.
Are you doing anything special in your -tableView:heightForRowAtIndexPath: method?
It looks to me like the height of the row is being set incorrectly, so the contents of the cell are expanding outside of its bounds.
The problem disappears when you set the cell height for the table view to 1 pixel in IB. It seems that before you populate the table, an empty table is drawn with the outlines of the cell height set in IB.
Don't set the cell height to 0. IB doesn't like that. :-)