<?xml version="1.0" encoding="UTF-8"?>
<!--Generated by Site-Server v@build.version@ (http://www.squarespace.com) on Wed, 22 Jul 2026 19:28:18 GMT
--><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:media="http://www.rssboard.org/media-rss" version="2.0"><channel><title>WatchKit Developer Blog - Sneaky Crab</title><link>https://www.sneakycrab.com/blog/</link><lastBuildDate>Tue, 04 Aug 2015 21:05:43 +0000</lastBuildDate><language>en-US</language><generator>Site-Server v@build.version@ (http://www.squarespace.com)</generator><description><![CDATA[<p>A blog by the developers of Sneaky Crab, discussing the cutting edge of WatchKit development, tips, code examples and more.</p>]]></description><item><title>watchOS 1 quickie -- debugging reloadRootControllersWithNames errors</title><dc:creator>Justin Ng</dc:creator><pubDate>Tue, 04 Aug 2015 21:05:42 +0000</pubDate><link>https://www.sneakycrab.com/blog/2015/8/4/watchos-1-quickie-debugging-reloadrootcontrollerswithnames-errors</link><guid isPermaLink="false">552351f8e4b0ea389c393627:5564269ee4b0c0ea1b06cf5e:55c12707e4b0fa221024779a</guid><description><![CDATA[<p>If you've ever used the API <code>reloadRootControllersWithNames(names: [AnyObject], contexts: [AnyObject]?)</code> in any non-trivial way, you're likely to encounter the frustration of getting this error spamming your logs and causing a lot of issues:</p>

<p><code>*********** ERROR -[SPRemoteInterface _interfaceControllerClientIDForControllerID:] clientIdentifier for interfaceControllerID:114D0003 not found</code></p>

<p>Generally this doesn't seem all too helpful. What is <code>interfaceControllerID:114D0003</code> anyway?</p>

<p>It turns out this is the ID in a private property called <code>_viewControllerID</code>. There is a little bit of code you can add to your <code>willActivate()</code> to see what the <code>_viewControllerID</code> is for each of your pages.</p>

  


  
    <pre><code class="language-swift">    override func awakeWithContext(context: AnyObject?) {
        super.awakeWithContext(context)
        if let vcID = self.valueForKey("_viewControllerID") as? NSString {
            println("Page One: \(vcID)")
        }
    }</code></pre>
  
  






<p>With a little bit of key-value coding trickery, we can get access to the private variable. Knowing exactly which <code>WKInterfaceController</code> is misbehaving really saves time when you're hunting down to clear out all references to the old controller before blowing it away with the <code>reloadRootControllersWithNames</code> call.</p>

<p>Hope this quick tip helps all of you too.</p>]]></description></item><item><title>Haptic feedback with the Taptic Engine - WKInterfaceDevice and WKHapticType in WatchKit and watchOS 2</title><dc:creator>Michael Gu</dc:creator><pubDate>Mon, 22 Jun 2015 23:17:21 +0000</pubDate><link>https://www.sneakycrab.com/blog/2015/6/22/haptic-feedback-with-the-taptic-engine-in-watchkit-and-watchos-2-wkinterfacedevice-and-wkhaptic</link><guid isPermaLink="false">552351f8e4b0ea389c393627:5564269ee4b0c0ea1b06cf5e:558871cde4b04baa030fb016</guid><description><![CDATA[<p>The Taptic Engine is a game-changing piece of hardware that Apple has added to the Apple Watch. One of the annoyances of Android Wear and Pebble is that the notification vibrations are not very subtle, and everyone nearby knows that your watch demands attention. The Taptic Engine allows you to send taps to your users wrist, feeling much like someone tapping their finger on you, as a subtle and discreet to communication information for users that they can choose to ignore or receive without bothering those around them.</p>

<h2 id="sowhattheheckisahapticandhowisitdifferentfromataptic">So what the heck is a Haptic and how is it different from a Taptic?</h2>

<p><a href="https://en.wikipedia.org/wiki/Haptic_technology">Haptic Feedback</a> used in technology typically refers to any kind of vibration or force used in input devices on the user. Pressing a button on a smooth glass screen just doesn't feel as satisfying as clicking a physical button on a mouse. That's because the mouse button depresses and then gives a 'click' feeling vibrating into your finger to indicate the button has been pressed. What's nice about this is that you can know when a mouse button has been successfully pressed without looking at it. </p>

<p>Compare this to a button on an iOS App, where you have to visually look where you are aiming your finger, and rely on visual feedback that the button has been pressed correctly. Haptic feedback refers to the class of technology to simulate physical feedback in a device, like the vibrations of a Playstation Controller or the taps on an Apple Watch.</p>

