iOS UISwipeGestureRecognizer: Two Ways in Swift

I’ve been building a small sample iOS app and in learning how to implement UISwipeGestureRecognizer, found two different approaches. None of the resources I found online were overly explicit in both approaches, so documenting here…mostly for my own future reference.

Option 1: Storyboard

Xcode makes it easy to add a gesture recognizer to your app interface. Simply drag the appropriate gesture recognizer from the palette onto Storyboard, being sure to select the UI element that you would like to listen for the gesture. In my case, the entire view of my ViewController:

Screen Shot 2015-11-18 at 2.34.27 PM

Next, select the gesture recognizer and Ctrl+Drag to your ViewController class. Select the settings as shown below in the pop-up. You can now implement the response to your gesture.

Screen Shot 2015-11-18 at 2.36.38 PM

The Storyboard inspector also allows you to select swipe direction, etc. with the gesture recognizer selected.

Option 2: Code

Adding a gesture recognizer (in this case, a swipe gesture recognizer) requires just a few lines of code in your ViewController, typically in your viewDidLoad method.


let swipeRight:UISwipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: "doSomething:")
swipeRight.direction = .Right
self.view.addGestureRecognizer(swipeRight)

The only item left is to implement the handler for gesture, which is mostly identical to Option 1:


func doSomething(gestureRecognizer:UIGestureRecognizer) {
print("doSomething called")
}

My preference is Option 1. Although the implementation is spread across two files, keeping all view-related bits in the Storyboard feels cleaner, but either approach will work.


“Banners” = Bad in Ad Blocker World

Just ran into a rather aggravating issue…

In building a site meant to preview mobile ads, I used the term “banners” in the URL to point to image previews then spent 2+ hours tracking down why it worked in my development environment but not in production.

Luckily a colleague pointed out my ad blocker, which seems to have a broad match on the word “banner”…block all. Changing the name in the path fixed the problem.


Installing Nokogiri via Bundler on Mac (or why did this take two hours?)

If this post saves one person the headache of several hours of trying to build Nokogiri via Bundler on a Mac, maybe my time wasn’t wasted, but it was painful.

The setup…
Trying to install Nokogiri 1.6.1 as a dependency for other gems via Capistrano’s bundle:install task, I continually ran into “Failed to build gem native extension” error. Scrolling through the errors, the one item that stuck out was “You have to install development tools first.”

Although 100% certain my server had Xcode Command Line tools installed (it was recently updated at noted in the App Store), I reinstalled manually and tried to deploy again. Same error.

I then proceeded down the path of using Homebrew to install the various Nokogiri dependencies (e.g. libxml2, libxslt). Deploy…build…fail.

I ran “gem install nokogiri” locally on the server. Build…success. Tried to deploy again…build…fail.

Finally, I dug up the make log for Nokogiri (path below for reference) where I noted a message indicating that “gcc-4.2” was not installed. gcc is installed, but the build script seems specific. Not finding a switch to change the name of gcc, I went brute force:

sudo ln -s /usr/bin/gcc /usr/bin/gcc-4.2

Deploy…build…success! Annoying problem, solved.

Better suggestions welcome.

Make log: /shared/bundle/ruby/2.0.0/gems/nokogiri-1.6.1/ports/x86_64-apple-darwin13.1.0/ext/nokogiri/mkmf.log

Update
After all that, I noticed a warning: “Nokogiri was built against LibXML version 2.8.0, but has dynamically loaded 2.9.1”. After trying a few paths, I was able to rectify the warning via the steps in the comments of this :

  1. brew remove –force libxml2
  2. bundle config –delete build.nokogiri
  3. bundle exec gem uninstall nokogiri libxml-ruby
  4. bundle
  5. The commenter notes that Nokogiri 1.6+ now bundle the necessary libraries so there is no need to use the Homebrew versions.


Ransack: Search with Multiple Checkboxes (Rails)

I’ve been using the outstanding Ransack gem to enable search for a recent project. Ransack provides a tremendous amount of flexibility in a straightforward manner, but it took me a bit to understand how to search a single field across multiple values selected via checkboxes. My approach follows.

(Note that the field I was searching contained a serialized array of data, not to make life more difficult)

To start, a simplified model:

class Zoo < ActiveRecord::Base
  has_many :animals
end

class Animal < ActiveRecord::Base
  belongs_to :zoo # we'll assume an animal can only belong to one zoo
  validates_presence_of :name
end

Next, the controller, which is pretty much out-of-the-box from the Ransack documentation:

class ZoosController < ApplicationController
  def search # or index
    @search = Zoo.search(params[:q])
    @zoos = @search.result(distinct: true)
  end
end

And finally, the magic is really in the view:

<%= search_form_for @search, url: search_zoos_url do |f| %>
  <% Animal.all.uniq.each do |animal| %>
    # the check_box helper will not work as effectively here
    <%= check_box_tag('q[animals_name_cont_any][]', animal.name) %>
    <%= animal.name %>
  <% end %>
  <%= f.submit "Search" %>
<% end %>

The key is the name of the check box field. We are passing an array and also using Ransack’s cont_any predicate, which searches for any records whose name field contains one of the selected names.


WordPress.com Code Formatting…How Did I Not Know This!?

Somehow I have lived with pre blocks on this blog for much to long. On WordPress.com blogs (like this one), you can syntax-highlighted code very easily:

your code here

WordPress supports a wide variety of languages.

References


Sticky Navigation Bar with Skrollr

