Category Archives: programming

Custom modally-presented UIViewController from another UIViewController

As a fast follow-up from the previous Custom UINavigationController Animated Transitions post, let’s say you have a UIViewController up and you want to transition to another UIViewController, but you are not using segues. The simple solution: present.

Create an animator like a fading animation controller

class FadeAnimator: NSObject, UIViewControllerAnimatedTransitioning {
    var duration: TimeInterval = 2.0

    func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
        return duration
    }

    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        let containerView = transitionContext.containerView
        let toView = transitionContext.view(forKey: .to)!

        containerView.addSubview(toView)
        toView.alpha = 0

        UIView.animate(withDuration: duration,
                       animations: { toView.alpha = 1.0 },
                       completion: { _ in transitionContext.completeTransition(true) } )
    }
}

Extend your UIViewController as a transition delegate

Easy peasy: just extend the existing class, in this case to do a fade animation.

extension DetailViewController: UIViewControllerTransitioningDelegate {
    func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return FadeAnimator()
    }
}

Finally, instantiate and present!

Ready to show the next UIViewController? Let’s say you want to show a SubdetailViewController:

        let subdetailVC = SubdetailViewController()
        subdetailVC.view.frame = view.frame
        subdetailVC.transitioningDelegate = self
        present(subdetailVC, animated: true, completion: { })

The two bits of magic here are setting your “from” view controller as the transitioning delegate of the new view controller. Then you present with animations. The new controller will be presented modally over the old one.

One more thing: dismissing the new view controller

And when you’re ready to get rid of the new view controller, you can do it from inside it:

    dismiss(animated: true, completion: { })

That’s it!

Custom UINavigationController animated transitions

Thanks to the iOS Animation Tutorial: Custom View Controller Presentation Transitions article combined with A look at UIView Animation Curves (Part 3), it’s not that bad to implement custom transitions on UINavigationControllers. But of course, it’s sprinkling the right ingredients in the right proportions in the right files…

Create an Animator

Let’s start with the animation. If you create a file like SlideAnimator.swift and you put in it:

import UIKit

class SlideAnimator: NSObject, UIViewControllerAnimatedTransitioning {
    var duration: TimeInterval = 1.0

    func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
        return duration
    }

    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        let containerView = transitionContext.containerView
        let toView = transitionContext.view(forKey: .to)!

        containerView.addSubview(toView)
        toView.frame = CGRect(x: 0, y: containerView.bounds.height, width: containerView.bounds.width, height: containerView.bounds.height)

        let timingFunction = CAMediaTimingFunction(controlPoints: 0/6, 0.8, 3/6, 1.0)
        CATransaction.begin()
        CATransaction.setAnimationTimingFunction(timingFunction)
        UIView.animate(withDuration: duration, animations: {
            toView.frame = containerView.frame
        }, completion: { _ in
            transitionContext.completeTransition(true)
        } )
        CATransaction.commit()
    }
}

That will take the “to view” that you’re going to and slide it up from the offscreen bottom and overlay the “from view”. In the above code, we do it in 1 second—tune to your liking. In animateTransition there’s a lot of juicy stuff in there:

  • The “to view” needs to be added to the containerView.
  • The transitionContext view needs to be added to the controller’s view.
  • We set the toView offscreen beyond the bottom.
  • We use a Bezier curve timing curve and add that to the CATransaction.
  • We do a usual UIView.animate and position the toView where we eventually want it.
  • The completion block notifies the transition context that it’s done.
  • And then we commit() to begin the animation.

Tell the UINavigationController to use custom transitions

(This does assume you are instantiating UINavigationController programmatically, and that it’s not your root view controller.) In the view controller that hosts your UINavigationController, set its delegate to itself, e.g.

class ViewController: UIViewController {
    var navVC: UINavigationController!
    ...

    override func viewDidLoad() {
        ...
        navVC = UINavigationController(rootViewController: tableVC)
        navVC.delegate = self
        ...
    }
}

Then it’s just a matter of extending that view controller to asking it for an animation controller depending on the operation (push or pop):

extension ViewController: UINavigationControllerDelegate {
    func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationControllerOperation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        switch operation {
        case .push:
            return SlideAnimator()
        default:
            return nil
        }
    }
}

Believe it or not, that is it!

Pssst. If you want to see how to go from UIViewController to UIViewController without a UINavigationController, you can do custom animations with present().

CSS3 columns demo

The addition to CSS3 removes so much pain from doing multicolumn layouts:

Dynamically deliver vertical action items with interoperable bandwidth. Appropriately drive client-centric systems for real-time process improvements. Proactively engineer client-centric technology and goal-oriented intellectual capital.