<p>The Taptic Engine is Apple's marketing name for the piece of hardware that can produce Haptic feedback by way of the feeling of taps on your wrist in response to different actions in the hardware. It can notify you that you scrolled to the end of a list, it can make it feel clicky as you click through the items of a <a href="http://www.sneakycrab.com/blog/2015/6/12/wkinterfacepicker-in-watchkit-20-using-the-digital-crown">WKInterfacePicker</a> list, or even indicate on your driving directions if it's time to turn left or right with different feeling taps so you don't even have to look at the Watch screen to know which way to turn.</p>

<h1 id="codingyourownhaptics">Coding Your Own Haptics</h1>

<p>The API is exceedingly simple, with just a quick API call to <code>playHaptic()</code>:</p>

  


  
    <pre><code class="language-swift">WKInterfaceDevice.currentDevice().playHaptic(.Click)</code></pre>
  
  






<p>The <code>playHaptic()</code> API takes in values from the <code>WKHapticType</code> enum.</p>

  


  
    <pre><code class="language-swift">enum WKHapticType : Int {
    case Notification
    case DirectionUp
    case DirectionDown
    case Success
    case Failure
    case Retry
    case Start
    case Stop
    case Click
}</code></pre>
  
  






<p>Apple currently doesn't allow for defining custom Haptic events, so whatever you want to do on your app, you'll have to do it with one of these nine Haptic types.</p><p>It's pretty important to understand the feeling, sound and intention of each of these types, so we'll cover each in detail.</p><h1 id="wkhaptictypeindetail"><code>WKHapticType</code> in Detail</h1><h2 id="notification"><code>.Notification</code></h2><p><strong>Sound</strong>: Chime <br>
<strong>Haptic</strong>: Tap-Tap-Vibrate</p><p>The <code>.Notification</code> type is intended for drawing the user's attention when something significant or out of the ordinary has occurred.</p><h2 id="directionup"><code>.DirectionUp</code></h2><p><strong>Sound</strong>: Increasing Pitch <br>
<strong>Haptic</strong>: Tap-Tap</p><p>The <code>.DirectionUp</code> type is intended for indicating a significant increase value threshold has been crossed such as when moving up a list.</p><h2 id="directiondown"><code>.DirectionDown</code></h2><p><strong>Sound</strong>: Decreasing Pitch <br>
<strong>Haptic</strong>: Tap-Tap</p><p>The <code>.DirectionDown</code> type is intended for indicating a significant decrease value threshold has been crossed, such as when moving down a list.</p><h2 id="success"><code>.Success</code></h2><p><strong>Sound</strong>: Confirmation Ding <br>
<strong>Haptic</strong>: Tap-Tap-Tap</p><p>The <code>.Success</code> type is intended as a confirmation tone to indicate some action has been completed successfully.</p><h2 id="failure"><code>.Failure</code></h2><p><strong>Sound</strong>: Failure Ding <br>
<strong>Haptic</strong>: Long Vibrate</p><p>The <code>.Failure</code> type is intended as a failure tone to indicate some action has not been completed successfully.</p><h2 id="retry"><code>.Retry</code></h2><p><strong>Sound</strong>: Quick Ding-Ding-Ding <br>
<strong>Haptic</strong>: Long Vibrate</p><p>The <code>.Retry</code> type is intended as a gentle tone to indicate some action has not been completed successfully but the user has an opportunity to retry. Typically you should display some UI with this tone giving the user an opportunity to retry their failed action.</p><h2 id="start"><code>.Start</code></h2><p><strong>Sound</strong>: Long Ding <br>
<strong>Haptic</strong>: Long Tap</p><p>The <code>.Start</code> type is intended to indicate the start of an activity, such when a timer begins.</p><h2 id="end"><code>.End</code></h2><p><strong>Sound</strong>: Long Ding-Long Ding <br>
<strong>Haptic</strong>: Long Tap-Long Tap</p><p>The <code>.End</code> type is intended to indicate the end of an activity, such when a timer has ended.</p><h2 id="click"><code>.Click</code></h2><p><strong>Sound</strong>: Very soft click <br>
<strong>Haptic</strong>: Light tap</p><p>The <code>.Click</code> type is intended to indicate a clicking sound, like when a dial is clicking.</p>











































  

    
  
    

      

      
        <figure class="
              sqs-block-image-figure
              intrinsic
            "
        >
          
        
        

        
          
            
          
            
                
                
                
                
                
                
                
                <img data-stretch="false" data-image="https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1435014050323-0P0KOR758WMHPD4GFHT1/image-asset.png" data-image-dimensions="484x873" data-image-focal-point="0.5,0.5" alt="" data-load="false" elementtiming="system-image-block" data-sqsp-image-classic-block-image src="https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1435014050323-0P0KOR758WMHPD4GFHT1/image-asset.png?format=1000w" width="484" height="873" sizes="(max-width: 640px) 100vw, (max-width: 767px) 100vw, 100vw" onload="this.classList.add(&quot;loaded&quot;)" srcset="https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1435014050323-0P0KOR758WMHPD4GFHT1/image-asset.png?format=100w 100w, https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1435014050323-0P0KOR758WMHPD4GFHT1/image-asset.png?format=300w 300w, https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1435014050323-0P0KOR758WMHPD4GFHT1/image-asset.png?format=500w 500w, https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1435014050323-0P0KOR758WMHPD4GFHT1/image-asset.png?format=750w 750w, https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1435014050323-0P0KOR758WMHPD4GFHT1/image-asset.png?format=1000w 1000w, https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1435014050323-0P0KOR758WMHPD4GFHT1/image-asset.png?format=1500w 1500w, https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1435014050323-0P0KOR758WMHPD4GFHT1/image-asset.png?format=2500w 2500w" loading="lazy" decoding="async" data-loader="sqs">

            
          
        
          
        

        
          
          <figcaption data-sqsp-image-classic-block-caption-container class="image-caption-wrapper">
            <p>Haptic Demo sample provided on GitHub</p>
          </figcaption>
        
      
        </figure>
      

    
  


  