Parallax scrolling seems to be all the rage in web design these days.  It has a level of interactivity and richness that puts  the old click-and-wait experience to shame.  From simple and subtle (MMQB) to the complex (The Walking Dead), parallax can add a nice design flourish to most websites.  Of course, even simple effects are not free.

While redesigning a small business website, I wanted to add a few small touches to jazz up the minimal content, so I decided to add a spice of scrolling animations to the site.  In evaluating my options, I settled on Skrollr, which had the right mix of power and simplicity.  Skrollr is driven by CSS and HTML tag attributes, meaning there is little complex JavaScript for the end user, plus it works seamlessly across desktop and mobile.

Adding a stick navigation bar that drops in from the top of the screen using Skrollr was fairly straightforward, with two caveats that I will cover at the end of the article.

If you want to get to the end result: JSFiddle

First, our HTML markup before adding Skrollr:

<nav class="wrap">
  <div class="container">
    <div class="five columns">My Company</div>
    <div class="eleven columns last">
      <ul>
        <li><a href="#1">Item 1</a></li>
        <li><a href="#2">Item 2</a></li>
        <li><a href="#3">Item 3</a></li>
        <li><a href="#4">Item 4</a></li>
      </ul>
    </div>
  </div>
</nav>

Simple. Now, we can improve the style of the menu and also stick it to the top of the page via CSS. We’ll also add some transparency so it appears the page is passing under the menu as we scroll.

nav {
  background-color: rgba(255, 255, 255, 0.9);
  border: 1px solid red;
  height: 55px;
  top: 0;
  position: absolute; /* hold tight... */
  visibility: none;   /* we'll override these shortly */
  z-index: 1000;
}

/** some additional styling for navigation elements... **/

At this point, we should have a nice little navigation bar. It’s stuck at the top of the page and scrolls with the page though. Functionally, when the header is mostly off screen and then content is reaching the top of the viewport is when the navigation should slide in. Let’s modify our HTML to include Skrollr.

<nav class="wrap"
     data-anchor-target="#content"
     data-200-top="opacity:0;"
     data-150-top="visibility:visible; top: -55px; opacity: 0.3;"
     data-100-top="opacity: 1; position: fixed; top: 0;">
  <div class="container">
    <div class="five columns">My Company</div>
    <div class="eleven columns last">
      <ul>
        <li><a href="#1">Item 1</a></li>
        <li><a href="#2">Item 2</a></li>
        <li><a href="#3">Item 3</a></li>
        <li><a href="#4">Item 4</a></li>
      </ul>
    </div>
  </div>
</nav>

We’re doing a few things above:

  1. We use the data-anchor-target attribute and provided CSS selector to identify the page element on which the animation frames are triggered. Skrollr by default uses the tagged element, but can reference on the page via CSS.
  2. Animating the opacity, position, and visibility of the nav element. Skrollr handles the animation between the values, e.g. it “slides” the nav into place to animate the top position.
  3. Set the element as fixed on the page.

That’s it. As you can see in the JS Fiddle, this requires only minimal code and its fairly straightforward, except for two items:

Frame Positioning
Skrollr supports both absolute and relative positioning on the page, which is useful, though it took me a bit to wrap my head around it (and some trial-and-error). In this case, we are monitoring how close the content element is from the top of the viewport – as it gets closer, we animate in the nav (starting at 200 pixels from top and completing at 100 pixels). There is a nice graphic on the Skrollr website that helps in this regard, but depending on the animation/effect you wish to create, you may need to experiment:

Skrollr Positioning

Mobile Support
The Skrollr website has a great overview of how the library compensates for deferred processing of JavaScript in mobile browsers to fake scrolling. Because our example has both fixed and non-fixed elements on the page, we need to add a skrollr-body element that contains the scrollable content of our page (note in the Fiddle that the nav is not in this block). If you do not include the skrollr-body element, your page will not scroll properly, if at all.

This is just one example of adding a few small enhancements to a simple page, Skrollr can enable much, much more.

Complete Example

References


Rails Asset Pipeline + Bootstrap 3 Fonts

I admit it, I find the Rails Asset Pipeline confusing at times (as do seemingly many others judging from Stackoverflow and elsewhere).  Successfully adding the Bootstrap 3 glyphicon fonts took some trial-and-error amongst the various solutions I found as many still resulted in not found errors.

While there may be a better way, I found this approach most effective:

    1. Copy the contents of the Bootstrap “dist/fonts” directory to the “vendor/assets/fonts” directory (you will need to create a “fonts” directory.  Bootstrap’s minified JavaScript and CSS files can be copied to the appropriate directly in “vendor/assets” as well.
    2. Add the following to “config/application.rb” within the application config block:
      config.assets.paths << Rails.root.join('vendor', 'assets', 'fonts')
      config.assets.precompile += %w(.svg .eot .woff .ttf)
    3. Utilizing SASS (or LESS) here is useful in order to leverage built-in asset pipeline helper methods.  In a common file used across your site, include the following:
      @font-face {
        font-family: 'Glyphicons Halflings';
        src: font-url('glyphicons-halflings-regular.eot');
        src: font-url('glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'),
        font-url('glyphicons-halflings-regular.woff') format('woff'),
        font-url('glyphicons-halflings-regular.ttf') format('truetype'),
        font-url('glyphicons-halflings-regular.svg#glyphicons-halflingsregular') format('svg');
      }

Thus far, Not Found errors seem to have been eliminated.  If there is a better way, please comment.


Follow

Get every new post delivered to your Inbox.

Join 50 other followers