Aleksey Gureev

Sevastopol, Russia 17 posts

YAML you may have never known

A small collection of handy YAML tips you may have never known.   Read More

My current Elixir toolkit

All my free time I'm spending on a my own project that I decided to write in Elixir, Rails and CoffeeScript. Here's the run down of tooling I use.   Read More

Completes and totals, or how to count

Quick into into how to write conditional counts without sub-selects in Postgresql.   Read More

Appcelerator Titanium: Scaling and cropping images

Scaling and cropping of images in Appcelerator Titanium 3.3.0 GA explained with the sample code.   Read More

Thoughts on present iOS development

Now the time for iOS has come and I'm putting together these notes basing on my recent experience with XCode 6 Beta, Beta 6 and Beta 7.

On to the great sides:

  • XCode 6. Great Interface Builder experience so far. Although it's terribly slow at times, it's been very handy. Live rendering of custom views is both super useful and confusing at times. I don't know what hardware do they use for demos at WWDC, but on my 2010 Macbook Pro it's not even close to real-time (takes 20-30 seconds to build and update the view). Still cool and faster than rebuilding the project for that little tweak.

  • Swift is brilliant. I thought moving from ObjC will bring pain and even wanted to postpone until I'm more or less at home with it. Glad that I've done otherwise with the latest project. Aside of a couple little hacks, experience has been smooth and pleasant so far.

  • UI preview feature. Handy to check the constraints and have a rough idea of what the view will look on various devices, but with its weak sides -- not totally correct rendering of table view cells, latency and some crazy behavior with messed up constraints that doesn't match to that of a real device.

Now to what's not so great:

  • Installation issues. First launch after the fresh install is confusing. Filed the issue.

  • Docs can be better. Although the built-in doc browser has been seriously improved, guides are still in read it all in one book format, and are very hard to navigate and fish out necessary info (unless you are reading it from cover to cover).

  • Unwind segues not recognized when working with Swift and need ugly ObjC workaround.

  • Swift rules change often (especially for unboxing). I moved during the week from Beta to Beta 6 to Beta 7, and with each move there was a bunch of warnings about unboxing rules. Glad it evolves, but man, it's annoying at times (especially when you have to update template code that was generated for you and you don't have a clue what it should be without digging in).

  • Interfacing from Swift with some legacy libs can be an adventure. You'll need bridging header files and hand-keeping them in sync when you update libs.

  • Debugger doesn't show any vars and fields when working with Swift. Error messages are hilarious and don't help at all. One day it says something about some Metal library it couldn't compile, the other -- about an unknown variable that is actually defined two lines above the breakpoint. All in all, you can't debug Swift code reliably and have to get back to Stone Age NSLog techniques and good deal of guesswork.

What are we still missing:

  • Automatic laying out screen space on soft keyboard appearance / disappearance. It's 2014, but we still need to handle this manually. Android has the feature either to pan the screen or to resize it, but Apple figured that's something we can do ourselves. In every project, on every screen with fields.

  • Fitting of content within multiline labels doesn't work. Single-line UILabel views are capable of shrinking text to fit text fragments that are too long for the allotted screen space. When you go multi-line, you lose that. Oh boy, there's nothing terribly complex with that, and why is it not there yet. (I hear it is in iOS 8. Backport would be nice, guys.)

Bottom line is that toolkit has gone long way to become really helpful and usable. There are still lots of weak spots and at times experience is frustrating (rebuilding complete project for 2 minutes after a one line change is one of them), but at least designing and building stuff for iOS and Mac OS X is now a pleasurable experience.

If you are still using Appcelerator Titanium, consider going native with your next project. Both Android and iOS platforms give all you need to work on your projects efficiently now.

We are living through exciting times, ladies and gents!

What I like about present Android development

Android Studio. Number one most important thing in whole Android development story is Android Studio built on top of IntelliJ IDEA engine. Excellent off the box Gradle support, intuitive source control, intelligent code completion, responsiveness of the UI, debugging -- all top notch. They even help you complete repetitive strings in JavaDoc.

Responsiveness. Very simple and super-flexible means to layout interfaces for any platform, and means to pick the right resources (strings, values, drawables etc) for each. If I am to give just one suggestion here, it will be -- forget the visual UI designer. Give manual XML editing a try. It is very easy and pays of million times with precision and clarity in interfaces.