<h1 id="tapticengineconsiderations">Taptic Engine Considerations</h1>

<p>The Taptic Engine cannot overlap Haptics, and there is a delay between each one that can be played. So for example, let's say you wanted to play a <code>.Click</code> as you move through each item in a list. If you move quickly through the list, a lot of <code>.Click</code> haptics will be ignored, and your user will find it not feeling quite right when the taps fall out of sync from your UI.</p>

<p>Make sure that when you are designing your application, only use haptics on rare and significant events to both conserve battery as well as feel strange if they are asked to overlap and you end up losing feedback commands that you intended.</p>

<h1 id="tryingitout">Trying It Out</h1>

<p>We've provided sample code for an app to try out each of the haptic types on the <a href="https://github.com/sneakycrab/hapticdemo">Sneaky Crab GitHub</a>. Unfortunately, the current version of the watchOS Simulator does not support sounds, so you'll have to install this on your iOS 9/watchOS 2 hardware to try it out.</p>

<p><em>Remember that it is currently impossible to reverse a watchOS 2 update, so make sure that you only update to watchOS 2 for test devices and not your main Apple Watch, especially considering that watchOS 2 beta 1 is extremely unstable!</em></p>

<h1 id="wrappingup">Wrapping Up</h1>

<p>Apple provides a very simple API for providing haptic feedback to a user through the excellent Taptic Engine. Staying consistent with the intended meanings of the different types will allow a user to learn and understand what you are trying to convey without having to relearn anything while using your application.</p>

<p>How have you implemented Haptic feedback in your Apple Watch apps?</p>]]></description></item><item><title>WKInterfacePicker in WatchKit 2.0 - Using The Digital Crown</title><dc:creator>Michael Gu</dc:creator><pubDate>Fri, 12 Jun 2015 22:46:20 +0000</pubDate><link>https://www.sneakycrab.com/blog/2015/6/12/wkinterfacepicker-in-watchkit-20-using-the-digital-crown</link><guid isPermaLink="false">552351f8e4b0ea389c393627:5564269ee4b0c0ea1b06cf5e:557b0d90e4b04cad1c0b7885</guid><description><![CDATA[<p>Apple has provided a new <code>WKInterfaceObject</code> called <code>WKInterfacePicker</code>. It allows you to select an item from a list, similar to the <code>UIPickerView</code> you're already familiar with in iOS 8. You can use it on a list of text, images, and the items are selected by using the Digital Crown.</p>

<h2 id="pickerstyles">Picker Styles</h2>