Competently enable virtual data before corporate initiatives. Authoritatively impact team building leadership skills without best-of-breed total linkage. Collaboratively unleash principle-centered opportunities and sticky e-tailers.

Assertively facilitate market positioning internal or “organic” sources with cross-platform methodologies. Conveniently leverage existing extensible sources after superior best practices. Dramatically empower high standards in interfaces vis-a-vis cross-media methods of empowerment.

Efficiently benchmark an expanded array of portals rather than prospective results. Monotonectally revolutionize interactive web-readiness without pandemic services. Dynamically envisioneer timely resources vis-a-vis cross functional ideas.

Authoritatively e-enable cooperative content whereas just in time relationships. Uniquely fashion low-risk high-yield users without vertical expertise. Dynamically facilitate just in time mindshare with sustainable testing procedures.

Collaboratively envisioneer prospective solutions after 24/7 channels. Rapidiously simplify mission-critical data via leveraged collaboration and idea-sharing. Proactively provide access to timely action items after real-time processes.

Dynamically deliver vertical action items with interoperable bandwidth. Appropriately drive client-centric systems for real-time process improvements. Proactively engineer client-centric technology and goal-oriented intellectual capital.

Competently enable virtual data before corporate initiatives. Authoritatively impact team building leadership skills without best-of-breed total linkage. Collaboratively unleash principle-centered opportunities and sticky e-tailers.

Assertively facilitate market positioning internal or “organic” sources with cross-platform methodologies. Conveniently leverage existing extensible sources after superior best practices. Dramatically empower high standards in interfaces vis-a-vis cross-media methods of empowerment.

Efficiently benchmark an expanded array of portals rather than prospective results. Monotonectally revolutionize interactive web-readiness without pandemic services. Dynamically envisioneer timely resources vis-a-vis cross functional ideas.

Authoritatively e-enable cooperative content whereas just in time relationships. Uniquely fashion low-risk high-yield users without vertical expertise. Dynamically facilitate just in time mindshare with sustainable testing procedures.

Collaboratively envisioneer prospective solutions after 24/7 channels. Rapidiously simplify mission-critical data via leveraged collaboration and idea-sharing. Proactively provide access to timely action items after real-time processes.

A good explanation is in the Mozilla docs. The main thing is this one property:

column-count: 3;

(Vendor prefixes required, unfortunately.)

Solving iPhone rendering issues: stopping scaling, restoring inertial scrolling

There’s nothing like wasting a Sunday morning searching the Internet for solutions to web page rendering issues on mobile devices. šŸ™

Stopping an iPhone from resizing web page text

Nothing is more frustrating as a designer/developer to see a neatly laid out web page resize its font size when you don’t expect it. I thought this line of HTML would have solved the problem:

<meta name="viewport" content="width=device-width, initial-scale=1.0">

No. Apparently you have to also add this CSS in:

body { -webkit-text-size-adjust: 100%; }

Adding inertial scrolling back to overflow:auto or overflow:scroll DIVs

It is a weird feeling to have a graceful UI somehow feel “stuck” when inertial scrolling gets disabled. Apparently setting the CSS property overflow toĀ auto, scroll, scroll-x,Ā orĀ scroll-y will turn it off. This is how you put it back:

-webkit-overflow-scrolling: touch;

Ugh.

 

Resizing (to fill) and cropping images with Paperclip :convert_options

It has been quite a while since I’ve used the Paperclip gem by ThoughtBot. I have a very simple model calledĀ Photo which has anĀ imageĀ attribute acting as the attachment:

class Photo < ActiveRecord::Base
  attr_accessible :image
  has_attached_file :image,
    styles: {
      thumbnail: '200x200^',
      preview: '800x800^'
    },
    convert_options: {
      thumbnail: " -gravity center -crop '200x200+0+0'",
      preview: " -gravity center -crop '800x800+0+0'"
    },
  default_url: "/images/:style/missing.png"
end

For some reason I couldn’t remember how to resize images to fit neatly within a square, but after fiddling around this totally works:

  • 200×200^: This sets the output geometry to 200×200 pixels but the shortest side will be 200 pixels.
  • convert_options: This adds the extra options to:
    • -gravity center: First center the image. It’s important this is first!
    • -crop ‘200×200+0+0’: Then crop the image into a 200×200 square with 0,0 as the offset.

Underscore.js’s debounce() is a great way to kill that double-click

Your mission: make sure your users don’t double-click a form button, but also don’t forever deny them future clicks.

