I just ran into another case where Interface Builder did not allow me to do what I wanted to do and I finally just gave up and pulled everything but the first view controller from the storyboard. This is the story of how I got to this point.
My first iOS app was one of "finish this". Another developer who was no longer with the company had developed the app. I had the job of finishing the app and converting it to Android. I already knew Java and had written an Android app that was in the store. The iOS version used NIBs as this was back in the iOS 4 timeframe.
I continued down the NIB path and converted the app to be universal with special code for iPad layouts. There was special cases for landscape vs. portrait on one of the screens as well. Seemed to work OK but it was a fairly straightforward app.
I worked only on Android apps for a some time before my next position where I did both iOS and Android work again.
The next iOS app I worked on was written by another developer and he used storyboards. Still using the old style layouts with pixel perfect positioning. I kept the storyboards in place seeing some of the advantages of using them and added the iPad storyboard side of things. I liked how much easier it was to get things going, used segues and like the idea of seeing the program flow in a visual designer. Took quite a bit of web research to understand how it all tied together and a lot of clicking on tabs in IB to find all the secret nooks and crannies where you could set things.
I did a couple of other apps for the company that I got to write from scratch. I used the new found storyboards for them as well. Sadly none of these apps went to market as they never finished the server side of the work. Lots of pretty apps to demo at sales meetings but they were just demos.
For my current job I am again getting to write the app from scratch. I am doing the same with the Android side of things. I started out using storyboards and it was time to get into autolayout. Since I have been doing Android work and I have also done a lot of Java desktop work I have a solid understanding of doing layouts that scale.
I dove into autolayout and found it rather confusing. It appears to me to be written in the land of academia instead of the land of real world programming. One layout to rule them all no matter how you have to force things into it. Very verbose in one code only format and very terse in the other. If you do it in Interface Builder then you just have to know how to do things. Click here, Ctrl + Click here, set up constraints, delete them, set them up again, have them conflict, pull hair. Always something wrong and it get really bad when you have a complex layout. For a company that prides itself in UI and UX I must say IB is not a good reflection of that goal.
After fighting it and working with other iOS devs over chat I found Masonry and switched to that. Yes, it is code and not WYSIWYG but I could create complex layouts and have them work. I could do different layouts for iPad and iPhone and follow them logically. I still have storyboard layouts but most of them were empty as the code created the real layout. I was just using them for segues and to see program flow. That was until yesterday.
There I was back in Interface Builder. I just wanted a UITableView to move down one level, to have another UIView as its parent. IB fought me tooth and nail. I could and a UIView to the list but it would not show up under the UIViewController no matter how I dragged and dropped and clicked. I then said screw it and deleted that entire view controller and created a new one where I could re-add the UITableView but then all my segue links broke and all the IBOutlets into the code broke and I would have to do it again for the iPad storyboard and all the work went on and on. Plus Xcode crashed more than once while I was in it doing simple things.
Storyboards end up sucking pretty quickly. There is not enough screen room to see your iPad layouts. You get to see one scene at a time. Sure you can zoom out but the minute you edit something it zooms back in. Just opening a storyboard seems to trigger Xcode into thinking there was a change. If you look in the XML you will see it changed x = 4.0 to x = 3.999999999 or something just as stupid. Everything I did I had to do twice, once for iPhone and once for iPad. The IDE does not tell you if you forget to wire up a UIView to an IBOutlet. Objective C does not care if you send messages to a nil object. Moving a UIView can screw up the whole layout quickly. You can't see all the constraints in one place, you have to look in each level of the layout to see them and they are terse and unrelated to each other. When you try to Ctrl+Drag a UIView into the code you hardly can see anything else on screen.
I gave up. IB was fighting me not helping me. I converted all the code to Masonry and I was able to control that layout exactly. I had to move all the segue processing in code as well. It took me all day to get my code back to where it was before but now I am in control of all of it.
I don't have to do things twice. iPad and iPhone both work from one code base. I may have some if statements in code to tweak layout for iPad but I don't have to double layout it out in a crappy UI editor called IB and I don't have to double connect every UIView to a IBOutlet.
I can move a control around in my layout by changing a few lines of code instead clicking a bunch of times in IB and having it get pissed and redo other constraints.
I can name my controls so when I do get log messages about my layout being screwy I know exactly which UILabel it is mad about instead of guessing.
Another issue that bit me, I fixed, that bit me again and I fixed the right way arose. I needed a second line for the title area on iPhone. iPad has enough horizontal space to not need this. I was using the navigation prompt property which adds a second line of text to the title area. On Android I could use title / subtitle to do same thing but on Android this requires no extra vertical space.
How did this bite me twice? A number of months ago I wanted to add a UILabel above my UITableView but I could not due to same issues that I just covered, I could not get the UITableView hosted by another UIView. Thus I used the prompt property. It worked OK. After the conversion away from storyboards everything in this UIViewController aligned just fine the first time I displayed it but when I tapped a table row and moved to the detail screen then back to the table screen setting the prompt caused the navigation area to grow and it covered up part of my table. Rotating to landscape and back would fix it. I tried all sorts of relayout, needs display, calculation of offsets etc. and could not get it to work. Why autolayout would not stay in sync is beyond me but I got sick of fighting that.
Then I remembered what I originally wanted to do - put a UILabel above the UITableView on iPhone only. Now I am in control as I am using Masonry. Put the UILabel in place and changed all code references from prompt = to promptLabel.text = and I have a working layout the way I originally wanted.
I have no plans use prompt again due to it screwing up layouts and I will not be using storyboards or Interface Builder either. They just are not stable and cause more trouble than they are worth. I also do most of my work in AppCode instead of Xcode as AppCode does a much better job in a lot of areas. Better editor, much better refactoring, GIT actually works properly and it is stable. I have had it crash on me once in the two plus years I have been using it.
The other added benefit - I can take my code and drop it in another project and it will work. I have no dependencies on copying the layouts twice and having to manually reconnect every single freaking UIView to an IBOutlet. My code is self contained. It lays itself out and knows how to talk to all of its controls.
Goodbye IB and storyboards. I don't miss you.
Showing posts with label masonry. Show all posts
Showing posts with label masonry. Show all posts
Tuesday, January 13, 2015
Friday, August 29, 2014
Switched to autolayout via Masonry
I have known for some time that I needed to start using autolayout for my iOS development. My current app is universal so I was doing things twice already in Interface Builder which was getting to be a real pain. Add the control, drag and drop the IBOutlet connections and don't forget to do it on the other side.
I tried to use autolayout in Interface Builder and finally got my fairly simple login screen to work but I cussed at it the whole time. Move a control, have IB tell you the constraints and form are out of sync, correct it and repeat. If you move a control that was used as a reference anchor for other controls then it got really lost. You end up manually deleting constraints that show up either below the control you are moving or maybe at the root view. Just way to painful and error prone.
Here is where https://github.com/Masonry/Masonry comes into play. I have used a number of layout managers in the past including standard Java layouts, MigLayout for Java and the Android XML layouts. Masonry is similar to each of them in a number of areas.
A new layout with about 35 controls was the tipping point. No way I was going to do that after all the venom I spewed at IB doing the login view with only 7 controls. I got the new layout working pretty quickly in Masonry then I went back and ripped the login from IB and did it in Masonry where I can easily see the exact constraints and view relationships.
I attempting to use the Apple flavor of programmatically doing autolayout but I found it to be very verbose and nearly as confusing as IB. The other shorter syntax messed with my mind also. Masonry seemed to go right down the middle.
Not a huge fan of checking in the code for iPhone vs. iPad but for a universal app where you want special layouts that is what you get to do. Not sure what will happen when the new iPhone 6 comes into play.
I am now skipping story boards and all their headaches and just doing my layouts in code. This also means is a new developer was to come on board we would not be walking on top of each other when we change a layout which stinks with storyboards and version control. That developer would get to learn Masonry but it is reasonable straight forward. I still run into some odd layout issues that send me scrambling to stack overflow but in general it has been pretty smooth.
UIScrollView gave me the most fun but once I figured out how to anchor the scroll view to the main view then anchor child views of the scroll view to the scroll view it all worked out.
The error messages given by autolayout are not super helpful. Some trial and error is involved but I don't run into errors very often anymore.
I tried to use autolayout in Interface Builder and finally got my fairly simple login screen to work but I cussed at it the whole time. Move a control, have IB tell you the constraints and form are out of sync, correct it and repeat. If you move a control that was used as a reference anchor for other controls then it got really lost. You end up manually deleting constraints that show up either below the control you are moving or maybe at the root view. Just way to painful and error prone.
Here is where https://github.com/Masonry/Masonry comes into play. I have used a number of layout managers in the past including standard Java layouts, MigLayout for Java and the Android XML layouts. Masonry is similar to each of them in a number of areas.
A new layout with about 35 controls was the tipping point. No way I was going to do that after all the venom I spewed at IB doing the login view with only 7 controls. I got the new layout working pretty quickly in Masonry then I went back and ripped the login from IB and did it in Masonry where I can easily see the exact constraints and view relationships.
Not a huge fan of checking in the code for iPhone vs. iPad but for a universal app where you want special layouts that is what you get to do. Not sure what will happen when the new iPhone 6 comes into play.
I am now skipping story boards and all their headaches and just doing my layouts in code. This also means is a new developer was to come on board we would not be walking on top of each other when we change a layout which stinks with storyboards and version control. That developer would get to learn Masonry but it is reasonable straight forward. I still run into some odd layout issues that send me scrambling to stack overflow but in general it has been pretty smooth.
UIScrollView gave me the most fun but once I figured out how to anchor the scroll view to the main view then anchor child views of the scroll view to the scroll view it all worked out.
The error messages given by autolayout are not super helpful. Some trial and error is involved but I don't run into errors very often anymore.
Subscribe to:
Posts (Atom)