<p>There are three main styles you can choose from: List, Stack and Sequence.</p>











































  

    
  
    

      

      
        <figure class="
              sqs-block-image-figure
              intrinsic
            "
        >
          
        
        

        
          
            
          
            
                
                
                
                
                
                
                
                <img data-stretch="false" data-image="https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434144101612-OHQPY83DOMXLX63HS1P5/image-asset.gif" data-image-dimensions="272x340" data-image-focal-point="0.5,0.5" alt="" data-load="false" elementtiming="system-image-block" data-sqsp-image-classic-block-image src="https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434144101612-OHQPY83DOMXLX63HS1P5/image-asset.gif?format=1000w" width="272" height="340" sizes="(max-width: 640px) 100vw, (max-width: 767px) 33.33333333333333vw, 33.33333333333333vw" onload="this.classList.add(&quot;loaded&quot;)" srcset="https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434144101612-OHQPY83DOMXLX63HS1P5/image-asset.gif?format=100w 100w, https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434144101612-OHQPY83DOMXLX63HS1P5/image-asset.gif?format=300w 300w, https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434144101612-OHQPY83DOMXLX63HS1P5/image-asset.gif?format=500w 500w, https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434144101612-OHQPY83DOMXLX63HS1P5/image-asset.gif?format=750w 750w, https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434144101612-OHQPY83DOMXLX63HS1P5/image-asset.gif?format=1000w 1000w, https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434144101612-OHQPY83DOMXLX63HS1P5/image-asset.gif?format=1500w 1500w, https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434144101612-OHQPY83DOMXLX63HS1P5/image-asset.gif?format=2500w 2500w" loading="lazy" decoding="async" data-loader="sqs">

            
          
        
          
        

        
          
          <figcaption data-sqsp-image-classic-block-caption-container class="image-caption-wrapper">
            <p>List Style Picker</p>
          </figcaption>
        
      
        </figure>
      

    
  


  













































  

    
  
    

      

      
        <figure class="
              sqs-block-image-figure
              intrinsic
            "
        >
          
        
        

        
          
            
          
            
                
                
                
                
                
                
                
                <img data-stretch="false" data-image="https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434145082583-QL95QE5TFVVEKPA9CP6Z/image-asset.gif" data-image-dimensions="272x340" data-image-focal-point="0.5,0.5" alt="" data-load="false" elementtiming="system-image-block" data-sqsp-image-classic-block-image src="https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434145082583-QL95QE5TFVVEKPA9CP6Z/image-asset.gif?format=1000w" width="272" height="340" sizes="(max-width: 640px) 100vw, (max-width: 767px) 33.33333333333333vw, 33.33333333333333vw" onload="this.classList.add(&quot;loaded&quot;)" srcset="https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434145082583-QL95QE5TFVVEKPA9CP6Z/image-asset.gif?format=100w 100w, https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434145082583-QL95QE5TFVVEKPA9CP6Z/image-asset.gif?format=300w 300w, https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434145082583-QL95QE5TFVVEKPA9CP6Z/image-asset.gif?format=500w 500w, https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434145082583-QL95QE5TFVVEKPA9CP6Z/image-asset.gif?format=750w 750w, https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434145082583-QL95QE5TFVVEKPA9CP6Z/image-asset.gif?format=1000w 1000w, https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434145082583-QL95QE5TFVVEKPA9CP6Z/image-asset.gif?format=1500w 1500w, https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434145082583-QL95QE5TFVVEKPA9CP6Z/image-asset.gif?format=2500w 2500w" loading="lazy" decoding="async" data-loader="sqs">

            
          
        
          
        

        
          
          <figcaption data-sqsp-image-classic-block-caption-container class="image-caption-wrapper">
            <p>Stack Style Picker</p>
          </figcaption>
        
      
        </figure>
      

    
  


  













































  

    
  
    

      

      
        <figure class="
              sqs-block-image-figure
              intrinsic
            "
        >
          
        
        

        
          
            
          
            
                
                
                
                
                
                
                
                <img data-stretch="false" data-image="https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434145828398-0GW8JPZEQ10JUQNJ0YV4/image-asset.gif" data-image-dimensions="272x340" data-image-focal-point="0.5,0.5" alt="" data-load="false" elementtiming="system-image-block" data-sqsp-image-classic-block-image src="https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434145828398-0GW8JPZEQ10JUQNJ0YV4/image-asset.gif?format=1000w" width="272" height="340" sizes="(max-width: 640px) 100vw, (max-width: 767px) 33.33333333333333vw, 33.33333333333333vw" onload="this.classList.add(&quot;loaded&quot;)" srcset="https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434145828398-0GW8JPZEQ10JUQNJ0YV4/image-asset.gif?format=100w 100w, https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434145828398-0GW8JPZEQ10JUQNJ0YV4/image-asset.gif?format=300w 300w, https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434145828398-0GW8JPZEQ10JUQNJ0YV4/image-asset.gif?format=500w 500w, https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434145828398-0GW8JPZEQ10JUQNJ0YV4/image-asset.gif?format=750w 750w, https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434145828398-0GW8JPZEQ10JUQNJ0YV4/image-asset.gif?format=1000w 1000w, https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434145828398-0GW8JPZEQ10JUQNJ0YV4/image-asset.gif?format=1500w 1500w, https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434145828398-0GW8JPZEQ10JUQNJ0YV4/image-asset.gif?format=2500w 2500w" loading="lazy" decoding="async" data-loader="sqs">

            
          
        
          
        

        
          
          <figcaption data-sqsp-image-classic-block-caption-container class="image-caption-wrapper">
            <p>Sequence Style Picker (Images from&nbsp;<a href="http://hmaidasani.github.io/RadialChartImageGenerator/">RadialChartImageGenerator</a>)</p>
          </figcaption>
        
      
        </figure>
      

    
  


  