This is a throttling problem really. And recently I was working on a UI element that was just being clicked way too often, my suspicion being the users were double-clicking it. I was going to do what I normally do: set a timeout on the click handler that would prevent more than 1 click being fired during a time period. But that just ends up making me write more code—I’d rather use a library!

Turns out that I’m using Underscore.js a little bit more these days and there is a built-in utility called debounce. It pretty much does exactly what I want it to do. As a comparison, there’s a similar function called throttle, but that still fires at least one more click event. Check this example out:

Using the googleon/off HTML hints to tell Google not to use parts of the page for its snippet

This morning I was tickled to learn that there are ways to add some fine-granularity control to Google’s page indexing behavior. If you add some hints to your page in the form of HTML comments you can tell Google’s search engine to ignore the text for all purposes, for the search result snippet, and more.

For instance, if you search for “granularity seqmedia” you should come up with a hit to this very post. But the snippet text should not be the first sentence in this post but rather the preceeding sentence. (I’m using the googleoff:snippet hint.)

Getting output from Rails template helpers, plus blocks

I had something I was doing repetitively in an ERb template today and I figured I’d DRY it up by making a helper. Specifically, I was trying to output some given HTML unless a condition was met that should generate a hidden field instead—this case calls for handcrafted HTML generation.

I was doing things like:

<% ignore_these_fields = ['foo', 'bar'] %>

<% unless ignore_these_fields.include?('abc') %>
  <input type="text" name="abc" value="<%= @vals['abc'] %>" />
<% else %>
  <input type="hidden" name="abc" value="<%= @vals['abc'] %>" />
<% end %>

<% unless ignore_these_fields.include?('foo') %>
  <input type="radio" name="foo" value="<%= @vals['foo'] %>" /> One
  <input type="radio" name="foo" value="<%= @vals['foo'] %>" /> Two
<% else %>
  <input type="hidden" name="foo" value="<%= @vals['foo'] %>" />
<% end %>

<% unless ignore_these_fields.include?('bar') %>
  <select name="bar">
    <option <% 'selected' if @vals['bar']=='a'%>>blah1</option>
    <option <% 'selected' if @vals['bar']=='b'%>>blah2</option>
    <option <% 'selected' if @vals['bar']=='c'%>>blah3</option>
  </select>
<% else %>
  <input type="hidden" name="foo" value="<%= @vals['bar'] %>" />
<% end %>

Here, fairly different HTML form fields get rendered for each type of fields, and in some cases we do not want to show certain fields. So I wanted to do this instead: write a helper that would take a block and render its contents verbatim, otherwise create a hidden field.

<% ignore_these_fields = ['foo', 'bar'] %>

<% render_unless_ignored(ignore_these_fields, 'abc') do %>
  <input type="text" name="abc" value="<%= @vals['abc'] %>" />
<% end %>

<% render_unless_ignored(ignore_these_fields, 'foo') do %>
  <input type="radio" name="foo" value="<%= @vals['foo'] %>" /> One
  <input type="radio" name="foo" value="<%= @vals['foo'] %>" /> Two
<% end %>

<% render_unless_ignored(ignore_these_fields, 'bar') do %>
  <select name="bar">
    <option <% 'selected' if @vals['bar']=='a'%>>blah1</option>
    <option <% 'selected' if @vals['bar']=='b'%>>blah2</option>
    <option <% 'selected' if @vals['bar']=='c'%>>blah3</option>
  </select>
<% end %>

That’s a bit DRYer. But here came the tricky part: the helper. I had done what I thought was right:

def render_unless_ignored (ignoring_array, key)
  unless ignoring_array.include?(key)
    yield
  else
    %Q{<input type="hidden" name="#{CGI::escapeHTML key}" value="#{CGI::escapeHTML @vals[key]}" />}.html_safe
  end
end

The yielded content was showing up but the string result was not! The ERb template was not outputting it. Then a colleague pointed out that in this case we need to tell the ERb template to render the string with concat():

def render_unless_ignored (ignoring_array, key)
  unless ignoring_array.include?(key)
    yield
  else
    concat %Q{<input type="hidden" name="#{CGI::escapeHTML key}" value="#{CGI::escapeHTML @vals[key]}" />}.html_safe
  end
end

And THAT worked!

Rails’ html_safe vs. raw

The question came up today: what is the difference between Rails’ html_safe() and raw(). There is an excellent post by Yehuda Katz on this. It really boils down to this:

def raw(stringish)
  stringish.to_s.html_safe
end

Yes. raw() is a wrapper around html_safe() that forces the input to String and then calls html_safe() on it. It’s also the case that raw() is a helper in a module whereas html_safe() is a method on theĀ String class which makes a new ActiveSupport::SafeBuffer instance—that has a @dirty flag in it.