Building blocks. Extensive collection of modules and classes makes development a real pleasure. Take a look at AsyncTask and IntentService. These are the real pleasure to work with. Database management tooks, and speech recognition / synthesis are super handy too.

Documentation. Detailed tutorials and reference pages. In this aspect Google is light years ahead of Apple. The way Android Tutorials are designed and written is absolutely fantastic. You get just the necessary zoom level into the technology. If you need more, you drill down, if you need less -- you get up the hierarchy. In contrast, Apple has traditional all-in-one-book PDF-like papers, which makes it a complete waste of time if you need just a tad for solving the present task.

Fragments. With the introduction of fragments the development for Android went to a totally new level. They are those "sub-activities" you can embed in your views, replace, and transit to and from. You can juggle with them and use to compose interfaces for different platforms and form factors (think master-detail laid out sequentially for handhelds and as a sidebar+main area for the tablets.)

There's plenty more. I've highlighted something that stuck in memory after the recent week-long project.

Constraints aware soft keyboard compensation on iOS

A while ago Apple introduced constraints-based layouts for Mac OS X and iOS user interface designs. It's a huge and logical step forward from pixel-perfect fully manual laying out of things. The line of devices grows and creating all possible variations of interfaces has become a seriously tedious task.

One piece still missing from the puzzle is the set of tools for proper compensation for the soft keyboard. (It's when the keyboard slides up from the bottom of the screen.) There's a good chance that on a non-scrollable page your text fields at the bottom of it will become hidden by the keyboard. At this point you are on your own.

Recently, I've got exactly same problem and fished for solutions. All I could find were several pieces of code with frame-based calculations. That's when you figure the height of the keyboard that's about to slide out and animate the portion of the screen up by the same amount. It all looks like this:

- (void)registerForKeyboardNotifications {
    [[NSNotificationCenter defaultCenter] addObserver:self
        selector:@selector(keyboardWillShow:)
        name:UIKeyboardWillShowNotification object:nil];

   [[NSNotificationCenter defaultCenter] addObserver:self
         selector:@selector(keyboardWillHide:)
         name:UIKeyboardWillHideNotification object:nil];
}

- (void)keyboardWillShow:(NSNotification*)aNotification {
    NSDictionary* info = [aNotification userInfo];
    CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;

    CGRect aRect = self.view.frame;
    aRect.size.height -= kbSize.height;

    [UIView animateWithDuration: 0.3 animations: ^{
        self.view.frame = aRect
    })
}

- (void)keyboardWillHide:(NSNotification*)aNotification {
    NSDictionary* info = [aNotification userInfo];
    CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;

    CGRect aRect = self.view.frame;
    aRect.size.height += kbSize.height;

    [UIView animateWithDuration: 0.3 animations: ^{
        self.view.frame = aRect
    })
}

This approach work great until there's a view you want to also resize or move depending on what you do to your primary target. Say, you have a table above your data entry section that you want to shrink as the data entry section goes up when the keyboard slides out.

idea

And that's just the simplest example, believe me...

With modern constraints based layout, you tell the table view bottom edge to follow the entry section top edge and the entry section bottom edge to stick to the bottom of the container. Now to modify the frame-based functions we need to save the bottom edge constraint of the entry section into the outlet (here inputsSpaceConstraint). And then we can safely modify the keyboardWillShow and keyboardWillHide methods as follows.

- (void)keyboardWillShow:(NSNotification*)aNotification {
    NSDictionary* info = [aNotification userInfo];
    CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;

    [self.view layoutIfNeeded];
    [UIView animateWithDuration: 0.3 animations: ^{
        self.inputsSpaceConstraint.constant = -kbSize.height;
        [self.view layoutIfNeeded];
    })
}

- (void)keyboardWillHide:(NSNotification*)aNotification {
    [self.view layoutIfNeeded];
    [UIView animateWithDuration: 0.3 animations: ^{
        self.inputsSpaceConstraint.constant = 0;
        [self.view layoutIfNeeded];
    })
}

The idea here is to use the constant field of the constraint to shift the view by the given amount (the height of the keyboard), and then, when we hide the keyboard, return it back to zero (or whatever you are using).

One specific thing to notice is that you absolutely need to call layoutIfNeeded before and in the process of animation to see the animation itself, not just before-and-after. That's how Apple suggests it to be.