<p>The List style is very similar the the <code>UIPickerView</code> in iOS, where you use the crown to select a sequential list of items. The items can be images and text, just text or just images.</p>

<p>The Stack Style animates the items like a stack of cards, providing an attractive way to select an item.</p>

<p>The Sequence Style replaces each image, allowing you to quickly flip between your choices, and also can be used to animate progress bars.</p>

<h2 id="focusstyles">Focus Styles</h2>

<p>For each style, you can indicate a focus style, which indicates how you want watchOS to display which picker is in focus. If there is only one picker on the screen, you may want to use None. If you have multiple pickers, you need to indicate which control is in focus and will be affected by the Digital Crown. For example, when customizing the clock face, Outline focus styles are used to indicate which complication is in focus to be adjusted by the Digital Crown.</p>

<p>Each picker item can be annotated by a caption, which can be used to indicate the group or secondary information about the item that will be displayed while picking. The caption can be useful if you are picking images, for example.</p>











































  

    
  
    

      

      
        <figure class="
              sqs-block-image-figure
              intrinsic
            "
        >
          
        
        

        
          
            
          
            
                
                
                
                
                
                
                
                <img data-stretch="false" data-image="https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434146539267-TFC7KTCYHF3LKG0LOXW9/image-asset.png" data-image-dimensions="272x340" data-image-focal-point="0.5,0.5" alt="" data-load="false" elementtiming="system-image-block" data-sqsp-image-classic-block-image src="https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434146539267-TFC7KTCYHF3LKG0LOXW9/image-asset.png?format=1000w" width="272" height="340" sizes="(max-width: 640px) 100vw, (max-width: 767px) 33.33333333333333vw, 33.33333333333333vw" onload="this.classList.add(&quot;loaded&quot;)" srcset="https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434146539267-TFC7KTCYHF3LKG0LOXW9/image-asset.png?format=100w 100w, https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434146539267-TFC7KTCYHF3LKG0LOXW9/image-asset.png?format=300w 300w, https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434146539267-TFC7KTCYHF3LKG0LOXW9/image-asset.png?format=500w 500w, https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434146539267-TFC7KTCYHF3LKG0LOXW9/image-asset.png?format=750w 750w, https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434146539267-TFC7KTCYHF3LKG0LOXW9/image-asset.png?format=1000w 1000w, https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434146539267-TFC7KTCYHF3LKG0LOXW9/image-asset.png?format=1500w 1500w, https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434146539267-TFC7KTCYHF3LKG0LOXW9/image-asset.png?format=2500w 2500w" loading="lazy" decoding="async" data-loader="sqs">

            
          
        
          
        

        
          
          <figcaption data-sqsp-image-classic-block-caption-container class="image-caption-wrapper">
            <p>Focus Style: None</p>
          </figcaption>
        
      
        </figure>
      

    
  


  













































  

    
  
    

      

      
        <figure class="
              sqs-block-image-figure
              intrinsic
            "
        >
          
        
        

        
          
            
          
            
                
                
                
                
                
                
                
                <img data-stretch="false" data-image="https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434146504649-5XJQ351IJIYXIN6YQBIO/image-asset.png" data-image-dimensions="272x340" data-image-focal-point="0.5,0.5" alt="" data-load="false" elementtiming="system-image-block" data-sqsp-image-classic-block-image src="https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434146504649-5XJQ351IJIYXIN6YQBIO/image-asset.png?format=1000w" width="272" height="340" sizes="(max-width: 640px) 100vw, (max-width: 767px) 33.33333333333333vw, 33.33333333333333vw" onload="this.classList.add(&quot;loaded&quot;)" srcset="https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434146504649-5XJQ351IJIYXIN6YQBIO/image-asset.png?format=100w 100w, https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434146504649-5XJQ351IJIYXIN6YQBIO/image-asset.png?format=300w 300w, https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434146504649-5XJQ351IJIYXIN6YQBIO/image-asset.png?format=500w 500w, https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434146504649-5XJQ351IJIYXIN6YQBIO/image-asset.png?format=750w 750w, https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434146504649-5XJQ351IJIYXIN6YQBIO/image-asset.png?format=1000w 1000w, https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434146504649-5XJQ351IJIYXIN6YQBIO/image-asset.png?format=1500w 1500w, https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434146504649-5XJQ351IJIYXIN6YQBIO/image-asset.png?format=2500w 2500w" loading="lazy" decoding="async" data-loader="sqs">

            
          
        
          
        

        
          
          <figcaption data-sqsp-image-classic-block-caption-container class="image-caption-wrapper">
            <p>Focus Style: Outline</p>
          </figcaption>
        
      
        </figure>
      

    
  


  













































  

    
  
    

      

      
        <figure class="
              sqs-block-image-figure
              intrinsic
            "
        >
          
        
        

        
          
            
          
            
                
                
                
                
                
                
                
                <img data-stretch="false" data-image="https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434146531300-3YE9TSPDNL519V4X5YLQ/image-asset.png" data-image-dimensions="272x340" data-image-focal-point="0.5,0.5" alt="" data-load="false" elementtiming="system-image-block" data-sqsp-image-classic-block-image src="https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434146531300-3YE9TSPDNL519V4X5YLQ/image-asset.png?format=1000w" width="272" height="340" sizes="(max-width: 640px) 100vw, (max-width: 767px) 33.33333333333333vw, 33.33333333333333vw" onload="this.classList.add(&quot;loaded&quot;)" srcset="https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434146531300-3YE9TSPDNL519V4X5YLQ/image-asset.png?format=100w 100w, https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434146531300-3YE9TSPDNL519V4X5YLQ/image-asset.png?format=300w 300w, https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434146531300-3YE9TSPDNL519V4X5YLQ/image-asset.png?format=500w 500w, https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434146531300-3YE9TSPDNL519V4X5YLQ/image-asset.png?format=750w 750w, https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434146531300-3YE9TSPDNL519V4X5YLQ/image-asset.png?format=1000w 1000w, https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434146531300-3YE9TSPDNL519V4X5YLQ/image-asset.png?format=1500w 1500w, https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434146531300-3YE9TSPDNL519V4X5YLQ/image-asset.png?format=2500w 2500w" loading="lazy" decoding="async" data-loader="sqs">

            
          
        
          
        

        
          
          <figcaption data-sqsp-image-classic-block-caption-container class="image-caption-wrapper">
            <p>Focus Style: Outline With Caption</p>
          </figcaption>
        
      
        </figure>
      

    
  


  





  <h2>Coding</h2><p>Open the Storyboard for your WatchKit App, and drag a Picker into your InterfaceController.</p>


































































  

    
  
    

      

      
        <figure class="
              sqs-block-image-figure
              intrinsic
            "
        >
          
        
        

        
          
            
          
            
                
                
                
                
                
                
                
                <img data-stretch="false" data-image="https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434147089963-7VBRY88EWZ788PJY51TJ/image-asset.png" data-image-dimensions="960x442" data-image-focal-point="0.5,0.5" alt="" data-load="false" elementtiming="system-image-block" data-sqsp-image-classic-block-image src="https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434147089963-7VBRY88EWZ788PJY51TJ/image-asset.png?format=1000w" width="960" height="442" sizes="(max-width: 640px) 100vw, (max-width: 767px) 100vw, 100vw" onload="this.classList.add(&quot;loaded&quot;)" srcset="https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434147089963-7VBRY88EWZ788PJY51TJ/image-asset.png?format=100w 100w, https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434147089963-7VBRY88EWZ788PJY51TJ/image-asset.png?format=300w 300w, https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434147089963-7VBRY88EWZ788PJY51TJ/image-asset.png?format=500w 500w, https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434147089963-7VBRY88EWZ788PJY51TJ/image-asset.png?format=750w 750w, https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434147089963-7VBRY88EWZ788PJY51TJ/image-asset.png?format=1000w 1000w, https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434147089963-7VBRY88EWZ788PJY51TJ/image-asset.png?format=1500w 1500w, https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1434147089963-7VBRY88EWZ788PJY51TJ/image-asset.png?format=2500w 2500w" loading="lazy" decoding="async" data-loader="sqs">

            
          
        
          
        

        
      
        </figure>
      

    
  


  





  <p>Choose the Style and Focus Style. The Indicator allows you to toggle whether the scroll guide appears beside the Digital Crown. This can be useful for styles like Stack, where it may not be clear to the user where in the list they have scrolled to.</p><p>Connect your picker to your interface controller twice, one for the outlet and one for the action.</p>
























  


  
    <pre><code class="language-swift">class InterfaceController: WKInterfaceController {
    @IBOutlet var itemPicker: WKInterfacePicker!

    @IBAction func pickerSelectedItemChanged(value: Int) {
    }
}
</code></pre>
  
  






<p>We're going to use the <code>IBOutlet</code> to set up the picker with initial values, and the <code>IBAction</code> to react to changes in the picker.</p>

<p>Here's the code for a picker populated with some text:</p>

  


  
    <pre><code class="language-swift">class ListPickerInterfaceController: WKInterfaceController {
    @IBOutlet var itemPicker: WKInterfacePicker!

    var foodList: [(String, String)] = [
        ("Broccoli", "Gross"),
        ("Brussel Sprouts", "Gross"),
        ("Soup", "Delicious"),
        ("Steak", "Delicious"),
        ("Ramen", "Delicious"),
        ("Pizza", "Delicious") ]

    override func willActivate() {
        super.willActivate()

        let pickerItems: [WKPickerItem] = foodList.map {
            let pickerItem = WKPickerItem()
            pickerItem.title = $0.0
            pickerItem.caption = $0.1
            return pickerItem
        }
        itemPicker.setItems(pickerItems)
    }

    @IBAction func pickerSelectedItemChanged(value: Int) {
        NSLog("List Picker: \(foodList[value].0) selected")
    }
}</code></pre>
  
  






<p>Modifying this to support images like in the Stack picker is very simple. Just use the new <code>WKImage</code> and pass those in. If you wanted to create a picker with images <code>frame1.png</code> to <code>frame5.png</code>:</p>

  


  
    <pre><code class="language-swift">class StackPickerInterfaceController : WKInterfaceController {
    @IBOutlet var itemPicker: WKInterfacePicker!

    var items: [String]! = nil
    
    override func willActivate() {
        super.willActivate()

        items = (1...5).map { "frame\($0).png" }
        
        let pickerItems: [WKPickerItem] = items.map {
            let pickerItem = WKPickerItem()
            pickerItem.contentImage = WKImage(imageName: $0)
            return pickerItem
        }
        itemPicker.setItems(pickerItems)
        itemPicker.focusForCrownInput()
    }

    @IBAction func pickerSelectedItemChanged(value: Int) {
        NSLog("Stack Picker: \(items[value]) selected.")
    }
}</code></pre>
  
  






<p>Finally, you'll find that a Sequence picker is set up exactly like the Stack picker:</p>

  


  
    <pre><code class="language-swift">class SequencePickerInterfaceController : WKInterfaceController {
    @IBOutlet var itemPicker: WKInterfacePicker!

    override func willActivate() {
        super.willActivate()

        let pickerItems: [WKPickerItem] = (0...100).map {
            let pickerItem = WKPickerItem()
            pickerItem.contentImage = WKImage(imageName: "picker\($0).png")
            return pickerItem
        }
        itemPicker.setItems(pickerItems)
    }
    
    @IBAction func pickerSelectedItemChanged(value: Int) {
        NSLog("Sequence Picker: \(value) selected.")
    }
}</code></pre>
  
  






<h2 id="wrappingup">Wrapping Up</h2>

<p>All of the sample code for this project is available in the <a href="https://github.com/sneakycrab/pickerdemo">Sneaky Crab GitHub</a>. If you're having trouble, make sure to download it and try out the sample code.</p>

<p><code>WKInterfacePicker</code> provides a simple way to do very attractive and easy to use picking using the Digital Crown in watchOS 2.</p>

<p>What cool interactions have you designed for your watch apps?</p>]]></description></item><item><title>Writing a WatchKit Complication in watchOS 2</title><dc:creator>Michael Gu</dc:creator><pubDate>Thu, 11 Jun 2015 04:13:08 +0000</pubDate><link>https://www.sneakycrab.com/blog/2015/6/10/writing-your-own-watchkit-complications</link><guid isPermaLink="false">552351f8e4b0ea389c393627:5564269ee4b0c0ea1b06cf5e:5578b7bbe4b08ce360da09a2</guid><description><![CDATA[<p>One of the exciting new additions to the WatchKit Framework in watchOS 2 is the ability to add custom complications to the clock faces provided by Apple. We've written a quick guide on how to add custom Complications to your watch app.</p>

<h2 id="implementclkcomplicationdatasource">Implement CLKComplicationDataSource</h2>

<p>All of the magic happens in <code>CLKComplicationDataSource</code>. Create a new class on your WatchKit Extension target that implements this delegate. Since every delegate method is required, we can start by adding the skeleton of every method in the delegate.</p>

  


  
    <pre><code class="language-swift">import ClockKit

class Cowmplication: NSObject, CLKComplicationDataSource {
    
    func getNextRequestedUpdateDateWithHandler(handler: (NSDate?) -> Void) {
        handler(nil)      
    }

    func getPlaceholderTemplateForComplication(complication: CLKComplication, withHandler handler: (CLKComplicationTemplate?) -> Void) {
        handler(nil)
    }
    
    func getPrivacyBehaviorForComplication(complication: CLKComplication, withHandler handler: (CLKComplicationPrivacyBehavior) -> Void) {
        handler(CLKComplicationPrivacyBehavior.ShowOnLockScreen)
    }
    
    func getCurrentTimelineEntryForComplication(complication: CLKComplication, withHandler handler: (CLKComplicationTimelineEntry?) -> Void) {
        handler(nil)
    }
    
    func getTimelineEntriesForComplication(complication: CLKComplication, beforeDate date: NSDate, limit: Int, withHandler handler: ([CLKComplicationTimelineEntry]?) -> Void) {
        handler(nil)
    }
  
    func getTimelineEntriesForComplication(complication: CLKComplication, afterDate date: NSDate, limit: Int, withHandler handler: ([CLKComplicationTimelineEntry]?) -> Void) {
        handler([])
    }

    func getSupportedTimeTravelDirectionsForComplication(complication: CLKComplication, withHandler handler: (CLKComplicationTimeTravelDirections) -> Void) {
        handler([CLKComplicationTimeTravelDirections.None])        
    }
    
    func getTimelineStartDateForComplication(complication: CLKComplication, withHandler handler: (NSDate?) -> Void) {
        handler(NSDate())
    }
    
    func getTimelineEndDateForComplication(complication: CLKComplication, withHandler handler: (NSDate?) -> Void) {
        handler(NSDate())
    }
}</code></pre>
  
  






<p>You never need to create an instance of this class, and Apple will handle instantiating it using the default constructor.</p>

<h2 id="understandingcomplicationfamilies">Understanding Complication Families</h2>

<p>There are 5 families of complications that we need to become familiar with in the <a href="https://developer.apple.com/library/prerelease/watchos/documentation/ClockKit/Reference/CLKComplication_class/index.html#//apple_ref/c/tdef/CLKComplicationFamily"><code>CLKComplicationFamily</code></a> enum. From left to right, here are images of <code>ModularSmall</code>, <code>ModularLarge</code>, <code>UtilitarianSmall</code>, <code>UtilitarianLarge</code>, <code>CircularSmall</code>.</p>



  

  



  
    
      

        

        

        
          
            
              
                
                <a role="presentation" aria-label="ModularSmall" class="
                    image-slide-anchor
                    
                    content-fit
                  "
                >
                  
                  <img class="thumb-image" elementtiming="system-gallery-block-grid" data-image="https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1433981880986-N8I5EETWDFNLYSVIBH5P/modularsmall.png" data-image-dimensions="272x340" data-image-focal-point="0.5,0.5" alt="ModularSmall" data-load="false" data-image-id="5578d3b8e4b0c9bb376ec835" data-type="image" src="https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1433981880986-N8I5EETWDFNLYSVIBH5P/modularsmall.png?format=1000w" /><br>
                </a>
                
              
            
          

          
        

      

        

        

        
          
            
              
                
                <a role="presentation" aria-label="ModularLarge" class="
                    image-slide-anchor
                    
                    content-fit
                  "
                >
                  
                  <img class="thumb-image" elementtiming="system-gallery-block-grid" data-image="https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1433981923939-NK6I6RY3MBJ1032AX04G/modularlarge.png" data-image-dimensions="272x340" data-image-focal-point="0.5,0.5" alt="ModularLarge" data-load="false" data-image-id="5578d3e3e4b06e95d2919752" data-type="image" src="https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1433981923939-NK6I6RY3MBJ1032AX04G/modularlarge.png?format=1000w" /><br>
                </a>
                
              
            
          

          
        

      

        

        

        
          
            
              
                
                <a role="presentation" aria-label="UtilitarianSmall" class="
                    image-slide-anchor
                    
                    content-fit
                  "
                >
                  
                  <img class="thumb-image" elementtiming="system-gallery-block-grid" data-image="https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1433982009146-00T3ITECHRXIN9NTOK1G/Simulator+Screen+Shot+Jun+10%2C+2015%2C+5.19.51+PM.png" data-image-dimensions="272x340" data-image-focal-point="0.5,0.5" alt="UtilitarianSmall" data-load="false" data-image-id="5578d439e4b0c89ed7226dbc" data-type="image" src="https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1433982009146-00T3ITECHRXIN9NTOK1G/Simulator+Screen+Shot+Jun+10%2C+2015%2C+5.19.51+PM.png?format=1000w" /><br>
                </a>
                
              
            
          

          
        

      

        

        

        
          
            
              
                
                <a role="presentation" aria-label="UtilitarianLarge" class="
                    image-slide-anchor
                    
                    content-fit
                  "
                >
                  
                  <img class="thumb-image" elementtiming="system-gallery-block-grid" data-image="https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1433982048012-646TIFZHUU6YUGVVKA1M/Simulator+Screen+Shot+Jun+10%2C+2015%2C+5.20.45+PM.png" data-image-dimensions="272x340" data-image-focal-point="0.5,0.5" alt="UtilitarianLarge" data-load="false" data-image-id="5578d460e4b0a20ad9434de7" data-type="image" src="https://images.squarespace-cdn.com/content/v1/552351f8e4b0ea389c393627/1433982048012-646TIFZHUU6YUGVVKA1M/Simulator+Screen+Shot+Jun+10%2C+2015%2C+5.20.45+PM.png?format=1000w" /><br>
                </a>
                
              
            
          

          
        

      

        

        

        
          
    