<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

  <title><![CDATA[Cyril Mottier]]></title>
  <link href="http://cyrilmottier.com/atom.xml" rel="self"/>
  <link href="http://cyrilmottier.com/"/>
  <updated>2013-05-27T10:35:53+02:00</updated>
  <id>http://cyrilmottier.com/</id>
  <author>
    <name><![CDATA[Cyril Mottier]]></name>
    
  </author>
  <generator uri="http://octopress.org/">Octopress</generator>

  
  <entry>
    <title type="html"><![CDATA[Pushing the ActionBar to the next level]]></title>
    <link href="http://cyrilmottier.com/2013/05/24/pushing-the-actionbar-to-the-next-level/"/>
    <updated>2013-05-24T14:29:00+02:00</updated>
    <id>http://cyrilmottier.com/2013/05/24/pushing-the-actionbar-to-the-next-level</id>
    <content type="html"><![CDATA[<p>Back in November 2012, I wrote a blog post entitled &#8221;<a href="http://cyrilmottier.com/2012/11/27/actionbar-on-the-move/">ActionBar on the Move</a>&#8221;. This article was mainly dealing with a technique to nicely and uniquely animate your <code>ActionBar</code>. Although I mentioned some of the  effect&#8217;s possible applications, I never had time to effectively add an <code>ActionBar</code> animation to one of my own apps nor saw an application on the Play Store taking advantage of it.</p>

<p>While being at Google I/O last week, I finally found an application using the <code>ActionBar</code> animation technique. Let&#8217;s be honest, it literally blew my mind the first time I saw it. I felt in love with the nice, subtle and yet extremely useful animated effect probably more than the entire app itself! I am pretty sure you know the application I am talking about as it has been presented during the Google I/O keynote. You have also probably recently received an update of it: Play Music!</p>

<!-- More -->


<p>The latest update of Play Music (v5.0) has been completely redesign and features a brand new artist/album detail screen. If you open such a detail screen, you&#8217;ll notice the <code>ActionBar</code> is initially invisible and overlaps a large image describing the artist/album. Once you start scrolling down (if possible), the <code>ActionBar</code> fades in gradually. The <code>ActionBar</code> turns completely opaque when the large image has been scrolled out of the screen.</p>

<p>Here are two main advantages of this <code>ActionBar</code> animation:</p>

<ul>
<li><p><strong>Polish the UI</strong>: animations synchronized on an element you&#8217;re interacting with are generally appreciated by users because it makes them feel the UI is natural and reacts to their actions. The fading animation is a direct consequence of the per-pixel scrolling state and not a launched-once animation.</p></li>
<li><p><strong>Take advantage of the screen real estate</strong>: while still preserving the UX of the platform, this pattern let the user primarily focus on the content rather than the controls. Used in addition to a nicely designed screen, it can be a game changer for your app&#8217;s interface.</p></li>
</ul>


<p>In this article, I will deep dive into the details of implementing the technique described in &#8221;<a href="http://cyrilmottier.com/2012/11/27/actionbar-on-the-move/">ActionBar on the Move</a>&#8221; to create an effect similar to the one used in the Play Music app.</p>

<p>In order to better understand the goal we are targeting, you can have a look at the screenshots below or alternatively download the sample application.</p>

<p><img class="center" src="http://cyrilmottier.com/media/2013/05/pushing-the-actionbar-to-the-next-level/action_bar_alpha_animation.png" title="ActionBar alpha animation" ></p>

<p><button class="download-button" onclick="window.location='/media/2013/05/pushing-the-actionbar-to-the-next-level/TranslucentActionBar.apk';"><span class="icon"></span><span class="title">Download the sample APK</span></button></p>

<h2>Application theming/styling</h2>

<p>As you can easily notice, in order to reproduce such an effect, the <code>ActionBar</code> must overlap the content of the screen. This can be easily done using the <code>android:windowActionBarOverlay</code> XML attributes. The code below describes the definition of the themes we&#8217;ll use:</p>

<figure class='code'><figcaption><span>values/themes.xml </span></figcaption>
 <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
</pre></td><td class='code'><pre><code class='xml'><span class='line'><span class="cp">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;</span>
</span><span class='line'><span class="nt">&lt;resources&gt;</span>
</span><span class='line'>    <span class="nt">&lt;style</span> <span class="na">name=</span><span class="s">&quot;Theme.TranslucentActionBar&quot;</span> <span class="na">parent=</span><span class="s">&quot;@android:style/Theme.Holo.Light.DarkActionBar&quot;</span><span class="nt">&gt;</span>
</span><span class='line'>        <span class="nt">&lt;item</span> <span class="na">name=</span><span class="s">&quot;android:actionBarStyle&quot;</span><span class="nt">&gt;</span>@style/Widget.ActionBar<span class="nt">&lt;/item&gt;</span>
</span><span class='line'>    <span class="nt">&lt;/style&gt;</span>
</span><span class='line'>
</span><span class='line'>    <span class="nt">&lt;style</span> <span class="na">name=</span><span class="s">&quot;Theme.TranslucentActionBar.ActionBar&quot;</span> <span class="nt">/&gt;</span>
</span><span class='line'>
</span><span class='line'>    <span class="nt">&lt;style</span> <span class="na">name=</span><span class="s">&quot;Theme.TranslucentActionBar.ActionBar.Overlay&quot;</span><span class="nt">&gt;</span>
</span><span class='line'>        <span class="nt">&lt;item</span> <span class="na">name=</span><span class="s">&quot;android:actionBarStyle&quot;</span><span class="nt">&gt;</span>@style/Widget.ActionBar.Transparent<span class="nt">&lt;/item&gt;</span>
</span><span class='line'>        <span class="nt">&lt;item</span> <span class="na">name=</span><span class="s">&quot;android:windowActionBarOverlay&quot;</span><span class="nt">&gt;</span>true<span class="nt">&lt;/item&gt;</span>
</span><span class='line'>    <span class="nt">&lt;/style&gt;</span>
</span><span class='line'><span class="nt">&lt;/resources&gt;</span>
</span></code></pre></td></tr></table></div></figure>


<p>Pretty logically, the style of the <code>ActionBar</code> is defined in <code>values/styles.xml</code> as follows:</p>

<figure class='code'><figcaption><span>values/styles.xml </span></figcaption>
 <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
</pre></td><td class='code'><pre><code class='xml'><span class='line'><span class="cp">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;</span>
</span><span class='line'><span class="nt">&lt;resources&gt;</span>
</span><span class='line'>    <span class="nt">&lt;style</span> <span class="na">name=</span><span class="s">&quot;Widget.ActionBar&quot;</span> <span class="na">parent=</span><span class="s">&quot;@android:style/Widget.Holo.Light.ActionBar.Solid.Inverse&quot;</span><span class="nt">&gt;</span>
</span><span class='line'>        <span class="nt">&lt;item</span> <span class="na">name=</span><span class="s">&quot;android:background&quot;</span><span class="nt">&gt;</span>@drawable/ab_background<span class="nt">&lt;/item&gt;</span>
</span><span class='line'>    <span class="nt">&lt;/style&gt;</span>
</span><span class='line'>
</span><span class='line'>    <span class="nt">&lt;style</span> <span class="na">name=</span><span class="s">&quot;Widget.ActionBar.Transparent&quot;</span><span class="nt">&gt;</span>
</span><span class='line'>        <span class="nt">&lt;item</span> <span class="na">name=</span><span class="s">&quot;android:background&quot;</span><span class="nt">&gt;</span>@android:color/transparent<span class="nt">&lt;/item&gt;</span>
</span><span class='line'>    <span class="nt">&lt;/style&gt;</span>
</span><span class='line'><span class="nt">&lt;/resources&gt;</span>
</span></code></pre></td></tr></table></div></figure>


<p>Finally, we can use these themes in order to style our <code>Activity</code>.</p>

<figure class='code'><figcaption><span>AndroidManifest.xml </span></figcaption>
 <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
</pre></td><td class='code'><pre><code class='xml'><span class='line'><span class="cp">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;</span>
</span><span class='line'><span class="nt">&lt;manifest</span> <span class="na">xmlns:android=</span><span class="s">&quot;http://schemas.android.com/apk/res/android&quot;</span>
</span><span class='line'>    <span class="na">package=</span><span class="s">&quot;com.cyrilmottier.android.translucentactionbar&quot;</span>
</span><span class='line'>    <span class="na">android:versionCode=</span><span class="s">&quot;1&quot;</span>
</span><span class='line'>    <span class="na">android:versionName=</span><span class="s">&quot;1.0&quot;</span> <span class="nt">&gt;</span>
</span><span class='line'>
</span><span class='line'>    <span class="nt">&lt;uses-sdk</span>
</span><span class='line'>        <span class="na">android:minSdkVersion=</span><span class="s">&quot;14&quot;</span>
</span><span class='line'>        <span class="na">android:targetSdkVersion=</span><span class="s">&quot;17&quot;</span> <span class="nt">/&gt;</span>
</span><span class='line'>
</span><span class='line'>    <span class="nt">&lt;application</span>
</span><span class='line'>        <span class="na">android:allowBackup=</span><span class="s">&quot;true&quot;</span>
</span><span class='line'>        <span class="na">android:icon=</span><span class="s">&quot;@drawable/ic_launcher&quot;</span>
</span><span class='line'>        <span class="na">android:label=</span><span class="s">&quot;@string/app_name&quot;</span>
</span><span class='line'>        <span class="na">android:theme=</span><span class="s">&quot;@style/Theme.TranslucentActionBar&quot;</span><span class="nt">&gt;</span>
</span><span class='line'>
</span><span class='line'>        <span class="nt">&lt;activity</span>
</span><span class='line'>                <span class="na">android:name=</span><span class="s">&quot;.HomeActivity&quot;</span>
</span><span class='line'>                <span class="na">android:theme=</span><span class="s">&quot;@style/Theme.TranslucentActionBar.ActionBar.Overlay&quot;</span><span class="nt">&gt;</span>
</span><span class='line'>            <span class="nt">&lt;intent-filter&gt;</span>
</span><span class='line'>                <span class="nt">&lt;action</span> <span class="na">android:name=</span><span class="s">&quot;android.intent.action.MAIN&quot;</span> <span class="nt">/&gt;</span>
</span><span class='line'>                <span class="nt">&lt;category</span> <span class="na">android:name=</span><span class="s">&quot;android.intent.category.LAUNCHER&quot;</span> <span class="nt">/&gt;</span>
</span><span class='line'>            <span class="nt">&lt;/intent-filter&gt;</span>
</span><span class='line'>        <span class="nt">&lt;/activity&gt;</span>
</span><span class='line'>
</span><span class='line'>    <span class="nt">&lt;/application&gt;</span>
</span><span class='line'>
</span><span class='line'><span class="nt">&lt;/manifest&gt;</span>
</span></code></pre></td></tr></table></div></figure>


<p>Note that by using themes/styles we remove all potential flickering issues at startup (see <a href="http://cyrilmottier.com/2013/01/23/android-app-launching-made-gorgeous/">Android App Launching Made Gorgeous</a> for more information).</p>

<h2>Getting the content ready</h2>

<p>As explained previously, the <code>ActionBar</code> fading is synchronized on the per-pixel state scrolling of the scrolling container. In this example, we&#8217;ll simply use a <code>ScrollView</code> as a scrolling container. One of the major drawback of this container is you can&#8217;t register a listener in order to be notified when the scroll has changed. This can be easily done be creating a <code>NotifyingScrollView</code> extending the original <code>ScrollView</code>:</p>

<figure class='code'><figcaption><span>NotifyingScrollView.java </span></figcaption>
 <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="kn">package</span> <span class="n">com</span><span class="o">.</span><span class="na">cyrilmottier</span><span class="o">.</span><span class="na">android</span><span class="o">.</span><span class="na">translucentactionbar</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.content.Context</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.util.AttributeSet</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.widget.ScrollView</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'><span class="cm">/**</span>
</span><span class='line'><span class="cm"> * @author Cyril Mottier</span>
</span><span class='line'><span class="cm"> */</span>
</span><span class='line'><span class="kd">public</span> <span class="kd">class</span> <span class="nc">NotifyingScrollView</span> <span class="kd">extends</span> <span class="n">ScrollView</span> <span class="o">{</span>
</span><span class='line'>
</span><span class='line'>    <span class="cm">/**</span>
</span><span class='line'><span class="cm">     * @author Cyril Mottier</span>
</span><span class='line'><span class="cm">     */</span>
</span><span class='line'>    <span class="kd">public</span> <span class="kd">interface</span> <span class="nc">OnScrollChangedListener</span> <span class="o">{</span>
</span><span class='line'>        <span class="kt">void</span> <span class="nf">onScrollChanged</span><span class="o">(</span><span class="n">ScrollView</span> <span class="n">who</span><span class="o">,</span> <span class="kt">int</span> <span class="n">l</span><span class="o">,</span> <span class="kt">int</span> <span class="n">t</span><span class="o">,</span> <span class="kt">int</span> <span class="n">oldl</span><span class="o">,</span> <span class="kt">int</span> <span class="n">oldt</span><span class="o">);</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">private</span> <span class="n">OnScrollChangedListener</span> <span class="n">mOnScrollChangedListener</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">public</span> <span class="nf">NotifyingScrollView</span><span class="o">(</span><span class="n">Context</span> <span class="n">context</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="kd">super</span><span class="o">(</span><span class="n">context</span><span class="o">);</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">public</span> <span class="nf">NotifyingScrollView</span><span class="o">(</span><span class="n">Context</span> <span class="n">context</span><span class="o">,</span> <span class="n">AttributeSet</span> <span class="n">attrs</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="kd">super</span><span class="o">(</span><span class="n">context</span><span class="o">,</span> <span class="n">attrs</span><span class="o">);</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">public</span> <span class="nf">NotifyingScrollView</span><span class="o">(</span><span class="n">Context</span> <span class="n">context</span><span class="o">,</span> <span class="n">AttributeSet</span> <span class="n">attrs</span><span class="o">,</span> <span class="kt">int</span> <span class="n">defStyle</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="kd">super</span><span class="o">(</span><span class="n">context</span><span class="o">,</span> <span class="n">attrs</span><span class="o">,</span> <span class="n">defStyle</span><span class="o">);</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="nd">@Override</span>
</span><span class='line'>    <span class="kd">protected</span> <span class="kt">void</span> <span class="nf">onScrollChanged</span><span class="o">(</span><span class="kt">int</span> <span class="n">l</span><span class="o">,</span> <span class="kt">int</span> <span class="n">t</span><span class="o">,</span> <span class="kt">int</span> <span class="n">oldl</span><span class="o">,</span> <span class="kt">int</span> <span class="n">oldt</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="kd">super</span><span class="o">.</span><span class="na">onScrollChanged</span><span class="o">(</span><span class="n">l</span><span class="o">,</span> <span class="n">t</span><span class="o">,</span> <span class="n">oldl</span><span class="o">,</span> <span class="n">oldt</span><span class="o">);</span>
</span><span class='line'>        <span class="k">if</span> <span class="o">(</span><span class="n">mOnScrollChangedListener</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>            <span class="n">mOnScrollChangedListener</span><span class="o">.</span><span class="na">onScrollChanged</span><span class="o">(</span><span class="k">this</span><span class="o">,</span> <span class="n">l</span><span class="o">,</span> <span class="n">t</span><span class="o">,</span> <span class="n">oldl</span><span class="o">,</span> <span class="n">oldt</span><span class="o">);</span>
</span><span class='line'>        <span class="o">}</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">setOnScrollChangedListener</span><span class="o">(</span><span class="n">OnScrollChangedListener</span> <span class="n">listener</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="n">mOnScrollChangedListener</span> <span class="o">=</span> <span class="n">listener</span><span class="o">;</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'><span class="o">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>Then, we can use this new scrolling container in an XML layout:</p>

<figure class='code'><figcaption><span>layout/activity_home.xml </span></figcaption>
 <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
</pre></td><td class='code'><pre><code class='xml'><span class='line'><span class="cp">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;</span>
</span><span class='line'><span class="nt">&lt;com.cyrilmottier.android.translucentactionbar.NotifyingScrollView</span>
</span><span class='line'>    <span class="na">xmlns:android=</span><span class="s">&quot;http://schemas.android.com/apk/res/android&quot;</span>
</span><span class='line'>    <span class="na">android:id=</span><span class="s">&quot;@+id/scroll_view&quot;</span>
</span><span class='line'>    <span class="na">android:layout_width=</span><span class="s">&quot;match_parent&quot;</span>
</span><span class='line'>    <span class="na">android:layout_height=</span><span class="s">&quot;match_parent&quot;</span><span class="nt">&gt;</span>
</span><span class='line'>
</span><span class='line'>    <span class="nt">&lt;LinearLayout</span>
</span><span class='line'>        <span class="na">android:layout_width=</span><span class="s">&quot;match_parent&quot;</span>
</span><span class='line'>        <span class="na">android:layout_height=</span><span class="s">&quot;wrap_content&quot;</span>
</span><span class='line'>        <span class="na">android:orientation=</span><span class="s">&quot;vertical&quot;</span><span class="nt">&gt;</span>
</span><span class='line'>
</span><span class='line'>        <span class="nt">&lt;ImageView</span>
</span><span class='line'>            <span class="na">android:id=</span><span class="s">&quot;@+id/image_header&quot;</span>
</span><span class='line'>            <span class="na">android:layout_width=</span><span class="s">&quot;match_parent&quot;</span>
</span><span class='line'>            <span class="na">android:layout_height=</span><span class="s">&quot;wrap_content&quot;</span>
</span><span class='line'>            <span class="na">android:scaleType=</span><span class="s">&quot;centerCrop&quot;</span>
</span><span class='line'>            <span class="na">android:src=</span><span class="s">&quot;@drawable/daft_punk&quot;</span><span class="nt">/&gt;</span>
</span><span class='line'>
</span><span class='line'>      <span class="cp">&lt;! -- Some long content --&gt;</span>
</span><span class='line'>
</span><span class='line'>    <span class="nt">&lt;/LinearLayout&gt;</span>
</span><span class='line'>
</span><span class='line'><span class="nt">&lt;/com.cyrilmottier.android.translucentactionbar.NotifyingScrollView&gt;</span>
</span></code></pre></td></tr></table></div></figure>


<h2>Fading in/out the ActionBar</h2>

<p>Now most of the boilerplate is ready, we can plug all of these components together. The <code>ActionBar</code> algorithm is rather simple and only consists on computing the alpha depending on the current per-pixel scrolling state of the <code>NotifyingScrollView</code>. Note that the effective scrolled distance must be clamped to [0, <em>image_height - actionbar_height</em>] in order to avoid weird values that may occur mainly because of the default over scroll behavior of scrolling containers on Android:</p>

<figure class='code'><figcaption><span>HomeActivity.java </span></figcaption>
 <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="kn">package</span> <span class="n">com</span><span class="o">.</span><span class="na">cyrilmottier</span><span class="o">.</span><span class="na">android</span><span class="o">.</span><span class="na">translucentactionbar</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.app.Activity</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.graphics.drawable.Drawable</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.os.Build</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.os.Bundle</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.support.v4.view.GravityCompat</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.support.v4.widget.DrawerLayout</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.util.Log</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.view.Menu</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.widget.ScrollView</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'><span class="kd">public</span> <span class="kd">class</span> <span class="nc">HomeActivity</span> <span class="kd">extends</span> <span class="n">Activity</span> <span class="o">{</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">private</span> <span class="n">Drawable</span> <span class="n">mActionBarBackgroundDrawable</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'>    <span class="nd">@Override</span>
</span><span class='line'>    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">onCreate</span><span class="o">(</span><span class="n">Bundle</span> <span class="n">savedInstanceState</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="kd">super</span><span class="o">.</span><span class="na">onCreate</span><span class="o">(</span><span class="n">savedInstanceState</span><span class="o">);</span>
</span><span class='line'>        <span class="n">setContentView</span><span class="o">(</span><span class="n">R</span><span class="o">.</span><span class="na">layout</span><span class="o">.</span><span class="na">activity_home</span><span class="o">);</span>
</span><span class='line'>
</span><span class='line'>        <span class="n">mActionBarBackgroundDrawable</span> <span class="o">=</span> <span class="n">getResources</span><span class="o">().</span><span class="na">getDrawable</span><span class="o">(</span><span class="n">R</span><span class="o">.</span><span class="na">drawable</span><span class="o">.</span><span class="na">ab_background</span><span class="o">);</span>
</span><span class='line'>        <span class="n">mActionBarBackgroundDrawable</span><span class="o">.</span><span class="na">setAlpha</span><span class="o">(</span><span class="mi">0</span><span class="o">);</span>
</span><span class='line'>
</span><span class='line'>        <span class="n">getActionBar</span><span class="o">().</span><span class="na">setBackgroundDrawable</span><span class="o">(</span><span class="n">mActionBarBackgroundDrawable</span><span class="o">);</span>
</span><span class='line'>
</span><span class='line'>        <span class="o">((</span><span class="n">NotifyingScrollView</span><span class="o">)</span> <span class="n">findViewById</span><span class="o">(</span><span class="n">R</span><span class="o">.</span><span class="na">id</span><span class="o">.</span><span class="na">scroll_view</span><span class="o">)).</span><span class="na">setOnScrollChangedListener</span><span class="o">(</span><span class="n">mOnScrollChangedListener</span><span class="o">);</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">private</span> <span class="n">NotifyingScrollView</span><span class="o">.</span><span class="na">OnScrollChangedListener</span> <span class="n">mOnScrollChangedListener</span> <span class="o">=</span> <span class="k">new</span> <span class="n">NotifyingScrollView</span><span class="o">.</span><span class="na">OnScrollChangedListener</span><span class="o">()</span> <span class="o">{</span>
</span><span class='line'>        <span class="kd">public</span> <span class="kt">void</span> <span class="nf">onScrollChanged</span><span class="o">(</span><span class="n">ScrollView</span> <span class="n">who</span><span class="o">,</span> <span class="kt">int</span> <span class="n">l</span><span class="o">,</span> <span class="kt">int</span> <span class="n">t</span><span class="o">,</span> <span class="kt">int</span> <span class="n">oldl</span><span class="o">,</span> <span class="kt">int</span> <span class="n">oldt</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>            <span class="kd">final</span> <span class="kt">int</span> <span class="n">headerHeight</span> <span class="o">=</span> <span class="n">findViewById</span><span class="o">(</span><span class="n">R</span><span class="o">.</span><span class="na">id</span><span class="o">.</span><span class="na">image_header</span><span class="o">).</span><span class="na">getHeight</span><span class="o">()</span> <span class="o">-</span> <span class="n">getActionBar</span><span class="o">().</span><span class="na">getHeight</span><span class="o">();</span>
</span><span class='line'>            <span class="kd">final</span> <span class="kt">float</span> <span class="n">ratio</span> <span class="o">=</span> <span class="o">(</span><span class="kt">float</span><span class="o">)</span> <span class="n">Math</span><span class="o">.</span><span class="na">min</span><span class="o">(</span><span class="n">Math</span><span class="o">.</span><span class="na">max</span><span class="o">(</span><span class="n">t</span><span class="o">,</span> <span class="mi">0</span><span class="o">),</span> <span class="n">headerHeight</span><span class="o">)</span> <span class="o">/</span> <span class="n">headerHeight</span><span class="o">;</span>
</span><span class='line'>            <span class="kd">final</span> <span class="kt">int</span> <span class="n">newAlpha</span> <span class="o">=</span> <span class="o">(</span><span class="kt">int</span><span class="o">)</span> <span class="o">(</span><span class="n">ratio</span> <span class="o">*</span> <span class="mi">255</span><span class="o">);</span>
</span><span class='line'>            <span class="n">mActionBarBackgroundDrawable</span><span class="o">.</span><span class="na">setAlpha</span><span class="o">(</span><span class="n">newAlpha</span><span class="o">);</span>
</span><span class='line'>        <span class="o">}</span>
</span><span class='line'>    <span class="o">};</span>
</span><span class='line'><span class="o">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>As described in &#8221;<a href="http://cyrilmottier.com/2012/11/27/actionbar-on-the-move/">ActionBar on the Move</a>&#8221;, this snippet of code above doesn&#8217;t work for pre-JELLY_BEAN_MR1 devices. Indeed, the <code>ActionBar</code> isn&#8217;t invalidating itself when required because it isn&#8217;t registering itself as the <code>Drawable</code>&#8217;s callback. You can workaround this issue simply be attaching the following <code>Callback</code> in the <code>onCreate(Bundle)</code> method:</p>

<figure class='code'><figcaption><span>HomeActivity.java </span></figcaption>
 <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="kd">private</span> <span class="n">Drawable</span><span class="o">.</span><span class="na">Callback</span> <span class="n">mDrawableCallback</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Drawable</span><span class="o">.</span><span class="na">Callback</span><span class="o">()</span> <span class="o">{</span>
</span><span class='line'>    <span class="nd">@Override</span>
</span><span class='line'>    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">invalidateDrawable</span><span class="o">(</span><span class="n">Drawable</span> <span class="n">who</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="n">getActionBar</span><span class="o">().</span><span class="na">setBackgroundDrawable</span><span class="o">(</span><span class="n">who</span><span class="o">);</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="nd">@Override</span>
</span><span class='line'>    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">scheduleDrawable</span><span class="o">(</span><span class="n">Drawable</span> <span class="n">who</span><span class="o">,</span> <span class="n">Runnable</span> <span class="n">what</span><span class="o">,</span> <span class="kt">long</span> <span class="n">when</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="nd">@Override</span>
</span><span class='line'>    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">unscheduleDrawable</span><span class="o">(</span><span class="n">Drawable</span> <span class="n">who</span><span class="o">,</span> <span class="n">Runnable</span> <span class="n">what</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'><span class="o">};</span>
</span></code></pre></td></tr></table></div></figure>




<figure class='code'><figcaption><span>HomeActivity.java </span></figcaption>
 <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="k">if</span> <span class="o">(</span><span class="n">Build</span><span class="o">.</span><span class="na">VERSION</span><span class="o">.</span><span class="na">SDK_INT</span> <span class="o">&lt;</span> <span class="n">Build</span><span class="o">.</span><span class="na">VERSION_CODES</span><span class="o">.</span><span class="na">JELLY_BEAN_MR1</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>    <span class="n">mActionBarBackgroundDrawable</span><span class="o">.</span><span class="na">setCallback</span><span class="o">(</span><span class="n">mDrawableCallback</span><span class="o">);</span>
</span><span class='line'><span class="o">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>You can already run the code &#8220;as it&#8221;. Although the result looks alike the animation used in Play Music we can still continue to tweak it to make it better.</p>

<h2>A final brush stroke</h2>

<h3>Enforcing ActionBar contrast</h3>

<p>Having an transparent <code>ActionBar</code> may lead to design issues because you generally don&#8217;t know about the background you&#8217;ll be displayed on top of. For instance you may end up with a transparent <code>ActionBar</code> displaying a white text on top of a white description image. No need to say it makes the <code>ActionBar</code> invisible and useless.</p>

<p>The easiest way to avoid such a problem consists on modifying the image to make it a little bit darker at the top. Thus, in a worse case scenario (i.e. white image) we would have a grey area on top of the image making the <code>ActionBar</code> content (title, icons, buttons, etc.) visible.</p>

<p>A simple way to do that is to overlay a translucent dark to transparent gradient on top of the image. This can be done in XML only with the <code>Drawable</code> described below:</p>

<figure class='code'><figcaption><span>drawable/gradient.xml </span></figcaption>
 <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
</pre></td><td class='code'><pre><code class='xml'><span class='line'><span class="cp">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;</span>
</span><span class='line'><span class="nt">&lt;shape</span> <span class="na">xmlns:android=</span><span class="s">&quot;http://schemas.android.com/apk/res/android&quot;</span>
</span><span class='line'>       <span class="na">android:shape=</span><span class="s">&quot;rectangle&quot;</span><span class="nt">&gt;</span>
</span><span class='line'>
</span><span class='line'>    <span class="nt">&lt;size</span> <span class="na">android:height=</span><span class="s">&quot;100dp&quot;</span><span class="nt">/&gt;</span>
</span><span class='line'>
</span><span class='line'>    <span class="nt">&lt;gradient</span>
</span><span class='line'>        <span class="na">android:angle=</span><span class="s">&quot;270&quot;</span>
</span><span class='line'>        <span class="na">android:startColor=</span><span class="s">&quot;#8000&quot;</span>
</span><span class='line'>        <span class="na">android:endColor=</span><span class="s">&quot;#0000&quot;</span><span class="nt">/&gt;</span>
</span><span class='line'>
</span><span class='line'><span class="nt">&lt;/shape&gt;</span>
</span></code></pre></td></tr></table></div></figure>


<p>The gradient is overlaid using a wrapping <code>FrameLayout</code>:</p>

<figure class='code'><figcaption><span>layout/activity_home.xml </span></figcaption>
 <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
</pre></td><td class='code'><pre><code class='xml'><span class='line'><span class="nt">&lt;FrameLayout</span>
</span><span class='line'>    <span class="na">android:layout_width=</span><span class="s">&quot;match_parent&quot;</span>
</span><span class='line'>    <span class="na">android:layout_height=</span><span class="s">&quot;wrap_content&quot;</span><span class="nt">&gt;</span>
</span><span class='line'>
</span><span class='line'>    <span class="nt">&lt;ImageView</span>
</span><span class='line'>        <span class="na">android:id=</span><span class="s">&quot;@+id/image_header&quot;</span>
</span><span class='line'>        <span class="na">android:layout_width=</span><span class="s">&quot;match_parent&quot;</span>
</span><span class='line'>        <span class="na">android:layout_height=</span><span class="s">&quot;wrap_content&quot;</span>
</span><span class='line'>        <span class="na">android:scaleType=</span><span class="s">&quot;centerCrop&quot;</span>
</span><span class='line'>        <span class="na">android:src=</span><span class="s">&quot;@drawable/daft_punk&quot;</span><span class="nt">/&gt;</span>
</span><span class='line'>
</span><span class='line'>    <span class="nt">&lt;View</span>
</span><span class='line'>        <span class="na">android:layout_width=</span><span class="s">&quot;match_parent&quot;</span>
</span><span class='line'>        <span class="na">android:layout_height=</span><span class="s">&quot;wrap_content&quot;</span>
</span><span class='line'>        <span class="na">android:background=</span><span class="s">&quot;@drawable/gradient&quot;</span><span class="nt">/&gt;</span>
</span><span class='line'>
</span><span class='line'><span class="nt">&lt;/FrameLayout&gt;</span>
</span></code></pre></td></tr></table></div></figure>


<h3>Avoid over-scroll</h3>

<p>In Gingerbread (API 9), Android introduced a brand new way to notify the user a scrollable container is being scrolled beyond the content bounds. First it introduced the notion of <code>EdgeEffect</code> (available in the API starting API 14) and enabled over-scroll. While this is not a problem in general, it can be pretty annoying when one of the edge of your scrollable content is different from the background color.</p>

<p>You can reproduce it be simply flinging the <code>ScrollView</code> rapidly to the top and you&#8217;ll notice some white color (the background color) appears on top of the screen because the image is scrolling beyond the bounds. I personally consider this a a UI glitch and usually prefer disabling it in this rare cases.</p>

<p>One could imagine the best way to avoid over-scroll is to use <code>View#setOverScrollMode(int)</code> to change the mode to <code>View#OVER_SCROLL_NEVER</code>. Although it works, it also remove the edge effect which can be visually disturbing<sup>1</sup>. A simple way to do that is to modify the <code>NotifyingScrollView</code> to force the maximum over scroll values to zero when necessary:</p>

<figure class='code'><figcaption><span>NotifyingScrollView.java </span></figcaption>
 <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="kd">private</span> <span class="kt">boolean</span> <span class="n">mIsOverScrollEnabled</span> <span class="o">=</span> <span class="kc">true</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'><span class="kd">public</span> <span class="kt">void</span> <span class="nf">setOverScrollEnabled</span><span class="o">(</span><span class="kt">boolean</span> <span class="n">enabled</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>    <span class="n">mIsOverScrollEnabled</span> <span class="o">=</span> <span class="n">enabled</span><span class="o">;</span>
</span><span class='line'><span class="o">}</span>
</span><span class='line'>
</span><span class='line'><span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">isOverScrollEnabled</span><span class="o">()</span> <span class="o">{</span>
</span><span class='line'>    <span class="k">return</span> <span class="n">mIsOverScrollEnabled</span><span class="o">;</span>
</span><span class='line'><span class="o">}</span>
</span><span class='line'>
</span><span class='line'><span class="nd">@Override</span>
</span><span class='line'><span class="kd">protected</span> <span class="kt">boolean</span> <span class="nf">overScrollBy</span><span class="o">(</span><span class="kt">int</span> <span class="n">deltaX</span><span class="o">,</span> <span class="kt">int</span> <span class="n">deltaY</span><span class="o">,</span> <span class="kt">int</span> <span class="n">scrollX</span><span class="o">,</span> <span class="kt">int</span> <span class="n">scrollY</span><span class="o">,</span> <span class="kt">int</span> <span class="n">scrollRangeX</span><span class="o">,</span> <span class="kt">int</span> <span class="n">scrollRangeY</span><span class="o">,</span>
</span><span class='line'>                               <span class="kt">int</span> <span class="n">maxOverScrollX</span><span class="o">,</span> <span class="kt">int</span> <span class="n">maxOverScrollY</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">isTouchEvent</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>    <span class="k">return</span> <span class="kd">super</span><span class="o">.</span><span class="na">overScrollBy</span><span class="o">(</span>
</span><span class='line'>            <span class="n">deltaX</span><span class="o">,</span>
</span><span class='line'>            <span class="n">deltaY</span><span class="o">,</span>
</span><span class='line'>            <span class="n">scrollX</span><span class="o">,</span>
</span><span class='line'>            <span class="n">scrollY</span><span class="o">,</span>
</span><span class='line'>            <span class="n">scrollRangeX</span><span class="o">,</span>
</span><span class='line'>            <span class="n">scrollRangeY</span><span class="o">,</span>
</span><span class='line'>            <span class="n">mIsOverScrollEnabled</span> <span class="o">?</span> <span class="n">maxOverScrollX</span> <span class="o">:</span> <span class="mi">0</span><span class="o">,</span>
</span><span class='line'>            <span class="n">mIsOverScrollEnabled</span> <span class="o">?</span> <span class="n">maxOverScrollY</span> <span class="o">:</span> <span class="mi">0</span><span class="o">,</span>
</span><span class='line'>            <span class="n">isTouchEvent</span><span class="o">);</span>
</span><span class='line'><span class="o">}</span>
</span></code></pre></td></tr></table></div></figure>


<h2>Conclusion</h2>

<p>I seriously don&#8217;t know if the team behind the Play Music application decided to implement the behavior based on my article. But it appears they brilliantly used the technique to both polish and emphasize the UI. It is clearly an awesome pattern to use whenever you need to design a screen which content is self-explanatory and is more important than the <code>ActionBar</code> content itself.</p>

<hr />

<ol>
<li>Do not ask me why the naming of the constants/method is so ambiguous&#8230;</li>
</ol>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Enhancing Google Maps API v2 with Polaris v2]]></title>
    <link href="http://cyrilmottier.com/2013/05/02/enhancing-google-maps-api-v2-with-polaris-v2/"/>
    <updated>2013-05-02T14:00:00+02:00</updated>
    <id>http://cyrilmottier.com/2013/05/02/enhancing-google-maps-api-v2-with-polaris-v2</id>
    <content type="html"><![CDATA[<p>In October 2012, I released a library called <a href="https://github.com/cyrilmottier/Polaris">Polaris</a>. At that time, the library received quite a lot of success because it was really filling the mammoth blanks of the Google Maps external library (aka Google Maps Android API v1): effortless map annotation, gesture support, map callout support, built-in “user tracking” mode, etc. If you have never heard of Polaris feel free to checkout one of the links below:</p>

<ul>
<li><a href="https://github.com/cyrilmottier/Polaris">Polaris GitHub page</a></li>
<li><a href="http://cyrilmottier.com/2012/10/12/meet-polaris-a-map-library-for-android/">&#8220;Meet Polaris, a Map Library for Android&#8221; blog post</a></li>
<li><a href="https://speakerdeck.com/cyrilmottier/polaris-simple-mapping-library-for-android">&#8220;Polaris, simple mapping library for Android&#8221; slides</a></li>
</ul>


<!-- More -->


<p>(Un)fortunately - the addition/removal of the &#8216;un&#8217; obviously depends on the point of view - Google released a radically different and new version of the library in December 2012. In addition to this release they announced the deprecation of the first version of the API as of March 2013<sup>1</sup>. Let&#8217;s be honest, at first I was pretty annoyed by this new release because it turned almost all of my work to a waste of time. On the other hand, I was quite happy to notice the new API were really close - functionaly and <em>API-ly</em> speaking - to what I did on my own with Polaris.</p>

<p>Back in December I gave my <a href="http://cyrilmottier.com/2012/12/07/the-google-maps-android-api-v2-utopia/">point of view</a> about the new Google Maps Android API v2. After almost 6 months, the library has been updated only once (as part of the Google Play Service, it was supposed to be updated very often…) and is not a great starting base for building libraries on top of it (all of the classes are final and hence cannot be extended).</p>

<p>With the release of AVélov 1.2, a lot of people were interested in the <a href="http://www.youtube.com/watch?v=3R7cGxahDEk">animated clustering algorithm</a> I developed. Several companies asked me for the app source code and I was quite frustrated not being able to deliver a true library but only a sample code. That was true until I decided to find a way around the Google&#8217;s locked down library. I finally managed to by-pass the &#8216;final&#8217; limitation fairly easily. I entirely wrapped the original Google&#8217;s library into my own library: Polaris v2.</p>

<h2>Introducing Polaris v2</h2>

<p>The main purpose of Polaris v2 is to act as the root component for creating library projects around the Google Maps Android API v2. Although I originally developed it for creating commercial library providing animated clustering, I extracted the essence of it and kept some basic features. As a consequence, Polaris v2 aims to fix some of the most frustrating bugs of the original library and provide additional features.</p>

<p>For now, the code is mostly a wrapper but I&#8217;m releasing and open-sourcing the code so that the community can contribute to it and enhance it with some awesome new features and fixes. The current release includes just a few improvements (see the README file on GitHub for more information). Hopefully, some of the changes introduced in Polaris v2 will be backported into Google Maps Android API v2…</p>

<p><button class="download-button" onclick="window.location='https://github.com/cyrilmottier/Polaris2';"><span class="icon"></span><span class="title">Go to Polaris v2 GitHub page</span></button></p>

<h3>Using Polaris v2 in your projects</h3>

<p>Using Polaris v2 in your projects is quite simple. The API exposed by Polaris v2 is a super-set of what the original Google Maps Android API v2 exposes. As a result, you only need to switch all of the imports from the Google Maps Android API v2 (<code>com.google.android.gms.maps.*</code>) to Polaris v2 (<code>com.cyrilmottier.polaris2.maps.*</code>)</p>

<p>Finally you can start interacting with the underlying <code>GoogleMap</code> by calling <code>getPolarisMap()</code> (instead of <code>getMap()</code>) on your <code>SupportMapFragment</code>, <code>MapFragment</code> or <code>MapView</code>.</p>

<h2>Conclusion</h2>

<p>While the original project at the root of Polaris was more featureful, this release is the perfect way for developers to start adding some missing features to the original Google-provided mapping library. Today, Polaris v2 is just a wrapper around the Google Maps Android API v2 but could easily become a must-use library in the future. The project is just waiting for the community to help it grow.</p>

<hr />

<ol>
<li>Having a deprecated API doesn&#8217;t mean it is not working anymore for all existing applications. Google only decided to prevent people from generating new API keys. As a consequence, it is now impossible to create new applications using the Google Maps external library except if you are signing your application with a certificate you already have assigned a map API key to.</li>
</ol>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Redesigning cyrilmottier.com]]></title>
    <link href="http://cyrilmottier.com/2013/03/17/redesigning-cyrilmottier-dot-com/"/>
    <updated>2013-03-17T00:00:00+01:00</updated>
    <id>http://cyrilmottier.com/2013/03/17/redesigning-cyrilmottier-dot-com</id>
    <content type="html"><![CDATA[<p>Some of you may have noticed the maintenance page this weekend and the new face of this website. I&#8217;ve recently spent some time lately working on a complete redesign of my <em>cyrilmottier.com</em> domain. Here is a brief explanation of the motivations behind this redesign and a list of the main changes.</p>

<p>3 or 4 months ago I received an email from my host telling me they were dropping support of my old version of PHP (5.2). The version of Wordpress used for my <em>android.cyrilmottier.com</em> blog was so old it wasn&#8217;t supporting the PHP 5.4 and can&#8217;t even upgrade itself to a PHP 5.4 compliant version… Not being a server/backend guy, I decided to go for a complete redesign of both the guts and the look of <em>cyrilmottier.com</em>.</p>

<!-- More -->


<h2>No more PHP or MySQL</h2>

<p>The new version of the website is now using <a href="http://octopress.org/">Octopress</a>. Put simply, Octopress is a static website generator. Some of the main advantages of Otopress over Wordpress is it requires no SQL and no PHP, is responsive by default, deals perfectly with code snippets and relieve me from the pain of updating stuff I don&#8217;t know well. The only required piece of software Octopress needs is … Apache.</p>

<h2>Bringing simplicity</h2>

<p>The <em>cyrilmottier.com</em> domain was previously redirecting to a landing page made of tons of redirections to subdomains. Whilst it keeps clear sections in your website, it is hard to maintain and require time I don&#8217;t have (nor don&#8217;t want to spend on). As a result, I decided to go for something way more simple:</p>

<p><em>android.cyrilmottier.com</em> is now <em>cyrilmottier.com</em></p>

<p>In the process, I removed several subdomains and redirections I considered outdated and useless :</p>

<ul>
<li>My professional website</li>
<li>A prehistoric web page of my TI calculators apps</li>
<li>A old blog about my experience as an Erasmus student in Helsinki, Finland</li>
<li>A file manager I never ever used in 5 years</li>
</ul>


<h2>Holo-like theme</h2>

<p>Aside from removing a bunch of subdomains, I also created a theme from scratch. Once again, the idea behing the &#8216;Carrot&#8217; theme (don&#8217;t ask me why I decided to name it that way) is to make things simple, remove all distractful and useless info just like the Android Holo style does. I really think I managed to focus on the content by getting rid or minimalizing of all secondary information.</p>

<p>As a mobile UI/UX engineer and designer, I wanted to finally have a website that looked like what I would have done if my website was an Android app. You can now notice the new website is layout and density<sup>1</sup> responsive. As a result, it renders like magic on phones as well as tablets and desktop</p>

<h2>Do not hesitate to delegate</h2>

<p>Static websites don&#8217;t let you create dynamic algorithms… After all that&#8217;s what &#8220;static&#8221; means :). In order to keep features such as comments or search I used a plain old design pattern in computer science: delegation. Starting from now, comments are managed by <a href="http://disqus.com/">Disqus</a><sup>2</sup>, and search is done by the best search-engine in the world: <a href="http://google.com/">Google</a>.</p>

<h2>Miscellaneous</h2>

<p>Meaningless URLs are now over. When creating <em>android.cyrilmottier.com</em> I wanted to have short URLs to blog posts. The only purpose of this was to avoid the use of URL shorteners in social networks such as Twitter. However, using short URLs is far from being a great search engine optimization (SEO). Now that Twitter automatically shorten URLs, I&#8217;ve decided to switch to a more standard URL model:</p>

<pre><code>http://cyrilmottier.com/&lt;year&gt;/&lt;month&gt;/&lt;day&gt;/&lt;post-slug&gt;.html
</code></pre>

<p>The previous version of <em>android.cyrilmottier.com</em> was great for accessing new content but it wasn&#8217;t easy to browse the entire content of the blog. The new version now includes an &#8221;<a href="http://cyrilmottier.com/archives/">Archives</a>&#8221; page you can use to easily browse old posts.</p>

<h2>Conclusion</h2>

<p>I have spent quite a lot of time redesigning this domain but it was worth it. I learned tons of new stuff and I loved it. From a user point of view, everything should work fine seamlessly. However, as I said, I&#8217;m not a server administrator nor a backend guy so please <a href="http://cyrilmottier.com/about/">contact me</a> if you think something is wrong.</p>

<p>One of the redirection that scares me the most is the RSS feed (R.I.P. Google Reader …). The URL (from http://android.cyrilmottier.com/?feed=rss2 to <a href="http://cyrilmottier.com/atom.xml">http://cyrilmottier.com/atom.xml</a>) as well as the format (from RSS2 to ATOM) has changed so please make sure you RSS reader now points to <a href="http://cyrilmottier.com/atom.xml">http://cyrilmottier.com/atom.xml</a>.</p>

<hr />

<ol>
<li><p>I&#8217;m only talking about the theme. Indeed, images from posts are not density-responsive for one single reason: Octopress nor HTML correctly handles it.</p></li>
<li><p>Disqus comments are not activated nor migrated for now but I plan to do it as soon as possible.</p></li>
</ol>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Android App Launching Made Gorgeous]]></title>
    <link href="http://cyrilmottier.com/2013/01/23/android-app-launching-made-gorgeous/"/>
    <updated>2013-01-23T00:00:00+01:00</updated>
    <id>http://cyrilmottier.com/2013/01/23/android-app-launching-made-gorgeous</id>
    <content type="html"><![CDATA[<p>I will never say it out loud enough: always do overwhelm your users with your mobile apps. One of the most important way to mind-blow your users is to polish what is usually called <em>the first impression</em>. Indeed, <strong>the first impression is essential</strong> if you want to catch your users&#8217; attention. Contrary to what most people think, this process doesn&#8217;t start at the first launch of your application. It starts way before this when your potential users are looking at your app&#8217;s description, screenshots, icons, reviews, etc. in the Google Play Store.</p>

<p>This is only after the user has downloaded and launched the app you can start thinking of gradually engaging her/him, presenting an awesome user interface, displaying a minimalist setup, etc. A <a href="http://edition.cnn.com/2011/TECH/mobile/03/21/app.engagement.gahran/">recent study</a> measured the importance of the first impression and determined 26% of all apps downloaded are opened only once and then never used again. Only 26% were used 11 times or more. Of the remaining 48% of apps: 13% are opened only twice, 9% are opened only three times, and so on. Regarding such figures, there is no need to tell how crucial the polishing of the first impression is if you want your app to survive in the &#8220;apps jungle&#8221;.</p>

<!-- More -->


<p>In this post, I wanted to talk about the exact point in time at which the user taps on an app icon and opens it: the app launching animation. It happens I have recently played with tons of apps completely screwing this part of the user flow. In order to help developers polishing their applications, I thought about introducing the issue, explaining in details how Android deals with app launching and finally fixing all of the potential glitches.</p>

<h2>Introduction to the issue</h2>

<p>Let&#8217;s take a very simple example to understand what I am talking about here: the built-in Calculator application. This app is rather simple and made of a single screen letting users write formulas and get the result of it. From a feature point of view, the Calculator application does what it is intended to. Unfortunately it doesn&#8217;t respect the previously described &#8220;first impression is all&#8221; rule. You can have a closer look into the application startup looking at the screencast below.</p>

<div class="embed-video-container"><iframe src="http://www.youtube.com/embed/z7ZjreILHWw "></iframe></div>


<p>Have you seen something visually disturbing and/or jarring? I guess most of you haven&#8217;t noticed anything. Okay, I&#8217;ll be honest with you: the screencast example was intentionally hard. Here are some easier examples that respectively illustrate the launch of GigBeat and Facebook (the screen on the left is displayed prior the one on the right):</p>

<p><img class="center" src="http://cyrilmottier.com/media/2013/01/android-app-launching-made-gorgeaous/launching_gigbeat.png" title="Launching GigBeat" ></p>

<p><img class="center" src="http://cyrilmottier.com/media/2013/01/android-app-launching-made-gorgeaous/launching_facebook.png" title="Launching Facebook" ></p>

<p>I guess you now clearly understand the issue. GigBeat and especially Facebook display an intermediate screen that is completely at the opposite of the final screen on the right. When I&#8217;m saying &#8220;opposite&#8221; I thinking in terms of appearance and contrast. From a user standpoint, it looks like the application is launching a useless screen to initialize something prior actually launching the main screen.</p>

<p>On the other side, some applications like the built-in Contacts or Messages applications do the launching the right way. Here are the screen flow I have when starting the Contacts app on my dwarf-dedicated mobile phone&#8230;</p>

<p><img class="center" src="http://cyrilmottier.com/media/2013/01/android-app-launching-made-gorgeaous/launching_contacts.png" title="Launching Contacts" ></p>

<p>As you can see, the launching is perfect and gives the impression the app starts instantly by preloading a subset of the UI: the background color and the color of the <code>ActionBar</code>. Once the <code>Activity</code> is ready, the system fades out the temporary screen revealing the actual content of the screen. This technique makes app launching natural, continuous and smooth.</p>

<h2>Understanding Android app launching</h2>

<p>To fix this annoying issue we must first understand how Android deals with application launching. I believe giving all of the details would take a huge amount of time and I don&#8217;t think you need to understand every single detail of it so I will be as short as possible.</p>

<p>Starting a new application on Android basically consists on spawning a new process running an instance of a Dalvik VM. Once started, the Dalvik VM will, in turn, initialize a thread in which most of your code will be executed: the famous UI thread aka the main thread. Because initializing a process with a Dalvik VM from scratch may require a lot of time, Android relies on a trick called Zygote.</p>

<p>Curious people can go to the <a href="http://en.wikipedia.org/wiki/Zygote">Wikipedia page</a> of &#8220;Zygote&#8221; and will read the following abstract:</p>

<blockquote><p>A zygote is the initial cell formed when two gamete cells are joined by means of sexual reproduction. In multicellular organisms, it is the earliest developmental stage of the embryo. In single-celled organisms, the zygote divides to produce offspring, usually through meiosis.</p><footer><strong>Wikipedia</strong></footer></blockquote>


<p>It may looks like this definition has nothing to do this Android but it actually do! Android&#8217;s zygote has been named after the term defined above. The Zygote technique used in Android consists on creating an initial process at boot time with a Dalvik VM. This instance preloads a bunch of <a href="https://github.com/android/platform_frameworks_base/blob/android-4.2.1_r1/preloaded-classes">classes</a>, <a href="https://github.com/android/platform_frameworks_base/blob/android-4.2.1_r1/core/res/res/values/arrays.xml#L24">Drawables</a> and <a href="https://github.com/android/platform_frameworks_base/blob/android-4.2.1_r1/core/res/res/values/arrays.xml#L305">ColorStateLists</a> from the SDK and is used as the seed process from which all instances will be derived. Thanks to this technique, spawning a new ready-to-use process in Android simply requires forking the Zygote process which is way more efficient than creating a new process from scratch.</p>

<p>Zygote is an important optimization in Android because it minimizes the memory usage (on a copy-on-write basis) and reduces the amount of time required to start a new process. Although, application launching is blazingly fast, Android still require some time to load some data from your application (classes, resources, etc). In order to avoid hiccups and visually respond as soon as possible to the user interaction, the system displays a temporary window: the &#8220;starting window&#8221; also known as the &#8220;preview window&#8221;.</p>

<p>Pretty logically, starting windows are very basic windows that do almost nothing but displaying a minimalist UI. Starting windows are of type <a href="http://developer.android.com/reference/android/view/WindowManager.LayoutParams.html#TYPE_APPLICATION_STARTING"><code>TYPE_APPLICATION_STARTING</code></a>, are not focusable nor touchable and only displayed when the started <code>Activity</code> belongs to an application whose process is not started yet. As a result, starting windows are usually shown before actually displaying the Activity whose category is <code>android.intent.category.LAUNCHER</code>. However, due to the Android multitasking model, starting windows can also be displayed when restoring an Activity. In other words, do not consider starting windows as splash screens (you can read a <a href="http://www.cyrilmottier.com/2012/05/03/splash-screens-are-evil-dont-use-them/">previous post of mine</a> to understand my point of view on splash screens).</p>

<p>As described previously, the purpose of preview windows is to give the user immediate feedback that the app launched, but it also gives your app time to initialize itself. When your app is ready to run, the system removes the window and displays your app’s windows and views. As a result, none of your Java code is executed when the starting window is displayed. So how does Android know what my application will look like? In order to infer the design of the <code>Activity</code>, the framework uses the current <code>Activity</code> theme i.e. the theme of the <code>Activity</code> or the theme of the parent <code>Application</code> if no theme has been set to the <code>Activity</code>. Android inflates an empty but themed decor view (the base view hierarchy of an <code>Activity</code>), attaches it to a starting window and displays the latter on screen.</p>

<h2>The perfect preview window</h2>

<p>Now you have a clear overview of how Android deals with application launching, you can easily imagine what&#8217;s wrong this the Calculator, Gigbeat and Facebook apps. They are not correctly setting the theme. Even worse, all of these applications rely on the default theme <code>@android:style/Theme</code> or <code>@android:style/Theme.Holo.Light</code> and use their layout as the UI styling component. This is the reason why we see an intermediate design of the application (inferred from the theme) that is completely different from the second screen (the actual <code>Activity</code>).</p>

<p>So how can we fix the preview window issue? The first thing to do is obviously to create your own custom theme. As an example, we will investigate the built-in Calculator app because the code source is completely open source and available on <a href="https://github.com/android/platform_packages_apps_calculator">GitHub</a>. The Calculator app&#8217;s <code>AndroidManifest.xml</code> is given below:</p>

<figure class='code'><figcaption><span>AndroidManifest.xml  </span></figcaption>
 <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
</pre></td><td class='code'><pre><code class='xml'><span class='line'><span class="cp">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;</span>
</span><span class='line'><span class="nt">&lt;manifest</span> <span class="na">xmlns:android=</span><span class="s">&quot;http://schemas.android.com/apk/res/android&quot;</span>
</span><span class='line'>    <span class="na">package=</span><span class="s">&quot;com.android.calculator2&quot;</span><span class="nt">&gt;</span>
</span><span class='line'>
</span><span class='line'>    <span class="nt">&lt;original-package</span> <span class="na">android:name=</span><span class="s">&quot;com.android.calculator2&quot;</span> <span class="nt">/&gt;</span>
</span><span class='line'>
</span><span class='line'>    <span class="nt">&lt;application</span> <span class="na">android:label=</span><span class="s">&quot;@string/app_name&quot;</span> <span class="na">android:icon=</span><span class="s">&quot;@mipmap/ic_launcher_calculator&quot;</span><span class="nt">&gt;</span>
</span><span class='line'>        <span class="nt">&lt;activity</span>
</span><span class='line'>            <span class="na">android:name=</span><span class="s">&quot;Calculator&quot;</span>
</span><span class='line'>            <span class="na">android:theme=</span><span class="s">&quot;@android:style/Theme.Holo.NoActionBar&quot;</span>
</span><span class='line'>            <span class="na">android:windowSoftInputMode=</span><span class="s">&quot;stateAlwaysHidden&quot;</span><span class="nt">&gt;</span>
</span><span class='line'>            <span class="nt">&lt;intent-filter&gt;</span>
</span><span class='line'>                <span class="nt">&lt;action</span> <span class="na">android:name=</span><span class="s">&quot;android.intent.action.MAIN&quot;</span> <span class="nt">/&gt;</span>
</span><span class='line'>                <span class="nt">&lt;category</span> <span class="na">android:name=</span><span class="s">&quot;android.intent.category.DEFAULT&quot;</span> <span class="nt">/&gt;</span>
</span><span class='line'>                <span class="nt">&lt;category</span> <span class="na">android:name=</span><span class="s">&quot;android.intent.category.LAUNCHER&quot;</span> <span class="nt">/&gt;</span>
</span><span class='line'>                <span class="nt">&lt;category</span> <span class="na">android:name=</span><span class="s">&quot;android.intent.category.APP_CALCULATOR&quot;</span> <span class="nt">/&gt;</span>
</span><span class='line'>            <span class="nt">&lt;/intent-filter&gt;</span>
</span><span class='line'>        <span class="nt">&lt;/activity&gt;</span>
</span><span class='line'>    <span class="nt">&lt;/application&gt;</span>
</span><span class='line'><span class="nt">&lt;/manifest&gt;</span>
</span></code></pre></td></tr></table></div></figure>


<p>As you can see, the Calculator app is made of a single <code>Activity</code> using the <code>@android:style/Theme.Holo.NoActionBar</code> theme. In order to modify some theme attributes, we will simply create a custom theme using the theme currently used by the Calculator app as the parent:</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='xml'><span class='line'><span class="nt">&lt;style</span> <span class="na">name=</span><span class="s">&quot;Theme.Calculator&quot;</span> <span class="na">parent=</span><span class="s">&quot;@android:style/Theme.Holo.NoActionBar&quot;</span><span class="nt">&gt;</span>
</span><span class='line'>    <span class="c">&lt;!-- --&gt;</span>
</span><span class='line'><span class="nt">&lt;/style&gt;</span>
</span></code></pre></td></tr></table></div></figure>


<p>and use it in the <code>AndroidManifest.xml</code>:</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='xml'><span class='line'><span class="nt">&lt;activity</span>
</span><span class='line'>    <span class="na">android:name=</span><span class="s">&quot;Calculator&quot;</span>
</span><span class='line'>    <span class="na">android:theme=</span><span class="s">&quot;@style/Theme.Calculator&quot;</span>
</span><span class='line'>    <span class="na">android:windowSoftInputMode=</span><span class="s">&quot;stateAlwaysHidden&quot;</span><span class="nt">&gt;</span>
</span><span class='line'>    <span class="c">&lt;!-- --&gt;</span>
</span><span class='line'><span class="nt">&lt;/activity&gt;</span>
</span></code></pre></td></tr></table></div></figure>


<p>The first way to avoid the preview window artifacts is to completely disable the feature. Indeed, although starting windows are enable by default on Android, the SDK allows you to disable them simply by setting the <code>android:windowDisablePreview</code> attribute to <code>true</code> in your theme. Unfortunately, disabling preview windows also removes their main advantage: simulate an instant application launching. As a result, I highly suggest you not to disable starting windows unless really necessary (this is mostly only necessary in games based on Open GL ES).</p>

<p>The correct way to style a preview window is to make sure it best matches your <code>Activity</code>. In the case of the Calculator app, we will simply modify the background of the window to switch from the default gradient to a solid black color:</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='xml'><span class='line'><span class="nt">&lt;style</span> <span class="na">name=</span><span class="s">&quot;Theme.Calculator&quot;</span> <span class="na">parent=</span><span class="s">&quot;@android:style/Theme.Holo.NoActionBar&quot;</span><span class="nt">&gt;</span>
</span><span class='line'>    <span class="nt">&lt;item</span> <span class="na">name=</span><span class="s">&quot;android:windowBackground&quot;</span><span class="nt">&gt;</span>@android:color/black<span class="nt">&lt;/item&gt;</span>
</span><span class='line'><span class="nt">&lt;/style&gt;</span>
</span></code></pre></td></tr></table></div></figure>


<p>You can now kill and restart the Calculator app and notice that the preview animation is now in accordance with the <code>Activity</code>. The job was pretty simple, wasn&#8217;t it? To help Google improving the Calculator app, I have already submitted this patch to the <a href="https://android-review.googlesource.com/#/c/50282/">Android review system</a>.</p>

<p>Thanks, to this tiny change in the code we now have a Calculator application with a nice preview animation. However, even if the result is visually correct, you can still enhance the rendering performance of the app. Indeed, let&#8217;s look for some potential overdraw. Enabling &#8220;Show GPU overdraw&#8221; in the developer options gives us the following screenshot:</p>

<p><img class="center" src="http://cyrilmottier.com/media/2013/01/android-app-launching-made-gorgeaous/calculator_overdraw.png" title="Calculator overdraw" ></p>

<p>As a reminder, blue means an overdraw of 1x, green 2x, light red 3x, etc. If you don&#8217;t know what overdraw is or how to measure and minimize it, please read the excellent documentation/reference on <a href="http://www.curious-creature.org/docs/android-performance-case-study-1.html">Romain Guy&#8217;s blog</a>. Most of the screen being blue or green it basically means we are rendering too much layers on some parts of the UI. A rapid investigation on the layouts explains the issue. Indeed, all of the <code>main.xml</code> layout variants used a the content view of our main Activity are as follow:</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
</pre></td><td class='code'><pre><code class='xml'><span class='line'><span class="cp">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;</span>
</span><span class='line'><span class="nt">&lt;LinearLayout</span> <span class="na">xmlns:android=</span><span class="s">&quot;http://schemas.android.com/apk/res/android&quot;</span>
</span><span class='line'>    <span class="na">android:orientation=</span><span class="s">&quot;vertical&quot;</span>
</span><span class='line'>    <span class="na">android:layout_width=</span><span class="s">&quot;match_parent&quot;</span>
</span><span class='line'>    <span class="na">android:layout_height=</span><span class="s">&quot;match_parent&quot;</span>
</span><span class='line'>    <span class="na">android:background=</span><span class="s">&quot;#ff000000&quot;</span><span class="nt">&gt;</span>
</span><span class='line'>
</span><span class='line'>    <span class="c">&lt;!-- --&gt;</span>
</span><span class='line'>
</span><span class='line'><span class="nt">&lt;/LinearLayout&gt;</span>
</span></code></pre></td></tr></table></div></figure>


<p>It is now clear that the overdraw comes from the fully opaque black color drawn by the root <code>LinearLayout</code> as the background. While it was previously used to inefficiently hide the default gradient window background, it is now useless and can be removed. Here again, I have submitted a <a href="https://android-review.googlesource.com/#/c/50283/">patch</a>.</p>

<p><img class="center" src="http://cyrilmottier.com/media/2013/01/android-app-launching-made-gorgeaous/calculator_no_overdraw.png" title="Calculator no overdraw" ></p>

<p>Moving the background of your screens from the root of your layout to the background of your window is generally a good fix. Nevertheless, in some cases, the background of your window cannot be used as the general background and styling at the &#8220;layout level&#8221; is still required. In such as case, the trick consists on keeping a theme so that the system can infer the preview window of your app and change the background of the final window back to <code>null</code> in your <code>Activity</code>&#8217;s <code>onCreate()</code>:</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="nd">@Override</span>
</span><span class='line'><span class="kd">public</span> <span class="kt">void</span> <span class="nf">onCreate</span><span class="o">(</span><span class="n">Bundle</span> <span class="n">savedInstanceState</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>    <span class="kd">super</span><span class="o">.</span><span class="na">onCreate</span><span class="o">(</span><span class="n">savedInstanceState</span><span class="o">);</span>
</span><span class='line'>    <span class="n">getWindow</span><span class="o">().</span><span class="na">setBackgroundDrawable</span><span class="o">(</span><span class="kc">null</span><span class="o">);</span>
</span><span class='line'>    <span class="n">setContentView</span><span class="o">(</span><span class="n">R</span><span class="o">.</span><span class="na">layout</span><span class="o">.</span><span class="na">main</span><span class="o">);</span>
</span><span class='line'><span class="o">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>To conclude, you may still want to understand how the Contacts app displays a preview of the <code>ActionBar</code>. The answer to this question has been given above: the preview window is made of a themed empty decor view. The decor view is the hierarchy where lies the <code>ActionBar</code>. As a consequence, always style the <code>ActionBar</code> directly in your theme (see the <a href="http://developer.android.com/guide/topics/ui/actionbar.html#Style">documentation</a> for more information) to have a nice and smooth application launching.</p>

<h2>Conclusion</h2>

<p>Starting windows may not be visible for a huge amount of time, they are shown at a crucial moment in the lifetime of your application. Hence, ensuring they correctly display a subset of your <code>Activity</code> UIs is vital. Polishing preview windows make your app fancier and smoother by removing all of the un-needed extra layers.</p>

<p>To finish, starting windows are great but must not be considered or used as splash screens. Do not consider preview windows as an excuse for publishing slow applications. They are clearly not intended to do that. They&#8217;re here to fake a fast launching while the system loads up your application process and make your app launch as graphically pleasant as possible to your users.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Back To Top: Android vs. iOS]]></title>
    <link href="http://cyrilmottier.com/2013/01/09/back-to-top-android-vs-ios/"/>
    <updated>2013-01-09T00:00:00+01:00</updated>
    <id>http://cyrilmottier.com/2013/01/09/back-to-top-android-vs-ios</id>
    <content type="html"><![CDATA[<p>I generally don&#8217;t talk a lot about iOS on this blog. I&#8217;ll be honest with you, it is not because I consider iOS as an evil platform. As an extremely curious person, I just hate that iOS is a closed-source platform. I would really love to look at the implementation of some parts of the system or framework sometimes. However, Apple&#8217;s iOS remains an incredibly awesome mobile platform to develop for and to use. I assure you the APIs are gorgeous. From the UI point of view, iOS also has tons of exciting features, one of which is the &#8220;tap status bar to scroll to top&#8221;.</p>

<p>The purpose of this article is to give you a clear explanation about the control offered by Android over scroll containers. I have intentionally used iOS to do the comparison because the philosophy behind scroll containers in iOS is relatively different than Android.</p>

<!-- More -->


<h2>Once upon a time, there was iOS</h2>

<p>Just like every mobile OS, iOS runs on devices with a rather limited display surface. In order to display as much content as possible, applications can use scroll containers such as <code>UIScrollView</code> (<code>ScrollView</code>-equivalent), <code>UITableView</code> (<code>ListView</code>-equivalent), <code>UIWebView</code> (<code>WebView</code>-equivalent), etc. These containers let you scroll the content using gestures now considered elementary: the swipe gestures. When looking at your content, you may want to be brought back to the top of that content. While this is not something obvious on Android, the feature is available via a consistent and nice gesture on iOS: you simply have to tap the status bar. When doing so, the system will basically look for a <code>UIScrollView</code> in your app&#8217;s view hierarchy and scroll it back to the top if allowed to (i.e. if the <code>UIScrollView</code> has the <code>scrollToTop</code> property set to <code>YES</code> and the delegate allows it)).</p>

<p><img class="center" src="http://cyrilmottier.com/media/2013/01/back-to-top-android-vs-ios/tap_scroll_bar_ios.png" title="Tap Status Bar iOS" ></p>

<p>Some might criticize the lack of discoverability of this feature and I totally agree. This is clearly something that is not natural to the user. It will generally be discovered by mistake. Once spotted, this is a power-feature reserved to power-users. However, always keep in mind that it is important to satisfy these guys : they generally push feedbacks and review your application way more rapidly than &#8220;regular&#8221; users.</p>

<p>So what about Android? I guess you are not aware of such a gesture on your devices. The reason is pretty obvious: Android doesn&#8217;t offer such a system-wide/global gesture! I don&#8217;t know the exact reason of this &#8220;lack&#8221;. Google considering it as not required? Apple having patented the gesture? The only thing I&#8217;m sure of is implementing <em>scroll-to-top</em> is almost impossible on Android because scroll containers in the SDK are a complete mess.</p>

<h2>The Android scroll issue</h2>

<p>This is not a mystery to anyone, globally speaking, I do love Android. However, I&#8217;m also pragmatic enough to notice some parts of the platform are not well designed or badly implemented. The scrollable containers APIs belong in this category. You don&#8217;t need to be an API designer to notice they are extremely confusing regarding scroll-related capabilities.</p>

<p>By default, the framework provides basic support for <code>View</code>s that wish to internally scroll their content and draw scrollbars. For instance, you can <a href="http://developer.android.com/reference/android/view/View.html#scrollTo(int,%20int"><code>scrollTo(int, int)</code></a>). While this works perfectly with <code>ScrollView</code> it doesn&#8217;t with <code>ListView</code> nor <code>WebView</code> nor my beloved <code>MapView</code>. Another example of this confusion is the <a href="http://developer.android.com/reference/android/view/ViewTreeObserver.OnScrollChangedListener.html"><code>ViewTreeObserver.OnScrollListener</code></a> that works perfectly on all kinds of scrollable content but doesn&#8217;t provide you with the container that scrolled. Once again, Google Maps Android API v2 <code>MapView</code> is an exception and won&#8217;t fire the callback when being scrolled or zoomed. Finally, there are some inconsistencies. For instance, <a href="http://developer.android.com/reference/android/widget/AbsListView.OnScrollListener.html"><code>AbsListView.OnScrollListener</code></a> lets you listen to <code>AbsListView</code> scrolls but there is no <code>View.OnScrollListener</code> counterpart. If you want to listen to scrolls at the <code>View</code> level, you&#8217;ll need to override the <code>onScrollChanged(int, int, int, int)</code> method.</p>

<p>Put simply, Android offers several scroll containers, but no consistent way to formalize scrolling and notify the developer. Even if you can determine if a <code>View</code> is a scroll container by using <code>View.setScrollContainer(boolean)</code><sup>1</sup>, there is absolutely no way to develop a unified algorithm that would scroll your container to its top with a single call to <code>View.scrollTo(0, 0)</code>.</p>

<p>On the other side, iOS simplified the problem by making sure all scrollable containers are unified via a <code>UIScrollView</code> - the base class containing the &#8220;scrolling&#8221; and &#8220;scroll-to-top&#8221; implementation. The framework offers a bunch of scrollable containers: <code>UITextView</code>, <code>UITableView</code>, <code>UIWebView</code>, <code>MKMapView</code>, etc. that all inherit or encapsulate a <code>UIScrollView</code>. By factorizing the scrolling behavior, iOS ensure that the scrolling physics (velocity, friction, bouncing, etc.) are consistent throughout iOS apps and guarantee all scrollable content can be scrolled back to the top.</p>

<p>So, is Android a crappy framework? Well I don&#8217;t think so. The API mess is probably difficult to apprehend - especially for new developers - but this is also what makes Android&#8217;s <code>ListView</code> so powerful compared to iOS <code>UITableView</code> when displaying items with variable heights for instance. <code>UITableView</code> relying on <code>UIScrollView</code>, it has to know <em>all</em> of the list&#8217;s items. On the other hand, Android&#8217;s <code>ListView</code> only requires the height of the <em>visible items</em>.</p>

<p>To sum up, iOS&#8217; <code>UIScrollView</code>-based API simplifies development and enforces UIs consistency. On the other hand Android&#8217;s messy API requires more attention from the developer, but can kick iOS&#8217; ass in some special cases.</p>

<p>It appears that not being able to implement a global <em>scroll-to-top</em> gesture is not really a problem. Indeed, most issues can be solved at the application level using components that are generally way more specific to the data displayed by your app. It obviously requires more work than relying on the default system&#8217;s behavior and doesn&#8217;t provide a consistent and coherent gesture throughout the platform. But, why would I need a <em>scroll-to-top</em> gesture in the Contacts iOS app if it also offers an index on the right?</p>

<h2>Back to top on Android: the ethereal problem</h2>

<p>Ultimately, the scroll content issue Android suffers from at the API level has no impact on the UI. If you are complaining about the feature missing, you should probably notify the developer his/her app needs some enhancements. The framework includes out-of-the-box workarounds and components that prevent the user from flinging for eternity trying to reach the top of your scrollable container:</p>

<ul>
<li><p><strong>Avoid long scrollable content at all cost</strong>: The best way to avoid scrolling pains is to avoid large scroll containers. In general, avoid long <code>ListView</code>s at all costs. Failing to do so will drown the important information in the middle of an almost un-findable/searchable list.</p></li>
<li><p><strong>Enable fly-wheel</strong>: Since API 11, Android offers a fly-wheel mode in <code>Scroller</code> and <code>OverScroller</code> (the base components used to implement scrolling behaviors). When activated, successive fling motions will keep on increasing scroll speed. As a result, the user can rapidly increase the speed of the scroll containers to go back to an edge. Prior API 11, the velocity was generally topped by <code>ViewConfiguration.getScaledMaximumFlingVelocity()</code>.</p></li>
<li><p><strong>Enable fast scroll whenever possible</strong>: <code>AbsListView</code> can be scrolled extremely rapidly with a call to <code>setFastScrollEnabled(true)</code>. Used in addition to <code>SectionIndexer</code> this makes navigation though an ordered list of grouped items extremely pleasant and powerful. While fast scroll can be used with all kind of data, it is generally only appropriate with ordered and grouped data. The Contacts app for instance uses it brilliantly.</p></li>
</ul>


<p>Contrary to iOS, you generally don&#8217;t need to implement a <em>tap-on-something-to-scroll-to-top</em> behavior on Android. However, there is one case where the previously described techniques don&#8217;t fit: the timeline. Most of the time, a timeline is a vertically scrolling area displaying events sorted by creation date. The closer you are to the top, the more recent the data are.</p>

<p>The best - or should I say the worst - example of this is Google+. Google+ for Android displays a timeline with all of the posts from your circles&#8217; members. Reading posts is usually done from top to bottom which basically means from the most recent to the oldest ones. Sometimes you want to scroll way back to the top to see if there is a new post. That sounds easy, right? Well good luck with that :s. Here are the two options I found:</p>

<ul>
<li><p><strong>Start flinging like crazy back to top</strong>. Unfortunately, it looks like they completely disabled the fly-wheel mode which makes scrolling a pain in the ass.</p></li>
<li><p><strong>Exit the timeline and reopens it</strong> I don&#8217;t think I need to describe this technique. You&#8217;ll all have understood it is purely non-logical and hence not user-friendly.</p></li>
</ul>


<p>In this rare case I think, the <em>tap-on-something-to-scroll-to-top</em> is the correct option.</p>

<h2>Tweaking the Quick Return pattern</h2>

<p>Android not letting us listen to taps on the status bar, the only option is to use a clickable area in your application: a tab, a regular <code>TextView</code>, etc. A few months ago, Roman Nurik and Nick Butcher described and formalized a pattern they called &#8220;Quick Return&#8221;. I highly suggest you take a look at <a href="https://plus.google.com/u/0/113735310430199015092/posts/1Sb549FvpJt">Roman&#8217;s G+ post</a> or at <a href="http://www.androiduipatterns.com/2012/08/an-emerging-ui-pattern-quick-return.html">Juhani Lehtimäki&#8217;s blog article</a> to learn more about this emerging UI pattern.</p>

<p>While this pattern is great to make some important controls of your UI reappear, it doesn&#8217;t exactly fit the <em>scroll-to-top</em> gesture. Indeed, using the Quick Return pattern in this case would involve having a button appearing once the user starts scrolling up. This could be really annoying or frustrating.</p>

<p>In order to fix the issue, I&#8217;ve decided to tweak the pattern. Because users usually scroll up rapidly when going back to top, I thought it was only necessary to display the button when the velocity is higher than a given threshold. The rest of the article will focus on implementing such a widget but you can download an APK of the project (API 12 min) here:</p>

<p><button class="download-button" onclick="window.location='/media/2013/01/back-to-top-android-vs-ios/ScrollToTop.apk';"><span class="icon"></span><span class="title">Download sample APK</span></button></p>

<p><em><strong>Note</strong>: The code given below is a proof of concept. I have never used it in production and I already know it may behave weirdly (crash ?) when the underlying <code>Adapter</code>&#8217;s data is modified. Please make sure to understand what you are doing when using/modifying the snippet of code below.</em></p>

<h2>Scrolling to the top</h2>

<p>Going back to the top in a <code>ListView</code> is rather complicated. Here are some of the methods you can use:</p>

<ul>
<li><p><code>setSelection(int)</code>: This method works like a charm by selecting the given position. As a result <code>setSelection(0)</code>can bring us back to the top. Unfortunately it has two mains disadvantages: the transition is not animated at all which is visually jarring and modifying the selected position in the middle of a fling animation doesn&#8217;t stop the animation.</p></li>
<li><p><code>smoothScrollToPosition(int)</code>: Available since API 8, this methods sounds like a good match. Unfortunately, I have never made it work in my projects. I&#8217;ve found a lot of complains about it on the web and stopped using it.</p></li>
<li><p><code>smoothScrollToPositionFromTop(int, int)</code>: Available since API 11, this method is a low-level counterpart of the previous method. The only different is it seems to work. Put simply, Android does not offer per-pixel scrolling in <code>ListView</code> prior API 11.</p></li>
</ul>


<p>As you may have noticed, scrolling a <code>ListView</code> to its top in an animated way is rather difficult. Fortunately, some people in the Android team already did the job of creating an extension of <code>ListView</code>: the <code>AutoScrollListView</code>. Available in the <a href="https://github.com/android/platform_packages_apps_contacts/blob/master/src/com/android/contacts/widget/AutoScrollListView.java">Contacts app</a>, the <code>AutoScrollListView</code> can be asked to scroll (smoothly or otherwise) to a position.</p>

<h3>Measuring the velocity of a ListView</h3>

<p>ListView doesn&#8217;t provide a method to get its current velocity. As a consequence, the only thing we can do is computing it. Measuring the velocity of a <code>ListView</code> is rather difficult. Indeed, measuring a velocity is usually done using the simple formula: <em>v = &#916;d/&#916;t</em>. Getting <em>&#916;t</em> is pretty elementary but that&#8217;s not the case for <em>&#916;d</em> on Android.</p>

<p>Contrary to iOS&#8217;s <code>UITableView</code>, <code>ListView</code> doesn&#8217;t give you a &#8220;current scroll Y&#8221;. The &#8220;measure items on demand&#8221; strategy used by <code>ListView</code> makes it hard to scroll at the pixel level and to measure its physical property (such as the velocity). However, even if you can&#8217;t determine the exact velocity of a <code>ListView</code>, you can approximate the value using an approximation of the travelled distance. Here is the approach I created:</p>

<ul>
<li><p>At each scroll step <em>n</em>, keep the values of the <code>View</code> top <em>d<sub>n</sub></em> and the position <em>p<sub>n</sub></em> of the underlying data in the <code>Adapter</code> of the <code>ListView</code>&#8217;s child at index 0</p></li>
<li><p>If the item&#8217;s at position <em>p<sub>n+1</sub></em> is still visible then <em>&#916;d</em> is equal to the difference between the new top and the previous top: <em>d<sub>n+1</sub> - d<sub>n</sub></em>.</p></li>
<li><p>If the position is not visible anymore, then we can approximate the distance by computing the average height of the visible items in the <code>ListView</code> and multiply this value by the difference between the current position and the old position.</p></li>
</ul>


<p>The schema shows a list being scrolled up (i.e. the user is swiping from top to bottom). As explained previously, <em>&#916;d = d<sub>2</sub> - d<sub>1</sub></em>.</p>

<p><img class="center" src="http://cyrilmottier.com/media/2013/01/back-to-top-android-vs-ios/velocity_case_1.png" title="Velocity Case 1" ></p>

<p>While the technique works great and scrolling up, you may easily fall into a case where <em>d<sub>2</sub></em> is not measurable because the view at index 0 in the previous measurement has been recycled. The trick consists of using the exact same technique twice: once for the child at index 0 (mostly used when scrolling up) and also for the child at index <code>getChildCount() - 1</code> (mostly used when scrolling down).</p>

<p><img class="center" src="http://cyrilmottier.com/media/2013/01/back-to-top-android-vs-ios/velocity_case_2.png" title="Velocity Case 2" ></p>

<p>Finally, if you are scrolling up or down extremely rapidly you may have none of the children on screen from one step to another. In this case we will use the &#8220;position is not visible anymore&#8221; approximation. This case can also occur if your application freezes the UI thread.</p>

<p>The code is provided below and consists on extending <code>AutoScrollListView</code> to approximate the velocity of the <code>ListView</code> and notifying an optional client:</p>

<figure class='code'><figcaption><span>VelocityListView.java </span></figcaption>
 <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
<span class='line-number'>56</span>
<span class='line-number'>57</span>
<span class='line-number'>58</span>
<span class='line-number'>59</span>
<span class='line-number'>60</span>
<span class='line-number'>61</span>
<span class='line-number'>62</span>
<span class='line-number'>63</span>
<span class='line-number'>64</span>
<span class='line-number'>65</span>
<span class='line-number'>66</span>
<span class='line-number'>67</span>
<span class='line-number'>68</span>
<span class='line-number'>69</span>
<span class='line-number'>70</span>
<span class='line-number'>71</span>
<span class='line-number'>72</span>
<span class='line-number'>73</span>
<span class='line-number'>74</span>
<span class='line-number'>75</span>
<span class='line-number'>76</span>
<span class='line-number'>77</span>
<span class='line-number'>78</span>
<span class='line-number'>79</span>
<span class='line-number'>80</span>
<span class='line-number'>81</span>
<span class='line-number'>82</span>
<span class='line-number'>83</span>
<span class='line-number'>84</span>
<span class='line-number'>85</span>
<span class='line-number'>86</span>
<span class='line-number'>87</span>
<span class='line-number'>88</span>
<span class='line-number'>89</span>
<span class='line-number'>90</span>
<span class='line-number'>91</span>
<span class='line-number'>92</span>
<span class='line-number'>93</span>
<span class='line-number'>94</span>
<span class='line-number'>95</span>
<span class='line-number'>96</span>
<span class='line-number'>97</span>
<span class='line-number'>98</span>
<span class='line-number'>99</span>
<span class='line-number'>100</span>
<span class='line-number'>101</span>
<span class='line-number'>102</span>
<span class='line-number'>103</span>
<span class='line-number'>104</span>
<span class='line-number'>105</span>
<span class='line-number'>106</span>
<span class='line-number'>107</span>
<span class='line-number'>108</span>
<span class='line-number'>109</span>
<span class='line-number'>110</span>
<span class='line-number'>111</span>
<span class='line-number'>112</span>
<span class='line-number'>113</span>
<span class='line-number'>114</span>
<span class='line-number'>115</span>
<span class='line-number'>116</span>
<span class='line-number'>117</span>
<span class='line-number'>118</span>
<span class='line-number'>119</span>
<span class='line-number'>120</span>
<span class='line-number'>121</span>
<span class='line-number'>122</span>
<span class='line-number'>123</span>
<span class='line-number'>124</span>
<span class='line-number'>125</span>
<span class='line-number'>126</span>
<span class='line-number'>127</span>
<span class='line-number'>128</span>
<span class='line-number'>129</span>
<span class='line-number'>130</span>
<span class='line-number'>131</span>
<span class='line-number'>132</span>
<span class='line-number'>133</span>
<span class='line-number'>134</span>
<span class='line-number'>135</span>
<span class='line-number'>136</span>
<span class='line-number'>137</span>
<span class='line-number'>138</span>
<span class='line-number'>139</span>
<span class='line-number'>140</span>
<span class='line-number'>141</span>
<span class='line-number'>142</span>
<span class='line-number'>143</span>
<span class='line-number'>144</span>
<span class='line-number'>145</span>
<span class='line-number'>146</span>
<span class='line-number'>147</span>
<span class='line-number'>148</span>
<span class='line-number'>149</span>
<span class='line-number'>150</span>
<span class='line-number'>151</span>
<span class='line-number'>152</span>
<span class='line-number'>153</span>
<span class='line-number'>154</span>
<span class='line-number'>155</span>
<span class='line-number'>156</span>
<span class='line-number'>157</span>
<span class='line-number'>158</span>
<span class='line-number'>159</span>
<span class='line-number'>160</span>
<span class='line-number'>161</span>
<span class='line-number'>162</span>
<span class='line-number'>163</span>
<span class='line-number'>164</span>
<span class='line-number'>165</span>
<span class='line-number'>166</span>
<span class='line-number'>167</span>
<span class='line-number'>168</span>
<span class='line-number'>169</span>
<span class='line-number'>170</span>
<span class='line-number'>171</span>
<span class='line-number'>172</span>
<span class='line-number'>173</span>
<span class='line-number'>174</span>
<span class='line-number'>175</span>
<span class='line-number'>176</span>
<span class='line-number'>177</span>
<span class='line-number'>178</span>
<span class='line-number'>179</span>
<span class='line-number'>180</span>
<span class='line-number'>181</span>
<span class='line-number'>182</span>
<span class='line-number'>183</span>
<span class='line-number'>184</span>
<span class='line-number'>185</span>
<span class='line-number'>186</span>
<span class='line-number'>187</span>
<span class='line-number'>188</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="kn">package</span> <span class="n">com</span><span class="o">.</span><span class="na">cyrilmottier</span><span class="o">.</span><span class="na">android</span><span class="o">.</span><span class="na">scrolltotop</span><span class="o">.</span><span class="na">widget</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.content.Context</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.util.AttributeSet</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.view.animation.AnimationUtils</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.widget.AbsListView</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.widget.ListView</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'><span class="cm">/**</span>
</span><span class='line'><span class="cm"> * An extension of the framework&#39;s {@link ListView} that can determine an</span>
</span><span class='line'><span class="cm"> * approximate value of its current velocity on the Y-axis.</span>
</span><span class='line'><span class="cm"> * </span>
</span><span class='line'><span class="cm"> * @author Cyril Mottier</span>
</span><span class='line'><span class="cm"> */</span>
</span><span class='line'><span class="kd">public</span> <span class="kd">class</span> <span class="nc">VelocityListView</span> <span class="kd">extends</span> <span class="n">AutoScrollListView</span> <span class="o">{</span>
</span><span class='line'>
</span><span class='line'>    <span class="cm">/**</span>
</span><span class='line'><span class="cm">     * A callback to be notified the velocity has changed.</span>
</span><span class='line'><span class="cm">     * </span>
</span><span class='line'><span class="cm">     * @author Cyril Mottier</span>
</span><span class='line'><span class="cm">     */</span>
</span><span class='line'>    <span class="kd">public</span> <span class="kd">interface</span> <span class="nc">OnVelocityListViewListener</span> <span class="o">{</span>
</span><span class='line'>        <span class="kt">void</span> <span class="nf">onVelocityChanged</span><span class="o">(</span><span class="kt">int</span> <span class="n">velocity</span><span class="o">);</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="kt">long</span> <span class="n">INVALID_TIME</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'>    <span class="cm">/**</span>
</span><span class='line'><span class="cm">     * This value is really necessary to avoid weird velocity values. Indeed, in</span>
</span><span class='line'><span class="cm">     * fly-wheel mode, onScroll is called twice per-frame which results in</span>
</span><span class='line'><span class="cm">     * having a delta divided by a value close to zero. onScroll is usually</span>
</span><span class='line'><span class="cm">     * being called 60 times per seconds (i.e. every 16ms) so 10ms is a good</span>
</span><span class='line'><span class="cm">     * threshold.</span>
</span><span class='line'><span class="cm">     */</span>
</span><span class='line'>    <span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="kt">long</span> <span class="n">MINIMUM_TIME_DELTA</span> <span class="o">=</span> <span class="mi">10L</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">private</span> <span class="kd">final</span> <span class="n">ForwardingOnScrollListener</span> <span class="n">mForwardingOnScrollListener</span> <span class="o">=</span> <span class="k">new</span> <span class="n">ForwardingOnScrollListener</span><span class="o">();</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">private</span> <span class="n">OnVelocityListViewListener</span> <span class="n">mOnVelocityListViewListener</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">private</span> <span class="kt">long</span> <span class="n">mTime</span> <span class="o">=</span> <span class="n">INVALID_TIME</span><span class="o">;</span>
</span><span class='line'>    <span class="kd">private</span> <span class="kt">int</span> <span class="n">mVelocity</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">private</span> <span class="kt">int</span> <span class="n">mFirstVisiblePosition</span><span class="o">;</span>
</span><span class='line'>    <span class="kd">private</span> <span class="kt">int</span> <span class="n">mFirstVisibleViewTop</span><span class="o">;</span>
</span><span class='line'>    <span class="kd">private</span> <span class="kt">int</span> <span class="n">mLastVisiblePosition</span><span class="o">;</span>
</span><span class='line'>    <span class="kd">private</span> <span class="kt">int</span> <span class="n">mLastVisibleViewTop</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">public</span> <span class="nf">VelocityListView</span><span class="o">(</span><span class="n">Context</span> <span class="n">context</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="kd">super</span><span class="o">(</span><span class="n">context</span><span class="o">);</span>
</span><span class='line'>        <span class="n">init</span><span class="o">();</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">public</span> <span class="nf">VelocityListView</span><span class="o">(</span><span class="n">Context</span> <span class="n">context</span><span class="o">,</span> <span class="n">AttributeSet</span> <span class="n">attrs</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="kd">super</span><span class="o">(</span><span class="n">context</span><span class="o">,</span> <span class="n">attrs</span><span class="o">);</span>
</span><span class='line'>        <span class="n">init</span><span class="o">();</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">public</span> <span class="nf">VelocityListView</span><span class="o">(</span><span class="n">Context</span> <span class="n">context</span><span class="o">,</span> <span class="n">AttributeSet</span> <span class="n">attrs</span><span class="o">,</span> <span class="kt">int</span> <span class="n">defStyle</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="kd">super</span><span class="o">(</span><span class="n">context</span><span class="o">,</span> <span class="n">attrs</span><span class="o">,</span> <span class="n">defStyle</span><span class="o">);</span>
</span><span class='line'>        <span class="n">init</span><span class="o">();</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">private</span> <span class="kt">void</span> <span class="nf">init</span><span class="o">()</span> <span class="o">{</span>
</span><span class='line'>        <span class="kd">super</span><span class="o">.</span><span class="na">setOnScrollListener</span><span class="o">(</span><span class="n">mForwardingOnScrollListener</span><span class="o">);</span>
</span><span class='line'>        <span class="n">mForwardingOnScrollListener</span><span class="o">.</span><span class="na">selfListener</span> <span class="o">=</span> <span class="n">mOnScrollListener</span><span class="o">;</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="nd">@Override</span>
</span><span class='line'>    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">setOnScrollListener</span><span class="o">(</span><span class="n">OnScrollListener</span> <span class="n">l</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="n">mForwardingOnScrollListener</span><span class="o">.</span><span class="na">clientListener</span> <span class="o">=</span> <span class="n">l</span><span class="o">;</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">setOnVelocityListener</span><span class="o">(</span><span class="n">OnVelocityListViewListener</span> <span class="n">l</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="n">mOnVelocityListViewListener</span> <span class="o">=</span> <span class="n">l</span><span class="o">;</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="cm">/**</span>
</span><span class='line'><span class="cm">     * Return an approximative value of the ListView&#39;s current velocity on the</span>
</span><span class='line'><span class="cm">     * Y-axis. A negative value indicates the ListView is currently being</span>
</span><span class='line'><span class="cm">     * scrolled towards the bottom (i.e items are moving from bottom to top)</span>
</span><span class='line'><span class="cm">     * while a positive value indicates it is currently being scrolled towards</span>
</span><span class='line'><span class="cm">     * the top (i.e. items are moving from top to bottom).</span>
</span><span class='line'><span class="cm">     * </span>
</span><span class='line'><span class="cm">     * @return An approximative value of the ListView&#39;s velocity on the Y-axis</span>
</span><span class='line'><span class="cm">     */</span>
</span><span class='line'>    <span class="kd">public</span> <span class="kt">int</span> <span class="nf">getVelocity</span><span class="o">()</span> <span class="o">{</span>
</span><span class='line'>        <span class="k">return</span> <span class="n">mVelocity</span><span class="o">;</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">private</span> <span class="kt">void</span> <span class="nf">setVelocity</span><span class="o">(</span><span class="kt">int</span> <span class="n">velocity</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="k">if</span> <span class="o">(</span><span class="n">mVelocity</span> <span class="o">!=</span> <span class="n">velocity</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>            <span class="n">mVelocity</span> <span class="o">=</span> <span class="n">velocity</span><span class="o">;</span>
</span><span class='line'>            <span class="k">if</span> <span class="o">(</span><span class="n">mOnVelocityListViewListener</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>                <span class="n">mOnVelocityListViewListener</span><span class="o">.</span><span class="na">onVelocityChanged</span><span class="o">(</span><span class="n">velocity</span><span class="o">);</span>
</span><span class='line'>            <span class="o">}</span>
</span><span class='line'>        <span class="o">}</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="cm">/**</span>
</span><span class='line'><span class="cm">     * @author Cyril Mottier</span>
</span><span class='line'><span class="cm">     */</span>
</span><span class='line'>    <span class="kd">private</span> <span class="kd">static</span> <span class="kd">class</span> <span class="nc">ForwardingOnScrollListener</span> <span class="kd">implements</span> <span class="n">OnScrollListener</span> <span class="o">{</span>
</span><span class='line'>
</span><span class='line'>        <span class="kd">private</span> <span class="n">OnScrollListener</span> <span class="n">selfListener</span><span class="o">;</span>
</span><span class='line'>        <span class="kd">private</span> <span class="n">OnScrollListener</span> <span class="n">clientListener</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'>        <span class="nd">@Override</span>
</span><span class='line'>        <span class="kd">public</span> <span class="kt">void</span> <span class="nf">onScroll</span><span class="o">(</span><span class="n">AbsListView</span> <span class="n">view</span><span class="o">,</span> <span class="kt">int</span> <span class="n">firstVisibleItem</span><span class="o">,</span> <span class="kt">int</span> <span class="n">visibleItemCount</span><span class="o">,</span> <span class="kt">int</span> <span class="n">totalItemCount</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>            <span class="k">if</span> <span class="o">(</span><span class="n">selfListener</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>                <span class="n">selfListener</span><span class="o">.</span><span class="na">onScroll</span><span class="o">(</span><span class="n">view</span><span class="o">,</span> <span class="n">firstVisibleItem</span><span class="o">,</span> <span class="n">visibleItemCount</span><span class="o">,</span> <span class="n">totalItemCount</span><span class="o">);</span>
</span><span class='line'>            <span class="o">}</span>
</span><span class='line'>            <span class="k">if</span> <span class="o">(</span><span class="n">clientListener</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>                <span class="n">clientListener</span><span class="o">.</span><span class="na">onScroll</span><span class="o">(</span><span class="n">view</span><span class="o">,</span> <span class="n">firstVisibleItem</span><span class="o">,</span> <span class="n">visibleItemCount</span><span class="o">,</span> <span class="n">totalItemCount</span><span class="o">);</span>
</span><span class='line'>            <span class="o">}</span>
</span><span class='line'>        <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>        <span class="nd">@Override</span>
</span><span class='line'>        <span class="kd">public</span> <span class="kt">void</span> <span class="nf">onScrollStateChanged</span><span class="o">(</span><span class="n">AbsListView</span> <span class="n">view</span><span class="o">,</span> <span class="kt">int</span> <span class="n">scrollState</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>            <span class="k">if</span> <span class="o">(</span><span class="n">selfListener</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>                <span class="n">selfListener</span><span class="o">.</span><span class="na">onScrollStateChanged</span><span class="o">(</span><span class="n">view</span><span class="o">,</span> <span class="n">scrollState</span><span class="o">);</span>
</span><span class='line'>            <span class="o">}</span>
</span><span class='line'>            <span class="k">if</span> <span class="o">(</span><span class="n">clientListener</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>                <span class="n">clientListener</span><span class="o">.</span><span class="na">onScrollStateChanged</span><span class="o">(</span><span class="n">view</span><span class="o">,</span> <span class="n">scrollState</span><span class="o">);</span>
</span><span class='line'>            <span class="o">}</span>
</span><span class='line'>        <span class="o">}</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">private</span> <span class="n">OnScrollListener</span> <span class="n">mOnScrollListener</span> <span class="o">=</span> <span class="k">new</span> <span class="n">OnScrollListener</span><span class="o">()</span> <span class="o">{</span>
</span><span class='line'>        <span class="nd">@Override</span>
</span><span class='line'>        <span class="kd">public</span> <span class="kt">void</span> <span class="nf">onScrollStateChanged</span><span class="o">(</span><span class="n">AbsListView</span> <span class="n">view</span><span class="o">,</span> <span class="kt">int</span> <span class="n">scrollState</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>            <span class="k">switch</span> <span class="o">(</span><span class="n">scrollState</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>                <span class="k">case</span> <span class="nl">SCROLL_STATE_IDLE:</span>
</span><span class='line'>                    <span class="n">mTime</span> <span class="o">=</span> <span class="n">INVALID_TIME</span><span class="o">;</span>
</span><span class='line'>                    <span class="n">setVelocity</span><span class="o">(</span><span class="mi">0</span><span class="o">);</span>
</span><span class='line'>                    <span class="k">break</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'>                <span class="k">default</span><span class="o">:</span>
</span><span class='line'>                    <span class="k">break</span><span class="o">;</span>
</span><span class='line'>            <span class="o">}</span>
</span><span class='line'>        <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>        <span class="nd">@Override</span>
</span><span class='line'>        <span class="kd">public</span> <span class="kt">void</span> <span class="nf">onScroll</span><span class="o">(</span><span class="n">AbsListView</span> <span class="n">view</span><span class="o">,</span> <span class="kt">int</span> <span class="n">firstVisiblePosition</span><span class="o">,</span> <span class="kt">int</span> <span class="n">visibleItemCount</span><span class="o">,</span> <span class="kt">int</span> <span class="n">totalItemCount</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>
</span><span class='line'>            <span class="kd">final</span> <span class="kt">long</span> <span class="n">now</span> <span class="o">=</span> <span class="n">AnimationUtils</span><span class="o">.</span><span class="na">currentAnimationTimeMillis</span><span class="o">();</span>
</span><span class='line'>            <span class="kd">final</span> <span class="kt">int</span> <span class="n">lastVisiblePosition</span> <span class="o">=</span> <span class="n">firstVisiblePosition</span> <span class="o">+</span> <span class="n">visibleItemCount</span> <span class="o">-</span> <span class="mi">1</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'>            <span class="k">if</span> <span class="o">(</span><span class="n">mTime</span> <span class="o">!=</span> <span class="n">INVALID_TIME</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>
</span><span class='line'>                <span class="kd">final</span> <span class="kt">long</span> <span class="n">delta</span> <span class="o">=</span> <span class="n">now</span> <span class="o">-</span> <span class="n">mTime</span><span class="o">;</span>
</span><span class='line'>                <span class="k">if</span> <span class="o">(</span><span class="n">now</span> <span class="o">-</span> <span class="n">mTime</span> <span class="o">&gt;</span> <span class="n">MINIMUM_TIME_DELTA</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>                    <span class="kt">int</span> <span class="n">distance</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span>
</span><span class='line'>                    <span class="c1">//@formatter:off</span>
</span><span class='line'>                    <span class="k">if</span> <span class="o">(</span><span class="n">mFirstVisiblePosition</span> <span class="o">&gt;=</span> <span class="n">firstVisiblePosition</span>
</span><span class='line'>                            <span class="o">&amp;&amp;</span> <span class="n">mFirstVisiblePosition</span> <span class="o">&lt;=</span> <span class="n">lastVisiblePosition</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>                        <span class="n">distance</span> <span class="o">=</span> <span class="n">getChildAt</span><span class="o">(</span><span class="n">mFirstVisiblePosition</span> <span class="o">-</span> <span class="n">firstVisiblePosition</span><span class="o">).</span><span class="na">getTop</span><span class="o">()</span> <span class="o">-</span> <span class="n">mFirstVisibleViewTop</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'>                    <span class="o">}</span> <span class="k">else</span> <span class="k">if</span> <span class="o">(</span><span class="n">mLastVisiblePosition</span> <span class="o">&gt;=</span> <span class="n">firstVisiblePosition</span>
</span><span class='line'>                            <span class="o">&amp;&amp;</span> <span class="n">mLastVisiblePosition</span> <span class="o">&lt;=</span> <span class="n">lastVisiblePosition</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>                        <span class="n">distance</span> <span class="o">=</span> <span class="n">getChildAt</span><span class="o">(</span><span class="n">mLastVisiblePosition</span> <span class="o">-</span> <span class="n">firstVisiblePosition</span><span class="o">).</span><span class="na">getTop</span><span class="o">()</span> <span class="o">-</span> <span class="n">mLastVisibleViewTop</span><span class="o">;</span>
</span><span class='line'>                    <span class="c1">//@formatter:on</span>
</span><span class='line'>                    <span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
</span><span class='line'>                        <span class="c1">// We&#39;re in a case were the item we were previously</span>
</span><span class='line'>                        <span class="c1">// referencing has moved out of the visible window.</span>
</span><span class='line'>                        <span class="c1">// Let&#39;s compute an approximative distance</span>
</span><span class='line'>                        <span class="kt">int</span> <span class="n">heightSum</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span>
</span><span class='line'>                        <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">visibleItemCount</span><span class="o">;</span> <span class="n">i</span><span class="o">++)</span> <span class="o">{</span>
</span><span class='line'>                            <span class="n">heightSum</span> <span class="o">+=</span> <span class="n">getChildAt</span><span class="o">(</span><span class="n">i</span><span class="o">).</span><span class="na">getHeight</span><span class="o">();</span>
</span><span class='line'>                        <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>                        <span class="n">distance</span> <span class="o">=</span> <span class="n">heightSum</span> <span class="o">/</span> <span class="n">visibleItemCount</span> <span class="o">*</span> <span class="o">(</span><span class="n">mFirstVisiblePosition</span> <span class="o">-</span> <span class="n">firstVisiblePosition</span><span class="o">);</span>
</span><span class='line'>                    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>                    <span class="n">setVelocity</span><span class="o">((</span><span class="kt">int</span><span class="o">)</span> <span class="o">(</span><span class="mi">1000</span><span class="n">d</span> <span class="o">*</span> <span class="n">distance</span> <span class="o">/</span> <span class="n">delta</span><span class="o">));</span>
</span><span class='line'>                <span class="o">}</span>
</span><span class='line'>            <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>            <span class="n">mFirstVisiblePosition</span> <span class="o">=</span> <span class="n">firstVisiblePosition</span><span class="o">;</span>
</span><span class='line'>            <span class="n">mFirstVisibleViewTop</span> <span class="o">=</span> <span class="n">getChildAt</span><span class="o">(</span><span class="mi">0</span><span class="o">).</span><span class="na">getTop</span><span class="o">();</span>
</span><span class='line'>            <span class="n">mLastVisiblePosition</span> <span class="o">=</span> <span class="n">lastVisiblePosition</span><span class="o">;</span>
</span><span class='line'>            <span class="n">mLastVisibleViewTop</span> <span class="o">=</span> <span class="n">getChildAt</span><span class="o">(</span><span class="n">visibleItemCount</span> <span class="o">-</span> <span class="mi">1</span><span class="o">).</span><span class="na">getTop</span><span class="o">();</span>
</span><span class='line'>
</span><span class='line'>            <span class="n">mTime</span> <span class="o">=</span> <span class="n">now</span><span class="o">;</span>
</span><span class='line'>        <span class="o">}</span>
</span><span class='line'>    <span class="o">};</span>
</span><span class='line'>
</span><span class='line'><span class="o">}</span>
</span></code></pre></td></tr></table></div></figure>


<h3>The final code</h3>

<p>Now we can be notified of a change in the velocity of our <code>ListView</code>, so we can animate in a <em>scroll-to-top</em> button only when going beyond a certain threshold. First of all, let&#8217;s create the layout of our <code>Activity</code>:</p>

<figure class='code'><figcaption><span>main_activity.xml </span></figcaption>
 <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
</pre></td><td class='code'><pre><code class='xml'><span class='line'><span class="cp">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;</span>
</span><span class='line'><span class="nt">&lt;merge</span> <span class="na">xmlns:android=</span><span class="s">&quot;http://schemas.android.com/apk/res/android&quot;</span>
</span><span class='line'>    <span class="na">xmlns:tools=</span><span class="s">&quot;http://schemas.android.com/tools&quot;</span>
</span><span class='line'>    <span class="na">android:layout_width=</span><span class="s">&quot;match_parent&quot;</span>
</span><span class='line'>    <span class="na">android:layout_height=</span><span class="s">&quot;match_parent&quot;</span> <span class="nt">&gt;</span>
</span><span class='line'>
</span><span class='line'>    <span class="nt">&lt;com.cyrilmottier.android.scrolltotop.widget.VelocityListView</span>
</span><span class='line'>        <span class="na">android:id=</span><span class="s">&quot;@android:id/list&quot;</span>
</span><span class='line'>        <span class="na">android:layout_width=</span><span class="s">&quot;match_parent&quot;</span>
</span><span class='line'>        <span class="na">android:layout_height=</span><span class="s">&quot;match_parent&quot;</span> <span class="nt">/&gt;</span>
</span><span class='line'>
</span><span class='line'>    <span class="nt">&lt;Button</span>
</span><span class='line'>        <span class="na">android:id=</span><span class="s">&quot;@+id/btn_scroll_to_top&quot;</span>
</span><span class='line'>        <span class="na">android:layout_width=</span><span class="s">&quot;match_parent&quot;</span>
</span><span class='line'>        <span class="na">android:layout_height=</span><span class="s">&quot;32dp&quot;</span>
</span><span class='line'>        <span class="na">android:layout_gravity=</span><span class="s">&quot;top&quot;</span>
</span><span class='line'>        <span class="na">android:background=</span><span class="s">&quot;@drawable/list_selector&quot;</span>
</span><span class='line'>        <span class="na">android:gravity=</span><span class="s">&quot;center&quot;</span>
</span><span class='line'>        <span class="na">android:text=</span><span class="s">&quot;@string/tap_to_scroll_to_top&quot;</span>
</span><span class='line'>        <span class="na">android:textColor=</span><span class="s">&quot;@android:color/white&quot;</span>
</span><span class='line'>        <span class="na">android:textSize=</span><span class="s">&quot;12sp&quot;</span>
</span><span class='line'>        <span class="na">android:textStyle=</span><span class="s">&quot;bold&quot;</span>
</span><span class='line'>        <span class="na">android:translationY=</span><span class="s">&quot;-32dp&quot;</span> <span class="nt">/&gt;</span>
</span><span class='line'>
</span><span class='line'><span class="nt">&lt;/merge&gt;</span>
</span></code></pre></td></tr></table></div></figure>


<p>The <code>Activity</code>&#8217;s code is now crystal clear:</p>

<figure class='code'><figcaption><span>MainActivity.java </span></figcaption>
 <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
<span class='line-number'>56</span>
<span class='line-number'>57</span>
<span class='line-number'>58</span>
<span class='line-number'>59</span>
<span class='line-number'>60</span>
<span class='line-number'>61</span>
<span class='line-number'>62</span>
<span class='line-number'>63</span>
<span class='line-number'>64</span>
<span class='line-number'>65</span>
<span class='line-number'>66</span>
<span class='line-number'>67</span>
<span class='line-number'>68</span>
<span class='line-number'>69</span>
<span class='line-number'>70</span>
<span class='line-number'>71</span>
<span class='line-number'>72</span>
<span class='line-number'>73</span>
<span class='line-number'>74</span>
<span class='line-number'>75</span>
<span class='line-number'>76</span>
<span class='line-number'>77</span>
<span class='line-number'>78</span>
<span class='line-number'>79</span>
<span class='line-number'>80</span>
<span class='line-number'>81</span>
<span class='line-number'>82</span>
<span class='line-number'>83</span>
<span class='line-number'>84</span>
<span class='line-number'>85</span>
<span class='line-number'>86</span>
<span class='line-number'>87</span>
<span class='line-number'>88</span>
<span class='line-number'>89</span>
<span class='line-number'>90</span>
<span class='line-number'>91</span>
<span class='line-number'>92</span>
<span class='line-number'>93</span>
<span class='line-number'>94</span>
<span class='line-number'>95</span>
<span class='line-number'>96</span>
<span class='line-number'>97</span>
<span class='line-number'>98</span>
<span class='line-number'>99</span>
<span class='line-number'>100</span>
<span class='line-number'>101</span>
<span class='line-number'>102</span>
<span class='line-number'>103</span>
<span class='line-number'>104</span>
<span class='line-number'>105</span>
<span class='line-number'>106</span>
<span class='line-number'>107</span>
<span class='line-number'>108</span>
<span class='line-number'>109</span>
<span class='line-number'>110</span>
<span class='line-number'>111</span>
<span class='line-number'>112</span>
<span class='line-number'>113</span>
<span class='line-number'>114</span>
<span class='line-number'>115</span>
<span class='line-number'>116</span>
<span class='line-number'>117</span>
<span class='line-number'>118</span>
<span class='line-number'>119</span>
<span class='line-number'>120</span>
<span class='line-number'>121</span>
<span class='line-number'>122</span>
<span class='line-number'>123</span>
<span class='line-number'>124</span>
<span class='line-number'>125</span>
<span class='line-number'>126</span>
<span class='line-number'>127</span>
<span class='line-number'>128</span>
<span class='line-number'>129</span>
<span class='line-number'>130</span>
<span class='line-number'>131</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="kn">package</span> <span class="n">com</span><span class="o">.</span><span class="na">cyrilmottier</span><span class="o">.</span><span class="na">android</span><span class="o">.</span><span class="na">scrolltotop</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.animation.Animator</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.animation.Animator.AnimatorListener</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.animation.AnimatorListenerAdapter</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.app.Activity</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.os.Bundle</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.view.View</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.view.View.OnClickListener</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.view.ViewGroup</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.view.ViewPropertyAnimator</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.widget.BaseAdapter</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.widget.Button</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.widget.TextView</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'><span class="kn">import</span> <span class="nn">com.cyrilmottier.android.scrolltotop.widget.VelocityListView</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">com.cyrilmottier.android.scrolltotop.widget.VelocityListView.OnVelocityListViewListener</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'><span class="kd">public</span> <span class="kd">class</span> <span class="nc">MainActivity</span> <span class="kd">extends</span> <span class="n">Activity</span> <span class="o">{</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="kt">int</span> <span class="n">VELOCITY_ABSOLUTE_THRESHOLD</span> <span class="o">=</span> <span class="mi">5500</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="kt">int</span> <span class="n">BIT_VISIBILITY</span> <span class="o">=</span> <span class="mh">0x01</span><span class="o">;</span>
</span><span class='line'>    <span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="kt">int</span> <span class="n">BIT_ANIMATION</span> <span class="o">=</span> <span class="mh">0x02</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="kt">int</span> <span class="n">SCROLL_TO_TOP_HIDDEN</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span>
</span><span class='line'>    <span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="kt">int</span> <span class="n">SCROLL_TO_TOP_HIDING</span> <span class="o">=</span> <span class="n">BIT_ANIMATION</span><span class="o">;</span>
</span><span class='line'>    <span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="kt">int</span> <span class="n">SCROLL_TO_TOP_SHOWN</span> <span class="o">=</span> <span class="n">BIT_VISIBILITY</span><span class="o">;</span>
</span><span class='line'>    <span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="kt">int</span> <span class="n">SCROLL_TO_TOP_SHOWING</span> <span class="o">=</span> <span class="n">BIT_ANIMATION</span> <span class="o">|</span> <span class="n">BIT_VISIBILITY</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">private</span> <span class="n">VelocityListView</span> <span class="n">mListView</span><span class="o">;</span>
</span><span class='line'>    <span class="kd">private</span> <span class="n">Button</span> <span class="n">mScrollToTopButton</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">private</span> <span class="n">ViewPropertyAnimator</span> <span class="n">mAnimator</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">private</span> <span class="kt">int</span> <span class="n">mVelocityAbsoluteThreshold</span><span class="o">;</span>
</span><span class='line'>    <span class="kd">private</span> <span class="kt">int</span> <span class="n">mScrollToTopState</span> <span class="o">=</span> <span class="n">SCROLL_TO_TOP_HIDDEN</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'>    <span class="nd">@Override</span>
</span><span class='line'>    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">onCreate</span><span class="o">(</span><span class="n">Bundle</span> <span class="n">savedInstanceState</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="kd">super</span><span class="o">.</span><span class="na">onCreate</span><span class="o">(</span><span class="n">savedInstanceState</span><span class="o">);</span>
</span><span class='line'>
</span><span class='line'>        <span class="n">mVelocityAbsoluteThreshold</span> <span class="o">=</span> <span class="o">(</span><span class="kt">int</span><span class="o">)</span> <span class="o">(</span><span class="n">VELOCITY_ABSOLUTE_THRESHOLD</span> <span class="o">*</span> <span class="n">getResources</span><span class="o">().</span><span class="na">getDisplayMetrics</span><span class="o">().</span><span class="na">density</span> <span class="o">+</span> <span class="mf">0.5f</span><span class="o">);</span>
</span><span class='line'>
</span><span class='line'>        <span class="n">setContentView</span><span class="o">(</span><span class="n">R</span><span class="o">.</span><span class="na">layout</span><span class="o">.</span><span class="na">main_activity</span><span class="o">);</span>
</span><span class='line'>
</span><span class='line'>        <span class="n">mScrollToTopButton</span> <span class="o">=</span> <span class="o">(</span><span class="n">Button</span><span class="o">)</span> <span class="n">findViewById</span><span class="o">(</span><span class="n">R</span><span class="o">.</span><span class="na">id</span><span class="o">.</span><span class="na">btn_scroll_to_top</span><span class="o">);</span>
</span><span class='line'>        <span class="n">mScrollToTopButton</span><span class="o">.</span><span class="na">setOnClickListener</span><span class="o">(</span><span class="n">mOnClickListener</span><span class="o">);</span>
</span><span class='line'>
</span><span class='line'>        <span class="n">mAnimator</span> <span class="o">=</span> <span class="n">mScrollToTopButton</span><span class="o">.</span><span class="na">animate</span><span class="o">();</span>
</span><span class='line'>
</span><span class='line'>        <span class="n">mListView</span> <span class="o">=</span> <span class="o">(</span><span class="n">VelocityListView</span><span class="o">)</span> <span class="n">findViewById</span><span class="o">(</span><span class="n">android</span><span class="o">.</span><span class="na">R</span><span class="o">.</span><span class="na">id</span><span class="o">.</span><span class="na">list</span><span class="o">);</span>
</span><span class='line'>        <span class="n">mListView</span><span class="o">.</span><span class="na">setAdapter</span><span class="o">(</span><span class="k">new</span> <span class="n">CheesesAdapter</span><span class="o">());</span>
</span><span class='line'>        <span class="n">mListView</span><span class="o">.</span><span class="na">setOnVelocityListener</span><span class="o">(</span><span class="n">mOnVelocityListener</span><span class="o">);</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">private</span> <span class="n">OnClickListener</span> <span class="n">mOnClickListener</span> <span class="o">=</span> <span class="k">new</span> <span class="n">OnClickListener</span><span class="o">()</span> <span class="o">{</span>
</span><span class='line'>        <span class="nd">@Override</span>
</span><span class='line'>        <span class="kd">public</span> <span class="kt">void</span> <span class="nf">onClick</span><span class="o">(</span><span class="n">View</span> <span class="n">v</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>            <span class="n">mListView</span><span class="o">.</span><span class="na">requestPositionToScreen</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="kc">true</span><span class="o">);</span>
</span><span class='line'>        <span class="o">}</span>
</span><span class='line'>    <span class="o">};</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">private</span> <span class="n">OnVelocityListViewListener</span> <span class="n">mOnVelocityListener</span> <span class="o">=</span> <span class="k">new</span> <span class="n">OnVelocityListViewListener</span><span class="o">()</span> <span class="o">{</span>
</span><span class='line'>        <span class="nd">@Override</span>
</span><span class='line'>        <span class="kd">public</span> <span class="kt">void</span> <span class="nf">onVelocityChanged</span><span class="o">(</span><span class="kt">int</span> <span class="n">velocity</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>            <span class="k">if</span> <span class="o">(</span><span class="n">velocity</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>                <span class="k">if</span> <span class="o">(</span><span class="n">Math</span><span class="o">.</span><span class="na">abs</span><span class="o">(</span><span class="n">velocity</span><span class="o">)</span> <span class="o">&gt;</span> <span class="n">mVelocityAbsoluteThreshold</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>                    <span class="k">if</span> <span class="o">((</span><span class="n">mScrollToTopState</span> <span class="o">&amp;&amp;</span> <span class="n">BIT_VISIBILITY</span><span class="o">)</span> <span class="o">==</span> <span class="mi">0</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>                        <span class="n">mAnimator</span><span class="o">.</span><span class="na">translationY</span><span class="o">(</span><span class="mi">0</span><span class="o">).</span><span class="na">setListener</span><span class="o">(</span><span class="n">mOnShownListener</span><span class="o">);</span>
</span><span class='line'>                        <span class="n">mScrollToTopState</span> <span class="o">=</span> <span class="n">SCROLL_TO_TOP_SHOWING</span><span class="o">;</span>
</span><span class='line'>                    <span class="o">}</span>
</span><span class='line'>                <span class="o">}</span>
</span><span class='line'>            <span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
</span><span class='line'>                <span class="k">if</span> <span class="o">((</span><span class="n">mScrollToTopState</span> <span class="o">&amp;&amp;</span> <span class="n">BIT_VISIBILITY</span><span class="o">)</span> <span class="o">==</span> <span class="n">BIT_VISIBILITY</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>                    <span class="n">mAnimator</span><span class="o">.</span><span class="na">translationY</span><span class="o">(-</span><span class="n">mScrollToTopButton</span><span class="o">.</span><span class="na">getHeight</span><span class="o">()).</span><span class="na">setListener</span><span class="o">(</span><span class="n">mOnHiddenListener</span><span class="o">);</span>
</span><span class='line'>                    <span class="n">mScrollToTopState</span> <span class="o">=</span> <span class="n">SCROLL_TO_TOP_HIDING</span><span class="o">;</span>
</span><span class='line'>                <span class="o">}</span>
</span><span class='line'>            <span class="o">}</span>
</span><span class='line'>        <span class="o">}</span>
</span><span class='line'>    <span class="o">};</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">private</span> <span class="kd">final</span> <span class="n">AnimatorListener</span> <span class="n">mOnHiddenListener</span> <span class="o">=</span> <span class="k">new</span> <span class="n">AnimatorListenerAdapter</span><span class="o">()</span> <span class="o">{</span>
</span><span class='line'>        <span class="kd">public</span> <span class="kt">void</span> <span class="nf">onAnimationEnd</span><span class="o">(</span><span class="n">Animator</span> <span class="n">animation</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>            <span class="n">mScrollToTopState</span> <span class="o">=</span> <span class="n">SCROLL_TO_TOP_HIDDEN</span><span class="o">;</span>
</span><span class='line'>        <span class="o">};</span>
</span><span class='line'>    <span class="o">};</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">private</span> <span class="kd">final</span> <span class="n">AnimatorListener</span> <span class="n">mOnShownListener</span> <span class="o">=</span> <span class="k">new</span> <span class="n">AnimatorListenerAdapter</span><span class="o">()</span> <span class="o">{</span>
</span><span class='line'>        <span class="kd">public</span> <span class="kt">void</span> <span class="nf">onAnimationEnd</span><span class="o">(</span><span class="n">Animator</span> <span class="n">animation</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>            <span class="n">mScrollToTopState</span> <span class="o">=</span> <span class="n">SCROLL_TO_TOP_SHOWN</span><span class="o">;</span>
</span><span class='line'>        <span class="o">};</span>
</span><span class='line'>    <span class="o">};</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">public</span> <span class="kd">class</span> <span class="nc">CheesesAdapter</span> <span class="kd">extends</span> <span class="n">BaseAdapter</span> <span class="o">{</span>
</span><span class='line'>
</span><span class='line'>        <span class="nd">@Override</span>
</span><span class='line'>        <span class="kd">public</span> <span class="kt">int</span> <span class="nf">getCount</span><span class="o">()</span> <span class="o">{</span>
</span><span class='line'>            <span class="k">return</span> <span class="n">CHEESES</span><span class="o">.</span><span class="na">length</span><span class="o">;</span>
</span><span class='line'>        <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>        <span class="nd">@Override</span>
</span><span class='line'>        <span class="kd">public</span> <span class="n">String</span> <span class="nf">getItem</span><span class="o">(</span><span class="kt">int</span> <span class="n">position</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>            <span class="k">return</span> <span class="n">CHEESES</span><span class="o">[</span><span class="n">position</span><span class="o">];</span>
</span><span class='line'>        <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>        <span class="nd">@Override</span>
</span><span class='line'>        <span class="kd">public</span> <span class="kt">long</span> <span class="nf">getItemId</span><span class="o">(</span><span class="kt">int</span> <span class="n">position</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>            <span class="k">return</span> <span class="n">position</span><span class="o">;</span>
</span><span class='line'>        <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>        <span class="nd">@Override</span>
</span><span class='line'>        <span class="kd">public</span> <span class="n">View</span> <span class="nf">getView</span><span class="o">(</span><span class="kt">int</span> <span class="n">position</span><span class="o">,</span> <span class="n">View</span> <span class="n">convertView</span><span class="o">,</span> <span class="n">ViewGroup</span> <span class="n">parent</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>
</span><span class='line'>            <span class="k">if</span> <span class="o">(</span><span class="n">convertView</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>                <span class="n">convertView</span> <span class="o">=</span> <span class="n">getLayoutInflater</span><span class="o">().</span><span class="na">inflate</span><span class="o">(</span><span class="n">R</span><span class="o">.</span><span class="na">layout</span><span class="o">.</span><span class="na">text_item</span><span class="o">,</span> <span class="n">parent</span><span class="o">,</span> <span class="kc">false</span><span class="o">);</span>
</span><span class='line'>            <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>            <span class="o">((</span><span class="n">TextView</span><span class="o">)</span> <span class="n">convertView</span><span class="o">).</span><span class="na">setText</span><span class="o">(</span><span class="n">getItem</span><span class="o">(</span><span class="n">position</span><span class="o">));</span>
</span><span class='line'>
</span><span class='line'>            <span class="k">return</span> <span class="n">convertView</span><span class="o">;</span>
</span><span class='line'>        <span class="o">}</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">public</span> <span class="kd">static</span> <span class="kd">final</span> <span class="n">String</span> <span class="n">CHEESES</span><span class="o">[]</span> <span class="o">=</span> <span class="o">{</span>
</span><span class='line'>            <span class="s">&quot;Abbaye de Belloc&quot;</span><span class="o">,</span> <span class="s">&quot;Abbaye du Mont des Cats&quot;</span><span class="o">,</span>
</span><span class='line'>            <span class="c1">// ...</span>
</span><span class='line'>            <span class="s">&quot;Zanetti Grana Padano&quot;</span><span class="o">,</span> <span class="s">&quot;Zanetti Parmigiano Reggiano&quot;</span>
</span><span class='line'>    <span class="o">};</span>
</span><span class='line'>
</span><span class='line'><span class="o">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>As described previously, the code above should be considered as a proof of concept rather than a ready-to-use widget. Because of this I have decided not to push it on GitHub but share it &#8220;as it&#8221; here. Please note the license attached to it is the Apache v2.</p>

<p><button class="download-button" onclick="window.location='/media/2013/01/back-to-top-android-vs-ios/ScrollToTop.zip';"><span class="icon"></span><span class="title">Download source</span></button></p>

<h2>Conclusion</h2>

<p>Android&#8217;s scroll containers are probably more difficult to understand than their iOS counterparts, but they also offer a larger set of features. While scrolling to the top is extremely easy to implement on iOS, it requires more work from developers on Android. However, always keep in mind that implementing an iOS-like <em>scroll-to-top</em> gesture is not necessary 95% of the time. The other 5% can freely tweak or reuse the code I shared here.</p>

<p><em>Thanks to <a href="https://twitter.com/franklinharper">@franklinharper</a> and <a href="https://twitter.com/moystard">@moystard</a> for reading drafts of this</em></p>

<hr />

<ol>
<li>This flag is currently used by Android to determine whether the window can resize or must pan when a soft IME is open.</li>
</ol>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[The Google Maps Android API v2 Utopia]]></title>
    <link href="http://cyrilmottier.com/2012/12/07/the-google-maps-android-api-v2-utopia/"/>
    <updated>2012-12-07T00:00:00+01:00</updated>
    <id>http://cyrilmottier.com/2012/12/07/the-google-maps-android-api-v2-utopia</id>
    <content type="html"><![CDATA[<p>One of the major announcement this week was the release, by Google, of a new maps framework: the <a href="https://developers.google.com/maps/documentation/android/">Google Maps Android API v2</a>. It is nothing to say that this new framework was overwhelmingly expected among the Android developer and user communities. Indeed, while the Google Maps app was using vector-based maps and 3D rendering since its version 5.0 (working on Froyo+), these features weren&#8217;t available to third-party applications. The only option at this time was to continue <em>leveraging</em> (yep that&#8217;s not a joke) the long-outdated Google Maps Android API v1…</p>

<p>As the creator and developer of <a href="https://github.com/cyrilmottier/Polaris">Polaris</a> - a library greatly enhancing the features of Google Maps API v1 with effortless map annotating, gesture support, map callout support, built-in &#8220;user tracking&#8221; mode, etc. - and the developer of <a href="https://play.google.com/store/apps/details?id=com.cyrilmottier.android.avelov">AVélov</a> - a map-based application to determine the availability of city bikes/slots in Lyon, France - I really wanted to have a look at the new version of the framework. So did I and here is a feedback after 5 days playing with it.</p>

<!-- More -->


<p>At first sight, Google Maps Android API v2 is clearly an insanely great improvement to the first version of the framework. First of all, it is providing the developer with all of the features I developed on top of Google Maps Android API v1 with Polaris: it gets rid of the annoying <code>ItemizedOverlay</code>, it provides a &#8220;user-tracking&#8221; mode, it recognizes all gestures, it contains several default resources (markers, info windows), etc. Moreover, all of this is based on a new vector-based rendering engine supporting scrolling, zooming, tilting and bearing for continous levels. Thanks to that you can now have a non-discrete zoom-level of 6.1234 which basically means you can create awesome smooth animations.</p>

<p>In addition, the framework brings some cool new features such as support for third-party tile provider, ground overlays, polylines, polygones, etc.</p>

<p>Pretty logically, the engineers behing the framework threw away the API from v1 and re-wrote the v2 from scratch. I&#8217;m pretty happy with that because the new API are more Android-compliant and future proof. API v2 are finally in accordance with what we could expect from a company like Google that is supposed to excel at doing maps.</p>

<p>One of the major drawback though is that everything is final. In other words, they decided to put some concrete in the set of API to prevent developers from using them :s. While I understand the <code>final</code> keyword can be useful sometimes, I really don&#8217;t understand why they used it as proficiently and - as it looks to me - as stupidly. I&#8217;m strongly convinced developing a solid but yet extensible framework is possible - the Android SDK is a great example of it - and that&#8217;s not the approach Google took here.</p>

<p>Finally, there are some strong lacks such as the un-ability to be notified of <a href="http://code.google.com/p/gmaps-api-issues/issues/detail?id=4644">user location change</a> when using the default <code>LocationSource</code> or to be notified precisely of a <a href="http://code.google.com/p/gmaps-api-issues/issues/detail?id=4656"><code>CameraPosition</code> change</a>.</p>

<p>Okay so now we are done with the API, I will continue with the implementation. In order to efficiently test the new Google Maps API v2 framework, I decided to make the switch in <a href="https://play.google.com/store/apps/details?id=com.cyrilmottier.android.avelov">AVélov</a>. Put simply, the app consists on displaying a map with a bunch of markers. When you click on it you have an info window that pops out and shows the name/address of the station and starts an asynchronous request to query the current number of bikes/slots for this station. Once the query is done, the popup is updated with the availabilty data.</p>

<p>Let&#8217;s be honest this application is pretty simple. Well I guess it was too simple because I ended up with a lot of bugs and limitations. Indeed, while it bring some amazingly great improvements, it cruely lacks of polish and pixel-perfect-ness. This article is not intended to be a bug-tracker but here are the main issues I had/have:</p>

<ul>
<li><a href="http://code.google.com/p/gmaps-api-issues/issues/detail?id=4639">Issue #4639</a>: Black screen when instantiating a SupportMapFragment</li>
<li><a href="http://code.google.com/p/gmaps-api-issues/issues/detail?id=4645">Issue #4645</a>: Info windows are not refreshed when updated</li>
<li><a href="http://code.google.com/p/gmaps-api-issues/issues/detail?id=4666">Issue #4666</a>: Info window displayed in two parts with a 1px wide transparent gap</li>
<li><a href="http://code.google.com/p/gmaps-api-issues/issues/detail?id=4667">Issue #4667</a>: Blurry markers</li>
</ul>


<p>In a nutshell, I really consider this new Google Maps Android API v2 as a beta version. I spent a lot of time and energy working with it and finally realized I had done all of this for nothing. I am now waiting for all of these bugs to be fixed. From my point of view, I seriously consider this new Google Maps Android API v2 shouldn&#8217;t have been released at all or alternatively, should have been released as the Google Maps Android API v2 beta. It clearly doesn&#8217;t respect my motto: <em>Do less but do it great</em>.</p>

<p>I spent the last 5 days being both joyful and unbelievably mad at the same time. I couldn&#8217;t resign myself publishing a version of my app which quality was lower than the current available version. While Google Maps API v2 brings several major improvements, it also carries a lot of issues, bugs and limitations. Always keep that in mind when starting using it or you&#8217;ll end up as disappointed as I was.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[ActionBar on the Move]]></title>
    <link href="http://cyrilmottier.com/2012/11/27/actionbar-on-the-move/"/>
    <updated>2012-11-27T00:00:00+01:00</updated>
    <id>http://cyrilmottier.com/2012/11/27/actionbar-on-the-move</id>
    <content type="html"><![CDATA[<p><em><strong>Edit (11/27/12)</strong>: Added a video demonstrating the result on a Nexus 7 running on Android 4.1</em></p>

<p>Over the past year, the ActionBar paradigm has become an essential component in the process of designing and developing an Android application. Indeed, the ActionBar has many advantages that help developers in future-proofing their apps. It contains contextual actions, can be customized fairly easily, is highly scalable, etc. Because of this, one should ALWAYS consider using the ActionBar UI pattern in one&#8217;s design process when creating a new Android app.</p>

<p><code>ActionBar</code> features a lot of interesting styling APIs. These APIs let you brand your application so that it fits your design, while still being recognizable among other applications. Put simply, there are almost no limits to what you can do with an <code>ActionBar</code>. Until you try doing something more advanced …</p>

<!-- More -->


<p>Back in March 2012, I was in the process of designing <a href="https://play.google.com/store/apps/details?id=com.cyrilmottier.android.avelov">AVélov</a>, I really wanted to have an <code>ActionBar</code> that differentiated it from the other apps. So I came up with the idea of having an animated <code>ActionBar</code> background. AVélov being about bikes, I logically wanted the animation to be in relation with bikes (a bike riding from the left edge of the screen to the right screen, a spinning wheel, etc.).</p>

<p>In order to make sure this was possible I created a tiny app with an <code>ActionBar</code>. I rapidly built an <code>AnimationDrawable</code>, started it with a simple call to the <code>start()</code> method and used it as the <code>ActionBar</code>&#8217;s background. The result was pretty disappointing because it wasn&#8217;t animating at all. Exploring <code>ActionBarContainer</code> (a non-public <code>View</code> backing the <code>ActionBar</code>) source code I noticed it wasn&#8217;t registering a callback<sup>1</sup> to my <code>Drawable</code>:</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="kd">public</span> <span class="kt">void</span> <span class="nf">setPrimaryBackground</span><span class="o">(</span><span class="n">Drawable</span> <span class="n">bg</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>    <span class="n">mBackground</span> <span class="o">=</span> <span class="n">bg</span><span class="o">;</span>
</span><span class='line'>    <span class="n">invalidate</span><span class="o">();</span>
</span><span class='line'><span class="o">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>As a result, the <code>Drawable</code> had no way to notify the enclosing <code>View</code> to redraw itself at fixed time intervals. From my point of view this was a wanted behavior to avoid these web-of-the-90&#8217;s-red-to-yellow-blinking <code>ActionBar</code>s. I finally decided to postpone the animation to a future release.</p>

<p>Recently I came back to this feature/enhancement and started developing a new <code>Animatable</code> <code>Drawable</code> for testing purposes. This very basic <code>Drawable</code> changes its color and animates the changes in a smooth fashion:</p>

<figure class='code'><figcaption><span>ColorAnimationDrawable.java  </span></figcaption>
 <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
<span class='line-number'>56</span>
<span class='line-number'>57</span>
<span class='line-number'>58</span>
<span class='line-number'>59</span>
<span class='line-number'>60</span>
<span class='line-number'>61</span>
<span class='line-number'>62</span>
<span class='line-number'>63</span>
<span class='line-number'>64</span>
<span class='line-number'>65</span>
<span class='line-number'>66</span>
<span class='line-number'>67</span>
<span class='line-number'>68</span>
<span class='line-number'>69</span>
<span class='line-number'>70</span>
<span class='line-number'>71</span>
<span class='line-number'>72</span>
<span class='line-number'>73</span>
<span class='line-number'>74</span>
<span class='line-number'>75</span>
<span class='line-number'>76</span>
<span class='line-number'>77</span>
<span class='line-number'>78</span>
<span class='line-number'>79</span>
<span class='line-number'>80</span>
<span class='line-number'>81</span>
<span class='line-number'>82</span>
<span class='line-number'>83</span>
<span class='line-number'>84</span>
<span class='line-number'>85</span>
<span class='line-number'>86</span>
<span class='line-number'>87</span>
<span class='line-number'>88</span>
<span class='line-number'>89</span>
<span class='line-number'>90</span>
<span class='line-number'>91</span>
<span class='line-number'>92</span>
<span class='line-number'>93</span>
<span class='line-number'>94</span>
<span class='line-number'>95</span>
<span class='line-number'>96</span>
<span class='line-number'>97</span>
<span class='line-number'>98</span>
<span class='line-number'>99</span>
<span class='line-number'>100</span>
<span class='line-number'>101</span>
<span class='line-number'>102</span>
<span class='line-number'>103</span>
<span class='line-number'>104</span>
<span class='line-number'>105</span>
<span class='line-number'>106</span>
<span class='line-number'>107</span>
<span class='line-number'>108</span>
<span class='line-number'>109</span>
<span class='line-number'>110</span>
<span class='line-number'>111</span>
<span class='line-number'>112</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="kd">public</span> <span class="kd">class</span> <span class="nc">ColorAnimationDrawable</span> <span class="kd">extends</span> <span class="n">Drawable</span> <span class="kd">implements</span> <span class="n">Animatable</span> <span class="o">{</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="kt">long</span> <span class="n">FRAME_DURATION</span> <span class="o">=</span> <span class="mi">1000</span> <span class="o">/</span> <span class="mi">60</span><span class="o">;</span>
</span><span class='line'>    <span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="kt">long</span> <span class="n">ANIMATION_DURATION</span> <span class="o">=</span> <span class="mi">1500</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="kt">int</span> <span class="n">ACCCENT_COLOR</span> <span class="o">=</span> <span class="mh">0x33FFFFFF</span><span class="o">;</span>
</span><span class='line'>    <span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="kt">int</span> <span class="n">DIM_COLOR</span> <span class="o">=</span> <span class="mh">0x33000000</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="n">Random</span> <span class="n">mRandom</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Random</span><span class="o">();</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">private</span> <span class="kd">final</span> <span class="n">Paint</span> <span class="n">mPaint</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Paint</span><span class="o">();</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">private</span> <span class="kt">boolean</span> <span class="n">mIsRunning</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">private</span> <span class="kt">int</span> <span class="n">mStartColor</span><span class="o">;</span>
</span><span class='line'>    <span class="kd">private</span> <span class="kt">int</span> <span class="n">mEndColor</span><span class="o">;</span>
</span><span class='line'>    <span class="kd">private</span> <span class="kt">int</span> <span class="n">mCurrentColor</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">private</span> <span class="kt">long</span> <span class="n">mStartTime</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'>    <span class="nd">@Override</span>
</span><span class='line'>    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">draw</span><span class="o">(</span><span class="n">Canvas</span> <span class="n">canvas</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="kd">final</span> <span class="n">Rect</span> <span class="n">bounds</span> <span class="o">=</span> <span class="n">getBounds</span><span class="o">();</span>
</span><span class='line'>
</span><span class='line'>        <span class="n">mPaint</span><span class="o">.</span><span class="na">setColor</span><span class="o">(</span><span class="n">mCurrentColor</span><span class="o">);</span>
</span><span class='line'>        <span class="n">canvas</span><span class="o">.</span><span class="na">drawRect</span><span class="o">(</span><span class="n">bounds</span><span class="o">,</span> <span class="n">mPaint</span><span class="o">);</span>
</span><span class='line'>
</span><span class='line'>        <span class="n">mPaint</span><span class="o">.</span><span class="na">setColor</span><span class="o">(</span><span class="n">ACCCENT_COLOR</span><span class="o">);</span>
</span><span class='line'>        <span class="n">canvas</span><span class="o">.</span><span class="na">drawRect</span><span class="o">(</span><span class="n">bounds</span><span class="o">.</span><span class="na">left</span><span class="o">,</span> <span class="n">bounds</span><span class="o">.</span><span class="na">top</span><span class="o">,</span> <span class="n">bounds</span><span class="o">.</span><span class="na">right</span><span class="o">,</span> <span class="n">bounds</span><span class="o">.</span><span class="na">top</span> <span class="o">+</span> <span class="mi">1</span><span class="o">,</span> <span class="n">mPaint</span><span class="o">);</span>
</span><span class='line'>
</span><span class='line'>        <span class="n">mPaint</span><span class="o">.</span><span class="na">setColor</span><span class="o">(</span><span class="n">DIM_COLOR</span><span class="o">);</span>
</span><span class='line'>        <span class="n">canvas</span><span class="o">.</span><span class="na">drawRect</span><span class="o">(</span><span class="n">bounds</span><span class="o">.</span><span class="na">left</span><span class="o">,</span> <span class="n">bounds</span><span class="o">.</span><span class="na">bottom</span> <span class="o">-</span> <span class="mi">2</span><span class="o">,</span> <span class="n">bounds</span><span class="o">.</span><span class="na">right</span><span class="o">,</span> <span class="n">bounds</span><span class="o">.</span><span class="na">bottom</span><span class="o">,</span> <span class="n">mPaint</span><span class="o">);</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="nd">@Override</span>
</span><span class='line'>    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">setAlpha</span><span class="o">(</span><span class="kt">int</span> <span class="n">alpha</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="n">oops</span><span class="o">(</span><span class="s">&quot;setAlpha(int)&quot;</span><span class="o">);</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="nd">@Override</span>
</span><span class='line'>    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">setColorFilter</span><span class="o">(</span><span class="n">ColorFilter</span> <span class="n">cf</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="n">oops</span><span class="o">(</span><span class="s">&quot;setColorFilter(ColorFilter)&quot;</span><span class="o">);</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="nd">@Override</span>
</span><span class='line'>    <span class="kd">public</span> <span class="kt">int</span> <span class="nf">getOpacity</span><span class="o">()</span> <span class="o">{</span>
</span><span class='line'>        <span class="k">return</span> <span class="n">PixelFormat</span><span class="o">.</span><span class="na">TRANSPARENT</span><span class="o">;</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="nd">@Override</span>
</span><span class='line'>    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">start</span><span class="o">()</span> <span class="o">{</span>
</span><span class='line'>        <span class="k">if</span> <span class="o">(!</span><span class="n">isRunning</span><span class="o">())</span> <span class="o">{</span>
</span><span class='line'>            <span class="n">mIsRunning</span> <span class="o">=</span> <span class="kc">true</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'>            <span class="n">mStartTime</span> <span class="o">=</span> <span class="n">AnimationUtils</span><span class="o">.</span><span class="na">currentAnimationTimeMillis</span><span class="o">();</span>
</span><span class='line'>            <span class="n">mStartColor</span> <span class="o">=</span> <span class="n">randomColor</span><span class="o">();</span>
</span><span class='line'>            <span class="n">mEndColor</span> <span class="o">=</span> <span class="n">randomColor</span><span class="o">();</span>
</span><span class='line'>
</span><span class='line'>            <span class="n">scheduleSelf</span><span class="o">(</span><span class="n">mUpdater</span><span class="o">,</span> <span class="n">SystemClock</span><span class="o">.</span><span class="na">uptimeMillis</span><span class="o">()</span> <span class="o">+</span> <span class="n">FRAME_DURATION</span><span class="o">);</span>
</span><span class='line'>            <span class="n">invalidateSelf</span><span class="o">();</span>
</span><span class='line'>        <span class="o">}</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="nd">@Override</span>
</span><span class='line'>    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">stop</span><span class="o">()</span> <span class="o">{</span>
</span><span class='line'>        <span class="k">if</span> <span class="o">(</span><span class="n">isRunning</span><span class="o">())</span> <span class="o">{</span>
</span><span class='line'>            <span class="n">unscheduleSelf</span><span class="o">(</span><span class="n">mUpdater</span><span class="o">);</span>
</span><span class='line'>            <span class="n">mIsRunning</span> <span class="o">=</span> <span class="kc">false</span><span class="o">;</span>
</span><span class='line'>        <span class="o">}</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="nd">@Override</span>
</span><span class='line'>    <span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">isRunning</span><span class="o">()</span> <span class="o">{</span>
</span><span class='line'>        <span class="k">return</span> <span class="n">mIsRunning</span><span class="o">;</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">private</span> <span class="kt">void</span> <span class="nf">oops</span><span class="o">(</span><span class="n">String</span> <span class="n">message</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="k">throw</span> <span class="k">new</span> <span class="nf">UnsupportedOperationException</span><span class="o">(</span><span class="s">&quot;ColorAnimationDrawable doesn&#39;t support &quot;</span> <span class="o">+</span> <span class="n">message</span><span class="o">);</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">private</span> <span class="kd">static</span> <span class="kt">int</span> <span class="nf">randomColor</span><span class="o">()</span> <span class="o">{</span>
</span><span class='line'>        <span class="k">return</span> <span class="n">mRandom</span><span class="o">.</span><span class="na">nextInt</span><span class="o">()</span> <span class="o">&amp;</span> <span class="mh">0x00FFFFFF</span><span class="o">;</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">private</span> <span class="kd">static</span> <span class="kt">int</span> <span class="nf">evaluate</span><span class="o">(</span><span class="kt">float</span> <span class="n">fraction</span><span class="o">,</span> <span class="kt">int</span> <span class="n">startValue</span><span class="o">,</span> <span class="kt">int</span> <span class="n">endValue</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="k">return</span> <span class="o">(</span><span class="kt">int</span><span class="o">)</span> <span class="o">(</span><span class="n">startValue</span> <span class="o">+</span> <span class="n">fraction</span> <span class="o">*</span> <span class="o">(</span><span class="n">endValue</span> <span class="o">-</span> <span class="n">startValue</span><span class="o">));</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">private</span> <span class="kd">final</span> <span class="n">Runnable</span> <span class="n">mUpdater</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Runnable</span><span class="o">()</span> <span class="o">{</span>
</span><span class='line'>        <span class="nd">@Override</span>
</span><span class='line'>        <span class="kd">public</span> <span class="kt">void</span> <span class="nf">run</span><span class="o">()</span> <span class="o">{</span>
</span><span class='line'>            <span class="kt">long</span> <span class="n">now</span> <span class="o">=</span> <span class="n">AnimationUtils</span><span class="o">.</span><span class="na">currentAnimationTimeMillis</span><span class="o">();</span>
</span><span class='line'>            <span class="kt">long</span> <span class="n">duration</span> <span class="o">=</span> <span class="n">now</span> <span class="o">-</span> <span class="n">mStartTime</span><span class="o">;</span>
</span><span class='line'>            <span class="k">if</span> <span class="o">(</span><span class="n">duration</span> <span class="o">&gt;=</span> <span class="n">ANIMATION_DURATION</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>                <span class="n">mStartColor</span> <span class="o">=</span> <span class="n">mEndColor</span><span class="o">;</span>
</span><span class='line'>                <span class="n">mEndColor</span> <span class="o">=</span> <span class="n">randomColor</span><span class="o">();</span>
</span><span class='line'>                <span class="n">mStartTime</span> <span class="o">=</span> <span class="n">now</span><span class="o">;</span>
</span><span class='line'>                <span class="n">mCurrentColor</span> <span class="o">=</span> <span class="n">mStartColor</span><span class="o">;</span>
</span><span class='line'>            <span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
</span><span class='line'>                <span class="kt">float</span> <span class="n">fraction</span> <span class="o">=</span> <span class="n">duration</span> <span class="o">/</span> <span class="o">(</span><span class="kt">float</span><span class="o">)</span> <span class="n">ANIMATION_DURATION</span><span class="o">;</span>
</span><span class='line'>                <span class="c1">//@formatter:off</span>
</span><span class='line'>                <span class="n">mCurrentColor</span> <span class="o">=</span> <span class="n">Color</span><span class="o">.</span><span class="na">rgb</span><span class="o">(</span>
</span><span class='line'>                        <span class="n">evaluate</span><span class="o">(</span><span class="n">fraction</span><span class="o">,</span> <span class="n">Color</span><span class="o">.</span><span class="na">red</span><span class="o">(</span><span class="n">mStartColor</span><span class="o">),</span> <span class="n">Color</span><span class="o">.</span><span class="na">red</span><span class="o">(</span><span class="n">mEndColor</span><span class="o">)),</span>     <span class="c1">// red</span>
</span><span class='line'>                        <span class="n">evaluate</span><span class="o">(</span><span class="n">fraction</span><span class="o">,</span> <span class="n">Color</span><span class="o">.</span><span class="na">green</span><span class="o">(</span><span class="n">mStartColor</span><span class="o">),</span> <span class="n">Color</span><span class="o">.</span><span class="na">green</span><span class="o">(</span><span class="n">mEndColor</span><span class="o">)),</span> <span class="c1">// green</span>
</span><span class='line'>                        <span class="n">evaluate</span><span class="o">(</span><span class="n">fraction</span><span class="o">,</span> <span class="n">Color</span><span class="o">.</span><span class="na">blue</span><span class="o">(</span><span class="n">mStartColor</span><span class="o">),</span> <span class="n">Color</span><span class="o">.</span><span class="na">blue</span><span class="o">(</span><span class="n">mEndColor</span><span class="o">)));</span>  <span class="c1">// blue</span>
</span><span class='line'>                <span class="c1">//@formatter:on</span>
</span><span class='line'>            <span class="o">}</span>
</span><span class='line'>            <span class="n">scheduleSelf</span><span class="o">(</span><span class="n">mUpdater</span><span class="o">,</span> <span class="n">SystemClock</span><span class="o">.</span><span class="na">uptimeMillis</span><span class="o">()</span> <span class="o">+</span> <span class="n">FRAME_DURATION</span><span class="o">);</span>
</span><span class='line'>            <span class="n">invalidateSelf</span><span class="o">();</span>
</span><span class='line'>        <span class="o">}</span>
</span><span class='line'>    <span class="o">};</span>
</span><span class='line'><span class="o">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>I think the only interesting thing in this code is the method used to animate a color change. It consists of extracting each color component and animating these values and not the entire color.</p>

<p>I applied this <code>Drawable</code> to my <code>ActionBar</code> and boooom it was working! I was quite surprised and starting to investigate. After looking at the AOSP source code for the Jelly Bean MR1 release, I noticed the issue had been fixed by <a href="https://plus.google.com/107708120842840792570">Adam Powell</a> (an engineer at Google working on the UI toolkit) with <a href="https://github.com/android/platform_frameworks_base/commit/a7cc06d82e45918c37429a59b14545c6a57db4e4">a7cc06d</a>. The code is now as described below:</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="kd">public</span> <span class="kt">void</span> <span class="nf">setPrimaryBackground</span><span class="o">(</span><span class="n">Drawable</span> <span class="n">bg</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>    <span class="k">if</span> <span class="o">(</span><span class="n">mBackground</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="n">mBackground</span><span class="o">.</span><span class="na">setCallback</span><span class="o">(</span><span class="kc">null</span><span class="o">);</span>
</span><span class='line'>        <span class="n">unscheduleDrawable</span><span class="o">(</span><span class="n">mBackground</span><span class="o">);</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>    <span class="n">mBackground</span> <span class="o">=</span> <span class="n">bg</span><span class="o">;</span>
</span><span class='line'>    <span class="k">if</span> <span class="o">(</span><span class="n">bg</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="n">bg</span><span class="o">.</span><span class="na">setCallback</span><span class="o">(</span><span class="k">this</span><span class="o">);</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>    <span class="n">setWillNotDraw</span><span class="o">(</span><span class="n">mIsSplit</span> <span class="o">?</span> <span class="n">mSplitBackground</span> <span class="o">==</span> <span class="kc">null</span> <span class="o">:</span>
</span><span class='line'>            <span class="n">mBackground</span> <span class="o">==</span> <span class="kc">null</span> <span class="o">&amp;&amp;</span> <span class="n">mStackedBackground</span> <span class="o">==</span> <span class="kc">null</span><span class="o">);</span>
</span><span class='line'>    <span class="n">invalidate</span><span class="o">();</span>
</span><span class='line'><span class="o">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>The problem with this fix is it wasn&#8217;t available for pre-API 17 builds. So I came up with a pretty simple solution for pre-API 17: registering a custom <code>Drawable.Callback</code> and invalidating the <code>ActionBarContainer</code> repeatedly setting the same <code>Drawable</code> with the <code>ActionBar</code>&#8217;s <code>setBackgroundDrawable(Drawable)</code> method:</p>

<figure class='code'><figcaption><span>MainActivity.java  </span></figcaption>
 <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="kd">public</span> <span class="kd">class</span> <span class="nc">MainActivity</span> <span class="kd">extends</span> <span class="n">Activity</span> <span class="o">{</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">private</span> <span class="kd">final</span> <span class="n">Handler</span> <span class="n">mHandler</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Handler</span><span class="o">();</span>
</span><span class='line'>    <span class="kd">private</span> <span class="n">ColorAnimationDrawable</span> <span class="n">mActionBarBackground</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'>    <span class="nd">@Override</span>
</span><span class='line'>    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">onCreate</span><span class="o">(</span><span class="n">Bundle</span> <span class="n">savedInstanceState</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="kd">super</span><span class="o">.</span><span class="na">onCreate</span><span class="o">(</span><span class="n">savedInstanceState</span><span class="o">);</span>
</span><span class='line'>        <span class="n">setContentView</span><span class="o">(</span><span class="n">R</span><span class="o">.</span><span class="na">layout</span><span class="o">.</span><span class="na">main_activity</span><span class="o">);</span>
</span><span class='line'>
</span><span class='line'>        <span class="n">mActionBarBackground</span> <span class="o">=</span> <span class="k">new</span> <span class="n">ColorAnimationDrawable</span><span class="o">();</span>
</span><span class='line'>        <span class="k">if</span> <span class="o">(</span><span class="n">Build</span><span class="o">.</span><span class="na">VERSION</span><span class="o">.</span><span class="na">SDK_INT</span> <span class="o">&lt;</span> <span class="n">Build</span><span class="o">.</span><span class="na">VERSION_CODES</span><span class="o">.</span><span class="na">JELLY_BEAN_MR1</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>            <span class="n">mActionBarBackground</span><span class="o">.</span><span class="na">setCallback</span><span class="o">(</span><span class="n">mDrawableCallback</span><span class="o">);</span>
</span><span class='line'>        <span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
</span><span class='line'>            <span class="n">getActionBar</span><span class="o">().</span><span class="na">setBackgroundDrawable</span><span class="o">(</span><span class="n">mActionBarBackground</span><span class="o">);</span>
</span><span class='line'>        <span class="o">}</span>
</span><span class='line'>        <span class="n">mActionBarBackground</span><span class="o">.</span><span class="na">start</span><span class="o">();</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="nd">@Override</span>
</span><span class='line'>    <span class="kd">protected</span> <span class="kt">void</span> <span class="nf">onResume</span><span class="o">()</span> <span class="o">{</span>
</span><span class='line'>        <span class="kd">super</span><span class="o">.</span><span class="na">onResume</span><span class="o">();</span>
</span><span class='line'>        <span class="n">mActionBarBackground</span><span class="o">.</span><span class="na">start</span><span class="o">();</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="nd">@Override</span>
</span><span class='line'>    <span class="kd">protected</span> <span class="kt">void</span> <span class="nf">onPause</span><span class="o">()</span> <span class="o">{</span>
</span><span class='line'>        <span class="kd">super</span><span class="o">.</span><span class="na">onPause</span><span class="o">();</span>
</span><span class='line'>        <span class="n">mActionBarBackground</span><span class="o">.</span><span class="na">stop</span><span class="o">();</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">private</span> <span class="n">Drawable</span><span class="o">.</span><span class="na">Callback</span> <span class="n">mDrawableCallback</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Drawable</span><span class="o">.</span><span class="na">Callback</span><span class="o">()</span> <span class="o">{</span>
</span><span class='line'>        <span class="nd">@Override</span>
</span><span class='line'>        <span class="kd">public</span> <span class="kt">void</span> <span class="nf">invalidateDrawable</span><span class="o">(</span><span class="n">Drawable</span> <span class="n">who</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>            <span class="n">getActionBar</span><span class="o">().</span><span class="na">setBackgroundDrawable</span><span class="o">(</span><span class="n">who</span><span class="o">);</span>
</span><span class='line'>        <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>        <span class="nd">@Override</span>
</span><span class='line'>        <span class="kd">public</span> <span class="kt">void</span> <span class="nf">scheduleDrawable</span><span class="o">(</span><span class="n">Drawable</span> <span class="n">who</span><span class="o">,</span> <span class="n">Runnable</span> <span class="n">what</span><span class="o">,</span> <span class="kt">long</span> <span class="n">when</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>            <span class="n">mHandler</span><span class="o">.</span><span class="na">postAtTime</span><span class="o">(</span><span class="n">what</span><span class="o">,</span> <span class="n">when</span><span class="o">);</span>
</span><span class='line'>        <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>        <span class="nd">@Override</span>
</span><span class='line'>        <span class="kd">public</span> <span class="kt">void</span> <span class="nf">unscheduleDrawable</span><span class="o">(</span><span class="n">Drawable</span> <span class="n">who</span><span class="o">,</span> <span class="n">Runnable</span> <span class="n">what</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>            <span class="n">mHandler</span><span class="o">.</span><span class="na">removeCallbacks</span><span class="o">(</span><span class="n">what</span><span class="o">);</span>
</span><span class='line'>        <span class="o">}</span>
</span><span class='line'>    <span class="o">};</span>
</span><span class='line'>
</span><span class='line'><span class="o">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>Thanks to this trick, you can now animate your ActionBar&#8217;s background back to API 11 but please keep in mind this may have several and sometimes serious consequences on your application:</p>

<ul>
<li><p>It can make your application look different and more polished by featuring tiny, subtle and nice details</p></li>
<li><p>When setting an animated background to an <code>ActionBar</code>, always make sure it is as subtle as possible. Animations should not distract or interrupt the user in his/her interactions with your app. For instance you could run the animation only when the user is not touching your <code>Activity</code>.</p></li>
<li><p>Using the technique described in this article forces the system to invalidate the whole <code>ActionBarContainer</code> for each animation frame. Reduce the duration of your animation as much as possible as it can be CPU &amp; GPU consuming</p></li>
<li><p>The animated background <code>Drawable</code> should not be something essential to your app. <code>Drawable</code> should only be considered as styling component and not interaction components.</p></li>
</ul>


<div class="embed-video-container"><iframe src="http://www.youtube.com/embed/ANmeW0VKyPQ "></iframe></div>


<hr />

<ol>
<li>I could write an entire book chapter about the <code>Drawable</code> notion. Put simple, when setting a <code>Drawable</code> as a <code>View</code> background, the <code>View</code> registers itself as the Drawable&#8217;s callback. This let the <code>Drawable</code> invalidate the <code>View</code> it is attached to. In other words, it lets you create <code>Drawable</code>s that can refresh/redraw themselves. Android experts will also say it lets you easily leak <code>Context</code>s when keeping a static reference to a <code>Drawable</code>.</li>
</ol>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Meet Polaris, a Map Library for Android]]></title>
    <link href="http://cyrilmottier.com/2012/10/12/meet-polaris-a-map-library-for-android/"/>
    <updated>2012-10-12T00:00:00+02:00</updated>
    <id>http://cyrilmottier.com/2012/10/12/meet-polaris-a-map-library-for-android</id>
    <content type="html"><![CDATA[<p>It&#8217;s been almost three years since Google last updated the Google Maps framework for Android. As you all know, this external library can be used to integrate map-related features into your applications. Unfortunately, in addition to getting old, this framework also suffers from a lot of limitations. I&#8217;ve recently spent a lot of time working on a map-based application of mine called <a href="https://play.google.com/store/apps/details?id=com.cyrilmottier.android.avelov">AVélov</a> and encountered a lot of issues while developing it. To make my life easier (as well as yours), I started creating a library with highly reusable components.</p>

<p><a href="http://cyrilmottier.com/media/2012/10/meet-polaris-a-map-library-for-android/polaris_large.png"><img class="center" src="http://cyrilmottier.com/media/2012/10/meet-polaris-a-map-library-for-android/polaris.png"></a></p>

<!-- More -->


<p>I am pleased to announce Polaris: a brand new map library that completely rethinks the way you use <code>MapView</code> in your application. Polaris&#8217; philosophy is based on 3 main rules:</p>

<ul>
<li>Make the user&#8217;s life easier</li>
<li>Make the developer&#8217;s life easier</li>
<li>Make the resulting map look polished and natural</li>
</ul>


<p><img class="center" src="http://cyrilmottier.com/media/2012/10/meet-polaris-a-map-library-for-android/polaris_logo.png"></p>

<p>Prior to giving you some details about the library and what it can do, here are all of the resources you can use to download and test the library:</p>

<ul>
<li><strong>Library</strong>: <a href="https://www.github.com/cyrilmottier/Polaris">github.com/cyrilmottier/Polaris</a></li>
<li><strong>Sample app</strong>: <a href="https://play.google.com/store/apps/details?id=com.cyrilmottier.android.polarissample">PolarisSample on Google Play</a></li>
</ul>


<p>In practice, the Polaris library is an extension of the Google Maps External Library that fills some important gaps. For instance, it provides a lot of amazingly useful and powerful additions to the regular <code>MapView</code>. Here is a short (but still incomplete) list of some of the features supported by the Polaris library:</p>

<h2>Gesture support</h2>

<p>One of the major drawbacks of <code>MapView</code> is the lack of support for basic gestures such as the well-known double tap to zoom. Not providing developers with a gestures-enabled map reduces consistency among map-based application. Users usually expect all <code>MapView</code> to supply at least the exact same set of gestures regardless of the application being used. As a consequence, having <code>MapView</code>s not recognizing the gestures supported by the built-in Maps application can greatly frustrate users.</p>

<p>Polaris automatically handles essential gestures. The list below gives you an exhaustive catalogue of the available gestures as of version 1.0:</p>

<ul>
<li><strong>Single tap on map</strong>: opens, if necessary, the callout associated to the tapped marker</li>
<li><strong>Double tap on map</strong>: zooms in focusing on the tapped location</li>
<li><strong>Long press on map</strong>: does nothing by default. Clients may assign a <code>OnMapViewLongClickListener</code> to the <code>PolarisMapView</code> to be notified of long presses</li>
<li><strong>Double tap on map callout</strong>: zooms in and pans to the maximum level of detail available</li>
</ul>


<h2>Effortless map annotating</h2>

<p><code>PolarisMapView</code> drastically simplifies addition of markers to a <code>MapView</code> by getting rid of the <code>ItemizedOverlay</code> (at least from a developer point of view) and introducing <code>Annotation</code>s. <code>Annotation</code> is an extension of <code>OverlayItem</code> containing map-related information such as coordinates of a point, a title, a snippet and an optional marker Drawable. Annotating a <code>PolarisMapView</code> consists on building a list of <code>Annotation</code>s and adding it to the map with the <code>setAnnotations(List, int)</code> or <code>setAnnotations(List, Drawable)</code> method. To sum up it only requires a few lines of code to annotate your map:</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="c1">// Create a new list of Annotations</span>
</span><span class='line'><span class="n">List</span><span class="o">&lt;</span><span class="n">annotation</span><span class="o">&gt;</span> <span class="n">annotations</span> <span class="o">=</span> <span class="k">new</span> <span class="n">ArrayList</span><span class="o">&lt;</span><span class="n">annotation</span><span class="o">&gt;();</span>
</span><span class='line'><span class="n">annotations</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="k">new</span> <span class="n">Annotation</span><span class="o">(</span><span class="k">new</span> <span class="n">GeoPoint</span><span class="o">(),</span> <span class="s">&quot;Paris&quot;</span><span class="o">,</span> <span class="s">&quot;The city of love&quot;</span><span class="o">));</span>
</span><span class='line'>
</span><span class='line'><span class="c1">// Set the Annotations to the PolarisMapView</span>
</span><span class='line'><span class="n">mPolarisMapView</span><span class="o">.</span><span class="na">setAnnotations</span><span class="o">(</span><span class="n">annotations</span><span class="o">,</span> <span class="n">R</span><span class="o">.</span><span class="na">drawable</span><span class="o">.</span><span class="na">default_marker</span><span class="o">);</span>
</span></code></pre></td></tr></table></div></figure>


<p>One of the main advantage of using <code>Annotation</code>s over <code>OverlayItem</code> is map callouts are automatically managed for you. Indeed, out of the box, the <code>OverlayItem</code> contains two <code>String</code>s: a title and a snippet. Unfortunately, no matter how hard you search into the documentation, you will notice these <code>String</code>s are <strong>never ever</strong> used! <code>PolarisMapView</code> automatically displays a map callout when the underlying annotation is tapped which makes map annotating insanely easy.</p>

<h2>Map callout variable anchor positioning</h2>

<p>Most (or should I say all) map-based applications uses 9-patches as map callout backgrounds. While 9-patches are great in most cases, they don&#8217;t allow variable stretching of the stretchable areas. As a consequence, it is not possible to make a map callout which positions an arrow depending on the position of the point of interest. Polaris includes a <code>MapCalloutDrawable</code> which allows variable positioning of the anchor.</p>

<p><img class="center" src="http://cyrilmottier.com/media/2012/10/meet-polaris-a-map-library-for-android/variable_anchor_positioning.png"></p>

<p>This improvement is largely used by the Polaris library to get a more polished map. Indeed, while third-party applications usually center the map on the tapped <code>OverlayItem</code>, and the Maps app scrolls to make the callout entirely visible, <code>PolarisMapView</code> shows map callouts trying to reduce map scrolls as much as possible.</p>

<p><img class="center" src="http://cyrilmottier.com/media/2012/10/meet-polaris-a-map-library-for-android/auto_map_callout_1.png"></p>

<p><img class="center" src="http://cyrilmottier.com/media/2012/10/meet-polaris-a-map-library-for-android/auto_map_callout_2.png"></p>

<h2>Built-in &#8220;user tracking&#8221; mode</h2>

<p>In order to track the user location, The Google Maps external library provides a dedicated <code>Overlay</code> call <code>MyLocationOverlay</code>. This overlay displays a tiny blinking blue dot surrounding by a translucent blue disc describing the accuracy of the fix. Unfortunately, this <code>Overlay</code> is just an indication of the user location. There absolutely is no way to interact with it. <code>PolarisMapView</code> greatly enhances, while still simplifing, user tracking. With only one call to <code>setUserTrackingEnabled(true)</code>, the Polaris library starts tracking the user location and displays a button similar to the one in the Maps application. When clicked this button centers the map on the user&#8217;s location.</p>

<p><img class="center" src="http://cyrilmottier.com/media/2012/10/meet-polaris-a-map-library-for-android/built_in_user_tracking.png"></p>

<h2>Automatic built-in zoom controls</h2>

<p>Android can run on a large diversity of devices. Nowadays, the vast majority of these devices support multi-touch gestures. However, there are still some others that don&#8217;t (especially lower-end devices). <code>PolarisMapView</code> seamlessly displays zoom controls only when required. It relieves the developer of the burden of checking the hardware capabilities of the device while maximizing the visible portion of the map on modern devices by hiding useless controls.</p>

<h2>Natural map callouts transitions</h2>

<p><code>PolarisMapView</code> animates all transitions when showing and/or dismissing map callouts. Making a demonstration of the animation in a blog post is obviously not possible so I highly suggest to you to look at the PolarisSample app. Animated transitions results in a more natural and more polished map callout rendering.</p>

<h2>Additional listeners</h2>

<p>The default Google Maps External Library is cruelly lacking of listeners notifying the developer when the current state of the map has changed. For instance, there is no way to listen to changes on the visible region of the map (i.e. when the map has been zoomed and/or panned). Polaris includes additional listeners such as the <code>OnRegionChangedListener</code>. It can be particularly useful in order to lazy load annotations depending on the currently visible region.</p>

<p>As you can easily imagine, <code>PolarisMapView</code> relies on <code>MapView</code> while trying to be as transparent as possible. As a consequence, <code>PolarisMapView</code> offers the exact same features <code>MapView</code> offers and also suffers from some bugs related to the Google Maps external library. However there is a limitation when adding <code>Overlay</code>s to the <code>PolarisMapView</code>. You <strong>must not</strong> use the <code>getOverlays()</code> method in <code>MapView</code><sup>1</sup> and use the <code>addOverlay(Overlay)</code>, <code>removeOverlay(Overlay)</code> and similar methods instead. Moreover, you need to bind the <code>onStart()</code> and <code>onStop()</code> to your <code>MapActivity</code> equivalents. These methods are necessary to notify the <code>PolarisMapView</code> of the <code>MapActivity</code> lifecycle.</p>

<p>I really hope you will love the features and principles introduced in this first version of the Polaris library. Please keep in mind, you can obvisouly use it in your projects but you can also help the project submitting pull requests on GitHub. If you release an app that uses Polaris I would love to hear about it. Please contact me via <a href="http://twitter.com/cyrilmottier">Twitter</a>, <a href="https://plus.google.com/118417777153109946393">Google+</a>, or <a href="mailto:cyril@cyrilmottier.com">email</a>.</p>

<p>Thanks to <a href="https://twitter.com/franklinharper">@franklinharper</a> for reading drafts of this and <a href="http://marie-schweiz.de/">Marie Schweiz</a> for designing the Polaris icon</p>

<hr />

<ol>
<li>There is no way to by-pass this limitation due to the fact <code>MapView</code> makes the <code>getOverlays()</code> final.</li>
</ol>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Google Maps Graphic Assets PSD]]></title>
    <link href="http://cyrilmottier.com/2012/09/18/google-maps-graphic-assets-psd/"/>
    <updated>2012-09-18T00:00:00+02:00</updated>
    <id>http://cyrilmottier.com/2012/09/18/google-maps-graphic-assets-psd</id>
    <content type="html"><![CDATA[<p>In a <a href="http://www.cyrilmottier.com/2012/07/11/creating-professional-looking-screenshots/">previous article</a> I shared some designer resources to help you create stunning and professional looking screenshots. This time, I wanted to share some of the resources I recently created as part of a project of mine named AVélov. Put simple, AVélov is an application I develop that lets you determine the availability of slots/bikes in the city of Lyon, France. I recently released it so you can download it on the <a href="https://play.google.com/store/apps/details?id=com.cyrilmottier.android.avelov">Google Play Store</a>, play with it and send me your feedbacks.</p>

<p>As you can imagine, AVélov heavily rely on the Google Maps External Library. This library lets you easily add mapping capabilities to your application. Unfortunately it is far from being perfect. It doesn&#8217;t support vector graphics, you can&#8217;t use the new animation framework to create custom map animations, you can&#8217;t have several <code>MapActivity</code> per process, <code>MapActivity</code> can contain one and only one <code>MapView</code>, <code>MapView</code> instantiation outside of a <code>MapActivity</code> is impossible, <code>MapView</code> doesn&#8217;t support some fundamental gestures such as &#8220;double tap to zoom&#8221;, <code>MapView</code> zooming gestures are completely buggy sometimes, etc. In other terms, the current Google Maps Android framework is far from what we could expect from a world-class mapping actor like Google.</p>

<!-- More -->


<p>Google not releasing a new version of the Google Maps framework was the biggest disappointment I had at Google I/O this year. This framework hasn&#8217;t been updated for years and is now pretty outdated. But there is a good news. Lots of developers at Google I/O asked what Google was doing to solve that issue. The answer was pretty simple and straightforward but also so vague at the same time: &#8220;We are working on it!&#8221;.</p>

<p>Another annoying flaw of the Google Maps External Library is the lack of default resources. Let&#8217;s imagine you want to add pins and bubbles to your map - which is what you want to do 99% of the time - you&#8217;ll have to create graphics resources from scratch. Providing default resources helps developers with no particular design-skills to create nice-looking maps and improve design consistency through applications.</p>

<p>As a consequence, while working on AVélov, I recreated the latest1 official Google Maps main screen. I made it using the xhdpi density so that you can easily downscale it to the appropriate density.</p>

<p><img class="center" src="http://cyrilmottier.com/media/2012/09/google-maps-graphic-assets-psd/google_maps_assets_preview.png" title="Preview of the Google Maps PSD" ></p>

<p>I also spent some time ensuring the resulting PSD contains only vector-based elements and is sensibly layered, named and grouped. In other words, the PSDs provided in this post respects a certain hygiene, all of your mobile-design-dedicated PSDs should respect.</p>

<p>The PSD below have been created with Photoshop CS6 but should work properly with all recent versions of CS. Also note the following resources are licensed under the CC BY 3.0:</p>

<p><button class="download-button" onclick="window.location='/media/2012/09/google-maps-graphic-assets-psd/google_maps_assets.zip';"><span class="icon"></span><span class="title">Google Maps Assets PSD</span></button></p>

<p>I really hope you&#8217;ll find this PSD useful in your <code>MapView</code>-based applications.</p>

<p>1The latest release of Google Maps have tweaked bubbles. Previous releases were based on rounded corners while they have now been squared. AVélov 1.0.1 contains the old version of the bubbles but will soon take advantage of the resources provided in this article as well as a <code>MapView</code>-related framework I&#8217;ve been working on. And yep, you can consider this spoiler as a teaser to an incoming new library.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Doing the Photoshopping]]></title>
    <link href="http://cyrilmottier.com/2012/08/07/doing-the-photoshopping/"/>
    <updated>2012-08-07T00:00:00+02:00</updated>
    <id>http://cyrilmottier.com/2012/08/07/doing-the-photoshopping</id>
    <content type="html"><![CDATA[<p>I guess you all have noticed, just like I did, that the Android community have been keeping a low profile for the past few weeks. I assume lots of developers are on vacation and I can&#8217;t blame them! I will soon take a well deserved two-week break too. Prior leaving, I wanted to share some new helpful graphic resources I recently made.</p>

<p>In a <a href="http://www.cyrilmottier.com/2012/07/11/creating-professional-looking-screenshots/">previous article</a> of mine I explained how important it is to create stunning and pixel-perfect screenshots. I gave several Photoshop resources you can use to create professional looking screenshots. Unfortunately, the pack had a lack of landscape resources. I am proud to tell you I have fixed this mistake and I am sharing the new resources to you. Here is the new zip file containing all of the PSDs:</p>

<!-- More -->


<p><button class="download-button" onclick="window.location='/media/2012/08/doing-the-photoshopping/android_screenshots_assets.zip';"><span class="icon"></span><span class="title">Android Screenshots Assets</span></button></p>

<p>The zip above contains four PSDs you can use to create professional looking Android screenshots:</p>

<ul>
<li><p><strong>Device framed screenshot</strong></p>

<ul>
<li>Landscape: <em>android_device_frame_land.psd</em></li>
<li>Portrait: <em>android_device_frame_port.psd</em></li>
</ul>
</li>
<li><p><strong>Basic screenshot</strong></p>

<ul>
<li>Landscape: <em>android_screenshot_land.psd</em></li>
<li>Portrait: <em>android_screenshot_port.psd</em></li>
</ul>
</li>
</ul>


<p>In order to follow the adage &#8220;A picture is worth a thousand words&#8221;, you will find below some sample screenshots generated using the resources:</p>

<p><img class="center" src="http://cyrilmottier.com/media/2012/08/doing-the-photoshopping/android_device_frame_land.png" title="Landscape device-framed screenshot" ></p>

<p><img class="center" src="http://cyrilmottier.com/media/2012/08/doing-the-photoshopping/android_device_frame_port.png" title="Portrait device-framed screenshot" ></p>

<p>All of the resources given in this post are available under the <a href="http://creativecommons.org/licenses/by/3.0/">Creative Commons BY 3.0</a> license. Feel free to use these PSD wherever and whenever you want to demonstrate and promote your applications in blogs, social networks, newsletters and conferences!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[The Making of Prixing #4: In-layout Notifications]]></title>
    <link href="http://cyrilmottier.com/2012/07/24/the-making-of-prixing-4-activity-tied-notifications/"/>
    <updated>2012-07-24T00:00:00+02:00</updated>
    <id>http://cyrilmottier.com/2012/07/24/the-making-of-prixing-4-activity-tied-notifications</id>
    <content type="html"><![CDATA[<p>In the three preceding articles, I talked about the fly-in application menu and how to implement it on Android. For those who want to catch up on the Making of Prixing series, here are the links:</p>

<ul>
<li><a href="http://www.cyrilmottier.com/2012/05/22/the-making-of-prixing-fly-in-app-menu-part-1/">The making of Prixing #1: Fly-in app menu</a></li>
<li><a href="http://www.cyrilmottier.com/2012/05/29/the-making-of-prixing-2-swiping-the-fly-in-app-menu/">The making of Prixing #2: Swiping the fly-in app menu</a></li>
<li><a href="http://www.cyrilmottier.com/2012/06/08/the-making-of-prixing-3-polishing-the-sliding-app-menu/">The making of Prixing #3: Polishing the sliding app menu</a></li>
</ul>


<p>This time, I would like to talk about the way we&#8217;ve managed notifications in Prixing 3.0. Indeed, Prixing for Android is a rather complex application containing tons of screens. Each of these screens can notify the user about something important: an error occurred while connecting to the server, you earned a new badge, the query you typed is too short, etc. By default, Android provides two great ways to notify the user without blocking: status bar notifications and <code>Toast</code>s. The first  is dedicated to notifications happening outside of the application while the latter is for in-app notifications. Simply put, a <code>Toast</code> is a non intrusive and non touchable notification that is always displayed on top of your application&#8217;s screens.</p>

<!-- More -->


<p><img class="center" src="http://cyrilmottier.com/media/2012/07/the-making-of-prixing-4-activity-tied-notifications/toast_default_appearance.png" title="Default appearance of a Toast as of Android 4.1" ></p>

<p>From my point of view, this class is amazing. I really love it and that&#8217;s probably one of the reason why I am getting so frustrated when developing on iOS. Indeed, the platform made by Apple has no equivalent by default. Developers generally use a <code>UIAlertView</code> (iOS <code>AlertDialog</code> equivalent) which is extremely annoying to the user as it completely blocks the user flow as long as one of the &#8220;Cancel&#8221; or &#8220;OK&#8221; buttons hasn&#8217;t been pressed. As a consequence, iOS developers tend to notify the user via in-layout notifications. It is not consistent throughout iOS apps but the usability gain definitely worth it. <code>Toast</code> makes unobstrusive notifications amazingly easy as you can create new instances from everywhere as long as you have a reference to a <code>Context</code> (<code>Service</code>, <code>Activity</code>, <code>BroadcastReceiver</code>&#8217;s <code>onReceive</code> method, etc.).</p>

<p>Unfortunately, Toast is far from being perfect and I am not entirely satisfied with it. Toast can be un-accurate in some cases. Indeed, <code>Toast</code> has one major drawback: it completely breaks contexts. This issue can be reproduced effortless. Let&#8217;s say a user is currently in an app firing a <code>Toast</code> and wants to switch to another application using the dedicated &#8220;multitask&#8221; button. The Toast will remain on screen even if the brought-to-front application has nothing do to with the previously shown app as described on the following figure:</p>

<p><a href="http://cyrilmottier.com/media/2012/07/the-making-of-prixing-4-activity-tied-notifications/toast_user_flow_fail_large.png"><img class="center" src="http://cyrilmottier.com/media/2012/07/the-making-of-prixing-4-activity-tied-notifications/toast_user_flow_fail.png" title="Sample of user flow in which Toast fails" ></a></p>

<p>Sample of a user flow in which Toast fails</p>

<p>As you can easily notice, the problem with <code>Toast</code>s is they are persistent1. Once a Toast has been fired, it is displayed on top of any screen and remains visible for the duration specified at its creation.</p>

<h3>Information is always context-related</h3>

<p>When designing and developing an app, you always have to spend a lot of time thinking about contexts. Contexts are insanely important as they define the space/time frame an information can live in. Exposing information in the wrong context will make your UI incomprehensive and will radically degrade your users&#8217; experience. Can you imagine Google announcing a new Android version in the middle of the annual world dental congress? I guess and hope your anwser is no. This example clearly demonstrates information and context are close and depend on each other.</p>

<p>As of this logic, Prixing currently features 3 main contexts:</p>

<ul>
<li><strong>The application context</strong> is where images and network data live in. All of this information is not tied to a particular screen or widget and are shared among all Prixing&#8217;s screens.</li>
<li><strong>The Activity context</strong> contains the information belonging to a screen (profile, nearby stores, products list, etc.).</li>
<li><strong>The application menu context</strong>: Introduced by the fly-in app menu, the application menu context describes the entire app navigation. It is completely independent from the two previous contexts.2</li>
</ul>


<p>In order to bypass the <code>Toast</code> persistence problem and ensure information is displayed in the correct context, we decided to create a new notification system in Prixing: <code>Activity</code>-bound notifications. In reference to the <code>Toast</code> class and to my French culture I decided to name it a <code>Crouton</code> (if you don&#8217;t know what a Crouton is go to this <a href="http://en.wikipedia.org/wiki/Crouton">Wikipedia page</a>). This is what it looks like in the current version of Prixing:</p>

<p><a href="http://cyrilmottier.com/media/2012/07/the-making-of-prixing-4-activity-tied-notifications/in_layout_notification_large.png"><img class="center" src="http://cyrilmottier.com/media/2012/07/the-making-of-prixing-4-activity-tied-notifications/in_layout_notification.png" title="Example of an 'alert' Crouton in Prixing" ></a></p>

<p><code>Crouton</code> overcomes the main issue of having a <code>Toast</code> being shown while the menu is open. It sticks to the current screen sliding with it and leaving the menu completely free of any information that would have not been related to it.</p>

<h3>Introducing the Crouton API</h3>

<p>The Android framework lets you interact with the <code>Toast</code> class via a very simple API. You usually only need a single line of code to create and show a notification. We wanted <code>Crouton</code> to be at least as easy to use as the <code>Toast</code> class so we engineered an insanely simple API:</p>

<ul>
<li>Public Constants

<ul>
<li><code>int STYLE_ALERT</code>: Show the text notification for a long period of time with a negative style.</li>
<li><code>int STYLE_CONFIRM</code>: Show the text notification for a short period of time with a positive style.</li>
<li><code>int STYLE_INFO</code>: Show the text notification for a short period of time with a neutral style.</li>
</ul>
</li>
<li>Public Methods

<ul>
<li><code>static Crouton makeText(PrixingActivity prixingActivity, CharSequence text, int style)</code>: Make a Crouton with the given text and style.</li>
<li><code>static Crouton makeText(PrixingActivity prixingActivity, int resId, int style)</code>: Make a Crouton with the given text (extracted from the resource identifier) and style.</li>
<li><code>void show()</code>: Show the view with the specified style.</li>
</ul>
</li>
</ul>


<p>Yes, you&#8217;re right! No visible constructors, just 2 static factory methods, a public method and 3 constants. The two main differences with <code>Toast</code> are you always need a <code>PrixingActivity</code> instead of a <code>Context</code> and the third parameter isn&#8217;t the duration but the style of the notification.</p>

<p>Contrary to the <code>Toast</code> class, <code>Crouton</code> automatically computes the duration of the notification depending on the style. Pretty logically, we decided an alert notification had to be visible for a larger amount of time than a confirmation or neutral information. People usually spend more time on understanding an issue than a validation message. As a result, we decided to use 3000 milliseconds instead of 1300 milliseconds.</p>

<p><a href="http://cyrilmottier.com/media/2012/07/the-making-of-prixing-4-activity-tied-notifications/crouton_types_large.png"><img class="center" src="http://cyrilmottier.com/media/2012/07/the-making-of-prixing-4-activity-tied-notifications/crouton_types.png" title="The three types of Croutons and their respective UI" ></a></p>

<p><code>Crouton</code> handles multiple notifications fired at the same time just like <code>Toast</code> does. In order to do so, it stacks <code>Crouton</code>s in a queue if another instance is currently being displayed. This makes sure no notification is lost as long as the user remains on the emitting <code>Activity</code></p>

<h3>Implementing <em>in-layout</em> notifications</h3>

<p>The Android framework contains several classes inheriting from <code>Activity</code>. Each of this <code>Activity</code>-subclasses can be used to manage particular components. For instance, <code>ListActivity</code> manages a <code>ListView</code>, <code>FragmentActivity</code> manages <code>Fragment</code>s and <code>Loader</code>s, <code>MapActivity</code> manages <code>MapView</code>, etc. All of these subclasses may look helpful for developers but they can also be a pain in the ass when engineering a rather large project. Java not allowing multiple inheritance and not supporting categories/extension methods (yet?) makes it pretty boring and tedious to add features to Activity-subclasses. As a direct consequence, trying to have a consistent layout in your Activity is hard. So here is a tiny advice to you: always favor composition over inheritance in your projects.</p>

<p>To overcome this issue, all Prixing <code>Activity</code> implements an interface called <code>PrixingActivity</code>. Roughly speaking, <code>PrixingActivity</code> manages several <code>Activity</code>-based behaviors and ensures the Activity root layout is as follows:</p>

<p><img class="center" src="http://cyrilmottier.com/media/2012/07/the-making-of-prixing-4-activity-tied-notifications/view_hierarchy.png" title="The base View hierarchy of a PrixingActivity" ></p>

<p>As described on the previous figure, a <code>PrixingActivity</code> always contains a <code>TextView</code> which is laid out by our custom <code>TitleBarHost</code> in a way it is above the <code>TitleBar</code> (custom implementation of the <code>ActionBar</code>) and slides down when the notification needs to be shown.</p>

<p>To have consistent and smooth animations, we used the same interpolator introduced in the first part of this serie when showing/hiding a <code>Crouton</code>: the <code>SmoothInterpolator</code>.</p>

<p>Finally, some of you may wonder why the notification is not lazily created/inflated thanks to a <code>ViewStub</code>. <code>Crouton</code> currently relies on a single <code>TextView</code>. Using a <code>ViewStub</code> is clearly not a performance boost in this case as the final <code>View</code> hierarchy is small. Keep in mind a <code>ViewStub</code> remains a <code>View</code>. As a result, using a <code>ViewStub</code> would have resulted in inflating 1-min or 2-max <code>View</code>. The method used in Prixing ensures only a single <code>TextView</code> is inflated. If you really care about not creating a <code>TextView</code> that is often never used, you can lazy-create it the first time it is requested.</p>

<p>In-layout notifications may not be perfect but they can solve lots of UI/UX problems. Implementing such a mechanism in Prixing made the application easier to use and more logical. The fly-in app menu clearly outlined some of the major drawbacks of the <code>Toast</code>, <code>Crouton</code> solved. Don&#8217;t use <code>Toast</code> blindly, think about your application&#8217;s context and the information you need to display. In other words: leave the engineering mindset aside and start thinking like a real user.</p>

<p>Thanks to <a href="http://twitter.com/#!/franklinharper">@franklinharper</a> for reading drafts of this.</p>

<hr />

<ol>
<li><p>A Toast is actually theoritacally persistent if and only if you don&#8217;t call <code>Toast#cancel()</code>. In practice, nobody keeps a reference on the fired <code>Toast</code>, the <code>Toast#cancel()</code> documentation clearly states it shouldn&#8217;t be used and, last but not least, the current <code>Toast#cancel()</code> implementation contains a magnificent <code>// TODO</code> annotation informing the method is not complete:</p>

<pre><code> // TODO this still needs to cancel the inflight notification if any
</code></pre></li>
<li><p>Contexts are everything! This is I why I believe an <code>ActionBar</code> has to slide with the content when using a fly-in app menu. An <code>ActionBar</code> should only be used to describe the current screen/<code>Activity</code> context. As a result it has nothing to do with the application menu. The current version of Prixing, Google+, Spotify, etc. have it right while some others such as Youtube have it wrong in my opinion.</p></li>
</ol>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Creating Professional Looking Screenshots]]></title>
    <link href="http://cyrilmottier.com/2012/07/11/creating-professional-looking-screenshots/"/>
    <updated>2012-07-11T00:00:00+02:00</updated>
    <id>http://cyrilmottier.com/2012/07/11/creating-professional-looking-screenshots</id>
    <content type="html"><![CDATA[<p><em><strong>Note</strong>: This article can be seen as the continuation of a previous article of mine entitled <a href="http://www.cyrilmottier.com/2011/12/01/please-guys-pay-attention-to-detail/">Please guys, pay attention to detail!</a>. In this article I explained why details matter and how graphic resources must be created meticulously as they reflect your product in the outside world. Once again I used the same Google product, the Galaxy Nexus, because I&#8217;m quite familiar to it - in other words this is the device I have in my pocket. As a consequence, I&#8217;d like to start with the exact same disclaimer: this article is not specifically targeted to Google nor the Galaxy Nexus. It obviously has to be read in a more global manner. I&#8217;m sure a booster shot won&#8217;t hurt anybody!</em></p>

<p>Let&#8217;s start this article with a quote I love from <a href="http://fr.wikipedia.org/wiki/John_Wooden">John Wooden</a>, a former basketball player and coach. Reading the following lines, you will easily notice this quote perfectly fits this article&#8217;s subject:</p>

<blockquote><p>It&#8217;s the little details that are vital.<br/>Little things make big things happen.</p><footer><strong>John Wooden</strong></footer></blockquote>




<!-- More -->


<p>Last week, I spent three amazing days at the Moscone Center in San Francisco, CA for the Google IO. Let&#8217;s be honest, this conference is clearly one of the best I have participated in so far. I saw insanely great sessions about various subjects and met very interesting people from Google or other well-known international companies. This year, Google IO focused on mobile and especially Android. As a result, keynotes and sessions was using a lot of images from mobile devices. Unfortunately, as a perfectionist, I was pretty disappointed about some of the graphics. Indeed, a lot of them were untidy, non professional, draft-looking, etc. The worst examples of this happened during the Google+ keynote. It featured some screenshots in which the screen glare was only visible on the device and not on the screenshot itself. I also saw an iPhone in which the screenshot of the application had been applied directly on top of the launcher app. This resulted in a translucent status bar with the background of the launcher which is obviously impossible in real life.</p>

<p>I recently decided to visit the new <a href="http://www.google.com/nexus/#/galaxy">Nexus website</a> and discovered some similar issues that could have been easily solved. Here are some of them:</p>

<ul>
<li>The time displayed on screen is different from the one in the status bar. I guess this is because the designer reused graphics from the ICS release and only changed the status bar. Unfortunately, this huge mistake transforms Android to a crappy platform that can&#8217;t even display the current time correctly</li>
</ul>


<p><img class="center" src="http://cyrilmottier.com/media/2012/07/creating-professional-looking-screenshots/time_mismatch.png"></p>

<ul>
<li>The disrupted/missing screen glare is probably one of the biggest mistakes I am used to seeing out there. Compared to the previous picture, this screenshot is far from looking professional. It gives the impression the screenshot has been glued to the device frame. There&#8217;s is also a more-difficult-to-notice issue on the status bar as it is smaller than it should. I seriously believe the designer used a screenshot from a Nexus 7 tablet and applied it to the Galaxy Nexus thinking nobody would notice the difference between 800x1280 and 720x1280.</li>
</ul>


<p><img class="center" src="http://cyrilmottier.com/media/2012/07/creating-professional-looking-screenshots/missing_glare.png"></p>

<ul>
<li>Blurry screenshots waste your product. Be careful when resizing an image and ensure the resize algorithm you use makes the final graphics crisp and sharp. Moreover, the background they used indicate a Jelly Bean release while the displayed time is at 4:00 (ICS). Try to remain logical: if you decided to change the displayed time then follow your own rules and stick to them.</li>
</ul>


<p><img class="center" src="http://cyrilmottier.com/media/2012/07/creating-professional-looking-screenshots/blur_wrong_time.png"></p>

<p>Lots of people think of me as a mobile developer but I am also a huge fan of pixel perfect graphics and applications. As a result I spend at least 15% of my time working on software like Photoshop or Illustrator. I am strongly convinced being a developer doesn&#8217;t mean you can&#8217;t like great things. As a developer you are not supposed to do your designer&#8217;s work but should be multi-skilled enough to handle situations where some design tasks are required. For example, it may be quite handy sometimes to know how to create resources to create a <code>Button</code> or style the background of your <code>ActionBar</code>.</p>

<p>Taking care of the resources you make public is extremely important as it reflects you and your product. When managing a product you always have to have a fine-grained control over the information you release. Screenshots are particularly important as they can carry tons of information. As a developer, you can think of releasing graphic resources as releasing a new API: everything that has been made public is visible and usable by everybody. You will have no opportunity to change it in the future without breaking what has been built on top. Moreover, using inappropriate graphic resources may completely make your product presentation pointless. One of the best recent example I have in mind is the announcement of the existence of the Higgs boson. The CERN team decided to use the Comic Sans MS font on web-from-the-90s-looking slides (cf <a href="http://www.theverge.com/2012/7/4/3136652/cern-scientists-comic-sans-higgs-boson">The Verge</a>). From my point of view, the poor quality of the presentation (obviously I am not talking about the content of the presentation itself) totally ruined the actual revelation of the announcement. People almost talked more about how crappy the slides were instead of the amazing announcement of the Higgs boson existence:</p>

<p><img class="center" src="http://cyrilmottier.com/media/2012/07/creating-professional-looking-screenshots/higgs_boson_slide.png"></p>

<p>Here is some advice I gathered to create professional-looking graphic assets:</p>

<ul>
<li><p><strong>Always ensure your screenshots are consistent</strong>: Just like you love to have a cohesive environment on your desktop, at home or at work, people appreciate consistency in marketing pictures. As a result, taking screenshots with the same version of your app and Android platform in the best guarantee your users won&#8217;t be jostled.</p></li>
<li><p><strong>Create physically accurate screenshots</strong>: When modifying the content of your screenshots always make sure the resulting image is physically &#8220;doable&#8221;. For instance, if you modify the time in the status bar, make sure the alarm widget is also modified. The other common issue occurs when using a screen glare as I described earlier. The image you show <strong>must</strong> be something the user can see in the real world.</p></li>
<li><p><strong>Apply the exact same status bar on all of your screenshots</strong>: Android status bars have changed quite a lot over time. It was grey with black information on Android 1.6, switched to black with green and gray information on Gingerbread and finally switched to black with blue/grey information on Honeycomb. When releasing screenshots always try to reuse the same status bar, preferably the latest version of it.</p></li>
<li><p><strong>Have clear and clean status bar icons</strong>: You generally don&#8217;t want your users to be distracted by a large set of status bar icons. Make them focus on the actual content of your application by removing all un-necessary icons (notification icons, alarm, silent mode, etc.). Also use completely filled up icons for fillable icons: battery, reception, etc.</p></li>
<li><p><strong>Override the current time</strong>: Releasing a graphic indicating a screenshot was taken at 2AM in clearly not professional. It may indicate you rushed to finalize the application. Use a smart and ingenious time and stick to it! For instance Google, with the Galaxy Nexus uses the version of latest platform: 4:00 for Ice Cream Sandwich and 4:10 for Jelly Bean. Apple generally uses 9:41, the time at which products such as the iPhone or the iPad are likely to be introduced.</p></li>
<li><p><strong>Always use the same device frame</strong>: If you have decided to base your graphics on the latest Google Android devices then stick to it. Using different device frames may make people think they are looking at different apps running on different hardware. It is usually a good idea to increase consistency by associating your app to a single Android device.</p></li>
<li><p><strong>Enforce branding if needed</strong>: You may add icons to ensure your screenshots are personalized but if you do so, make sure the result is Android compliant. For instance, you may add a notification icon in the status bar. When doing so, always ensure your icons follow the guidelines as described on the <a href="http://developer.android.com/guide/practices/ui_guidelines/icon_design_status_bar.html">Android website</a>.</p></li>
<li><p><strong>Use screen glare cleverly</strong>: Keep in mind, screen glares are not appropriate on screen-only screenshots. They are usually used in addition to a device frame.</p></li>
</ul>


<p>That&#8217;s a lot of rules, isn&#8217;t it? Fortunately, some tools and resources do exist to help you. Roman Nurik&#8217;s <a href="http://android-ui-utils.googlecode.com/hg/asset-studio/dist/device-frames.html">Android device frame generator</a> lets you easily create device-framed screenshots with a simple drag and drop gesture. Roman&#8217;s generator is awesome. However, the simplicity of this tool makes it also less powerful than Photoshop. Personally I don&#8217;t use the Android device frame generator for various reasons: drop shadow too strong - especially on white background, missing device reflection, un-optimized exported PNG, no status bar standardization, etc.</p>

<p>Below are the PSDs I made and use for my own screenshots. These files have been created in Photoshop CS6 but should work properly with all recent versions of CS. Also note the following resources are licensed under the <a href="http://creativecommons.org/licenses/by/3.0/">CC BY 3.0</a>:</p>

<p><button class="download-button" onclick="window.location='/media/2012/07/creating-professional-looking-screenshots/android_screenshots_assets.zip';"><span class="icon"></span><span class="title">Android Screenshots Assets</span></button></p>

<p>The PSDs above are very simple to use and will help you to generate graphic resources in a few steps:</p>

<ol>
<li>Open the appropriate PSD and the screenshot in Photoshop</li>
<li>Copy the entire source screenshot (⌘A and ⌘V)</li>
<li>Open the &#8220;Smart Object&#8221; (double click) and paste the source image (⌘V)</li>
<li>Save and close the &#8220;Smart Object&#8221; (⌘S and ⌘W)</li>
<li>Export the result for the web using the Photoshop optimizer (⌥⇧⌘S)</li>
</ol>


<p>I know Photoshop may be quite difficult to apprehend so I made a small demonstration video in which the few steps are explained in details.</p>

<div class="embed-video-container"><iframe src="http://www.youtube.com/embed/eIHCBjvEsYQ "></iframe></div>


<p>Carefully spreading your work on the Internet is extremely important. It shows how great your product is and the amount of attention you gave while designing it. The more care you give to the screenshots, the more you&#8217;ll say to your audience you brought care to your application, its features, its design, etc. I&#8217;m not a marketing guy but I can say that consumers are very impacted by the way things are presented. Be consistent, look carefully at the details, control what you are spreading in the outside world.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[API 16 (Jelly Bean) Review]]></title>
    <link href="http://cyrilmottier.com/2012/07/06/api-16-jelly-bean-review/"/>
    <updated>2012-07-06T00:00:00+02:00</updated>
    <id>http://cyrilmottier.com/2012/07/06/api-16-jelly-bean-review</id>
    <content type="html"><![CDATA[<p>Yesterday afternoon I tweeted about the differences in the Jelly Bean release (API 16). Some of you replied to my tweet and asked me to write about these changes. Here is a brief review of the API differences of API 16. Obviously, I won&#8217;t talk from a user point of view but rather from a developer point of view by giving you my feelings about these API changes.</p>

<p>API 16 is clearly a minor update. If you look attentively to the <a href="http://developer.android.com/sdk/api_diff/16/changes.html">API diff</a> documentation, you will notice there has been just a few packages, classes and methods added. However, being a minor update doesn&#8217;t mean it is useless. Indeed, what I particularly appreciate about this release is it makes the API more consistent and clearer. Google obviously spent some time making the API more logical and hence easier to understand and use. The list below gives you a set of changes that brings uniformity and clearness to the framework.</p>

<!-- More -->


<ul>
<li><p><strong>From non-final to final</strong>: Prior API 16, View <code>Property</code> such as <code>ALPHA</code>, or <code>ROTATION_X</code> were not final. This was obviously a huge mistake because these properties was not intended to be modified (see <a href="https://plus.google.com/118417777153109946393/posts/Z91s4Jd2Q6y">my Google+ post</a>). When I noticed it, I warned some of the framework engineers and I&#8217;m glad to see they fixed it even if it may break some applications.</p></li>
<li><p><strong>Methods renaming</strong>: In order to always have consistency between getters and setters, some methods have been renamed. For instance, <code>setAlpha(int)</code> on <code>ImageView</code> is now <code>setImageAlpha(int)</code>.</p></li>
<li><p><strong>Added getter and setter</strong>: Prior API 16, it was sometimes impossible to do things in Java while it was completely possible from XML. For example, the size of a scrollbar wasn&#8217;t modifiable from Java but it was from XML. Some getters/setters have also been added to ensure all <code>View</code> attributes have a setter and its getter counterpart. In general, you can now set and get all attributes from a widget (ie object that extends <code>View</code>)</p></li>
<li><p><strong>Deprecation of some classes</strong>: There has been a lot of criticism on the fact Renderscript rendering pipeline is now deprecated. I actually think Google made a mistake not informing developers that the graphic part of Renderscript was experimental at the first release. However, some widgets such as the <code>Gallery</code> are now deprecated and I think that&#8217;s a really good point. I really believe advanced widgets like the <code>Gallery</code> are not supposed to exist in the framework. For my point of view, a framework is not supposed to provide everything a developer need. It has to provide very simple but powerful APIs that let you, developers, create whatever you want whenever you want. A simple framework is easier to apprehend and understand and relieves Google of maintaining a too large/complex API. This deprecation (deprecation doesn&#8217;t mean it has been removed) is a good start and I hope Google will continue to remove/depreciate classes that should never has been there.<sup>1</sup></p></li>
</ul>


<p>While reading the entire API differences, I&#8217;ve also discovered several interesting changes:</p>

<ul>
<li><p>A new display density has been introduced: <a href="https://developer.android.com/reference/android/util/DisplayMetrics.html#DENSITY_XXHIGH">DENSITY_XXHIGH</a> which corresponds to 480 pixels per inch. It clearly demonstrates Google is thinking about Android in a long-term manner and starts to prepare the system to future screen densities. Personally I think this will be the last added density (no need to have a higher density on any device) but I can&#8217;t wait to see a Nexus device using it!</p></li>
<li><p><code>LongSparseArray</code> has been made public or more specifically unhidden (it has always been in the Android source code). <code>SparseArray&lt;E&gt;</code>s, <code>SparseBooleanArray</code> and <code>SparseIntArray</code> are really great to avoid auto-boxing/auto-unboxing problems in maps. Prior API 16, the <code>LongSparseArray</code> was hidden. As a result, it is now possible to have maps in which keys are <code>long</code>s. This make me believe, the pool API (<code>PoolManager</code>, <code>Poolable</code>, etc.) that lets you easily create a pool object mechanism may be unhidden some day&#8230;</p></li>
<li><p>You can now synchronize your custom animations with the display vertical synchronization (vsync). This can be done using the <code>Choreographer</code> class directly or one of the new <code>View</code> methods (also available in the support library through the <code>ViewCompat</code> class): <code>postOnAnimation(Runnable)</code> and <code>postInvalidateOnAnimation()</code>. I applied it to my implementation of the fly-in app menu and I got to admit I love the result!</p></li>
<li><p><code>ViewPropertyAnimator</code> now includes 3 more methods making the animation framework crystal clear and easier to use. Indeed, you can know define a start and/or action directly from it via <code>with[End|Start]Action(Runnable)</code>. The API also includes a new <code>withLayer()</code> method. Thanks to this method chaining feature, creating, applying properties and starting an animation has never been so simple.</p></li>
<li><p>The <code>WebView</code> framework has also been updated because a new <code>WebView.FindListener</code> has been added. it lets you be notified as find-on-page operations progress. The outdated <code>getZoomControls()</code> method has also been completely removed. Here again, it brings clearness to the framework and remove redundancy (zoom controls can be disabled/enabled using <code>WebSettings.setBuiltInZoomControls (boolean)</code>)</p></li>
</ul>


<p>The minor Jelly Bean release clearly moves Android forward. I sincerely love the work Google has made on this release and hope they&#8217;ll continue to follow the path they&#8217;ve taken. Lots of developers may complain at first about the introduced changes and deprecations but this is for the good of Android. Google is preparing Android for the future. You, as a developer should stop complaining, get use to it and adapt yourself. Do not forget Android is now a 6 years-old system. Legacy is not something we can ignore.</p>

<hr />

<ol>
<li>My personal point of view about what a framework should be is also the explanation of why the fly-in app menu shouldn&#8217;t be part of the SDK. The Android SDK contains everything you need to create a stunning fly-in app menu. Stop asking Google integrating it in the SDK. That&#8217;s something that should be clearly done by Android developers and optionally by third-party libraries. From time to time I really believe Android developers are pretty lazy. They prefer spending time on begging Google to help them rather than actually developing. Look at the permissive and powerful framework, read the documentation, etc. You have the power of Android in your hands: you just have to use it!</li>
</ol>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[The Making of Prixing #3: Polishing the Sliding App Menu]]></title>
    <link href="http://cyrilmottier.com/2012/06/08/the-making-of-prixing-3-polishing-the-sliding-app-menu/"/>
    <updated>2012-06-08T00:00:00+02:00</updated>
    <id>http://cyrilmottier.com/2012/06/08/the-making-of-prixing-3-polishing-the-sliding-app-menu</id>
    <content type="html"><![CDATA[<p>Thanks to the two previous articles of &#8220;The making of Prixing&#8221; series - see links below, we have learned all the technical details required to create a user-friendly, smooth and responsive fly-in app menu.</p>

<ul>
<li><a href="http://www.cyrilmottier.com/2012/05/22/the-making-of-prixing-fly-in-app-menu-part-1/">The making of Prixing #1: Fly-in app menu</a></li>
<li><a href="http://www.cyrilmottier.com/2012/05/29/the-making-of-prixing-2-swiping-the-fly-in-app-menu/">The making of Prixing #2: Swiping the fly-in app menu</a></li>
</ul>


<p>This post will concentrate on making the UI widget more polished and will give the answer to the puzzle I gave in the conclusion of the previous post: &#8220;How to use the sliding menu between Activities by-passing the default transition&#8221;. Of course, I highly suggest you read the previous articles of the series as they were both dedicated to the fly-in app menu.</p>

<!-- More -->


<p><em><strong>Note</strong>: As usual, all figures in this article are available in high definition by simply clicking on it.</em></p>

<h3>Enforcing perspective with drop shadows</h3>

<p>As shown in the figure below, the fly-in app menu draws a drop shadow on the left of the host - ie the content of the screen - when being dragged or opened. The drop shadow enforces the perspective giving the user the impression the host slides on top of the menu. It is also a way to indicate the content is primary while the menu is secondary.</p>

<p><a href="http://cyrilmottier.com/media/2012/06/the-making-of-prixing-3-polishing-the-sliding-app-menu/drop_shadow_large.png"><img class="center" src="http://cyrilmottier.com/media/2012/06/the-making-of-prixing-3-polishing-the-sliding-app-menu/drop_shadow.png" title="Drop shadow" ></a></p>

<p>Drawing a drop shadow can be done in a number of ways. For instance you can add an <code>ImageView</code> with a &#8220;shadow&#8221; image as background that will always be laid out on the left of the host. This is obviously possible but it is pretty heavy in term of memory-consumption and layout/drawing performance. The current implementation of the Prixing&#8217;s ribbon menu uses a <code>GradientDrawable</code> drawn manually in <code>dispatchDraw(Canvas)</code>. This latter method can be used in your custom <code>View</code>s whenever you want to draw something manually before or after the children were drawn. In our case this is obviously done after. You may also add a tiny optimization that prevents the shadow from being drawn when it is not visible ie when the drawer is closed. Here is what the <code>RootView</code>&#8217;s <code>dispatchDraw(Canvas)</code> looks like.</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="nd">@Override</span>
</span><span class='line'><span class="kd">protected</span> <span class="kt">void</span> <span class="nf">dispatchDraw</span><span class="o">(</span><span class="n">Canvas</span> <span class="n">canvas</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>    <span class="c1">// Draw the children</span>
</span><span class='line'>    <span class="kd">super</span><span class="o">.</span><span class="na">dispatchDraw</span><span class="o">(</span><span class="n">canvas</span><span class="o">);</span>
</span><span class='line'>
</span><span class='line'>    <span class="k">if</span> <span class="o">(</span><span class="n">mState</span> <span class="o">!=</span> <span class="n">MENU_CLOSED</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="c1">// The menu is not closed. That means we can potentially see the host</span>
</span><span class='line'>        <span class="c1">// overlapping it. Let&#39;s add a tiny gradient to indicate the host is</span>
</span><span class='line'>        <span class="c1">// sliding over the menu.</span>
</span><span class='line'>        <span class="n">canvas</span><span class="o">.</span><span class="na">save</span><span class="o">();</span>
</span><span class='line'>        <span class="n">canvas</span><span class="o">.</span><span class="na">translate</span><span class="o">(</span><span class="n">mHost</span><span class="o">.</span><span class="na">getLeft</span><span class="o">(),</span> <span class="mi">0</span><span class="o">);</span>
</span><span class='line'>        <span class="n">mShadowDrawable</span><span class="o">.</span><span class="na">draw</span><span class="o">(</span><span class="n">canvas</span><span class="o">);</span>
</span><span class='line'>        <span class="n">canvas</span><span class="o">.</span><span class="na">restore</span><span class="o">();</span>
</span><span class='line'>
</span><span class='line'>        <span class="kd">final</span> <span class="kt">int</span> <span class="n">menuWidth</span> <span class="o">=</span> <span class="n">mMenu</span><span class="o">.</span><span class="na">getWidth</span><span class="o">();</span>
</span><span class='line'>        <span class="k">if</span> <span class="o">(</span><span class="n">menuWidth</span> <span class="o">!=</span> <span class="mi">0</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>            <span class="kd">final</span> <span class="kt">float</span> <span class="n">opennessRatio</span> <span class="o">=</span> <span class="o">(</span><span class="n">menuWidth</span> <span class="o">-</span> <span class="n">mHost</span><span class="o">.</span><span class="na">getLeft</span><span class="o">())</span> <span class="o">/</span> <span class="o">(</span><span class="kt">float</span><span class="o">)</span> <span class="n">menuWidth</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'>            <span class="c1">// We also draw an overlay over the menu indicating the menu is</span>
</span><span class='line'>            <span class="c1">// in the process of being visible or invisible.</span>
</span><span class='line'>            <span class="n">onDrawMenuOverlay</span><span class="o">(</span><span class="n">canvas</span><span class="o">,</span> <span class="n">opennessRatio</span><span class="o">);</span>
</span><span class='line'>
</span><span class='line'>            <span class="c1">// Finally we draw an arrow indicating the feature we are</span>
</span><span class='line'>            <span class="c1">// currently in</span>
</span><span class='line'>            <span class="n">onDrawMenuArrow</span><span class="o">(</span><span class="n">canvas</span><span class="o">,</span> <span class="n">opennessRatio</span><span class="o">);</span>
</span><span class='line'>        <span class="o">}</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'><span class="o">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>The interesting things happen on top of the <code>menuWidth</code> computation/caching line (we will focus on the rest of the source code afterwards). When overriding the <code>dispatchDraw(Canvas)</code> just call <code>super.dispatchDraw(Canvas)</code> to draw the children <code>View</code>s and put your extra code after this call. As shown, the <code>GradientDrawable</code> is drawn manually on the <code>Canvas</code> which is translated to the appropriate position using <code>Canvas#translate(int, int)</code>. Do not forget to initialize the bounds of your <code>Drawable</code> using <code>Drawable#setBounds(int, int, int, int)</code> or <code>Drawable#setBounds(Rect)</code> prior to using it or you will end up pulling your hair out, or even crying, because nothing happens. And believe me, I know that it hurts a lot!</p>

<h3>&#8220;Abracadabra&#8221; or how to make the menu dis(appear)</h3>

<p>In order to emphasize the fact the menu is appearing or disappearing it is usually a good idea to add some nice effects. The stock launcher app on my Galaxy Nexus for instance uses a nice zooming and fading animation to indicate the next page is being visible/invisible. When designing the <code>RootView</code>, I wanted the effect to be subtle and more in a two-dimensional space (I am not a huge fan of 3D effects). Pretty naturally we decided to make the menu appear/disappear using a dimming and parallax effect as shown below:</p>

<p><a href="http://cyrilmottier.com/media/2012/06/the-making-of-prixing-3-polishing-the-sliding-app-menu/fading_parallax_large.png"><img class="center" src="http://cyrilmottier.com/media/2012/06/the-making-of-prixing-3-polishing-the-sliding-app-menu/fading_parallax.png" title="Fading and parallax" ></a></p>

<p>The dimming effect is done pretty basically using the previously introduced <code>dispatchDraw(Canvas)</code> method. It consists of drawing a translucent black rectangle entirely covering the menu. The transparency of the rectangle is computed on the fly with a fairly straightforward linear formula. Please note that the <code>MAXIMUM_MENU_ALPHA_OVERLAY</code> constant is not 255 but 170. Indeed, using a fully opaque rectangle when starting to open the menu would likely result in having users seeing a black background. This obviously doesn&#8217;t help knowing a menu is lying down there. Always having a translucent rectangle is way better from a user perspective.</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="kt">int</span> <span class="n">MAXIMUM_MENU_ALPHA_OVERLAY</span> <span class="o">=</span> <span class="mi">170</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'><span class="kd">private</span> <span class="kt">void</span> <span class="nf">onDrawMenuOverlay</span><span class="o">(</span><span class="n">Canvas</span> <span class="n">canvas</span><span class="o">,</span> <span class="kt">float</span> <span class="n">opennessRatio</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>    <span class="kd">final</span> <span class="n">Paint</span> <span class="n">menuOverlayPaint</span> <span class="o">=</span> <span class="n">mMenuOverlayPaint</span><span class="o">;</span>
</span><span class='line'>    <span class="kd">final</span> <span class="kt">int</span> <span class="n">alpha</span> <span class="o">=</span> <span class="o">(</span><span class="kt">int</span><span class="o">)</span> <span class="o">(</span><span class="n">MAXIMUM_MENU_ALPHA_OVERLAY</span> <span class="o">*</span> <span class="n">opennessRatio</span><span class="o">);</span>
</span><span class='line'>    <span class="k">if</span> <span class="o">(</span><span class="n">alpha</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="n">menuOverlayPaint</span><span class="o">.</span><span class="na">setColor</span><span class="o">(</span><span class="n">Color</span><span class="o">.</span><span class="na">argb</span><span class="o">(</span><span class="n">alpha</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span> <span class="mi">0</span><span class="o">));</span>
</span><span class='line'>        <span class="n">canvas</span><span class="o">.</span><span class="na">drawRect</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span> <span class="n">mHost</span><span class="o">.</span><span class="na">getLeft</span><span class="o">(),</span> <span class="n">getHeight</span><span class="o">(),</span> <span class="n">mMenuOverlayPaint</span><span class="o">);</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'><span class="o">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>If you have carefully read the first article of the series, you probably know how to implement the parallax effect. Indeed, in the first article of this series we talked about a method used to quickly offset a <code>View</code>: <code>offsetLeftAndRight(int)</code>. Thanks to this method, it is possible to offset the menu from a value depending on the current openness ratio:</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="kt">float</span> <span class="n">PARALLAX_SPEED_RATIO</span> <span class="o">=</span> <span class="mf">0.25f</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'><span class="kd">private</span> <span class="kt">void</span> <span class="nf">offsetMenu</span><span class="o">(</span><span class="kt">int</span> <span class="n">hostLeft</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>    <span class="kd">final</span> <span class="kt">int</span> <span class="n">menuWidth</span> <span class="o">=</span> <span class="n">mMenu</span><span class="o">.</span><span class="na">getWidth</span><span class="o">();</span>
</span><span class='line'>    <span class="k">if</span> <span class="o">(</span><span class="n">menuWidth</span> <span class="o">!=</span> <span class="mi">0</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="kd">final</span> <span class="kt">float</span> <span class="n">opennessRatio</span> <span class="o">=</span> <span class="o">(</span><span class="n">menuWidth</span> <span class="o">-</span> <span class="n">hostLeft</span><span class="o">)</span> <span class="o">/</span> <span class="o">(</span><span class="kt">float</span><span class="o">)</span> <span class="n">menuWidth</span><span class="o">;</span>
</span><span class='line'>        <span class="n">mMenu</span><span class="o">.</span><span class="na">offsetLeftAndRight</span><span class="o">((</span><span class="kt">int</span><span class="o">)</span> <span class="o">(-</span><span class="n">opennessRatio</span> <span class="o">*</span> <span class="n">menuWidth</span> <span class="o">*</span> <span class="n">PARALLAX_SPEED_RATIO</span><span class="o">)</span> <span class="o">-</span> <span class="n">mMenu</span><span class="o">.</span><span class="na">getLeft</span><span class="o">());</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'><span class="o">}</span>
</span></code></pre></td></tr></table></div></figure>


<h3>Indicating the selected application menu item</h3>

<p>The Prixing application includes a lot of application features. Each of these features are normally represented by a single item in the application menu. In order to help the user understand where she is in the workflow, we decided to add an indicator on the current feature. In the application, the indicator is represented by a tiny arrow that keeps pointing to the feature as long as it is visible on screen. In the beginning, I thought about adding it to all of the itemviews composing the app menu and displaying it whenever necessary. Unfortunately, this would have caused several problems. First the drop shadow would have been drawn on top of the arrow, so we would have had some cases where the arrow is drawn next to the <code>ActionBar</code> which would be really ugly and it would have been impossible to make the arrow strech out/retract depending on the current openness of the menu. We really wanted to have a precise control over the arrow so we used a radically different approch: drawing the arrow manually in <code>dispatchDraw(Canvas)</code>.</p>

<p><a href="http://cyrilmottier.com/media/2012/06/the-making-of-prixing-3-polishing-the-sliding-app-menu/selection_arrow_large.png"><img class="center" src="http://cyrilmottier.com/media/2012/06/the-making-of-prixing-3-polishing-the-sliding-app-menu/selection_arrow.png" title="Selection arrow" ></a></p>

<p>As attentive people may have noticed, the heavy work is done with the <code>onDrawMenuArrow(Canvas, float)</code> method. It first retrieves the bounds of the active <code>View</code> with <code>getDrawing(Rect)</code>. At first, this method may look quite weird as its return type is <code>void</code>. <code>getDrawing(Rect)</code> is one of the rare methods in the Android framework returning the result directly in the passed argument. This is a trick that prevents creating several <code>Rect</code> instances for nothing. As a result, only a single instance can be created and reused over time. The main problem with the bounds returned by <code>getDrawing(Rect)</code> is that they are given in the active <code>View</code>&#8217;s parent coordinates space. Since we need to draw the arrow in the <code>RootView</code>&#8217;s <code>dispatchDraw(Canvas)</code> method, we need them in our coordinates space. Fortunately, the Android framework provides a utility method to offset the rectangle appropriately: <code>offsetDescendantRectToMyCoords(View, Rect)</code>. The name of this method is rather long and mysterious, but it does the job! The resulting <code>Rect</code> lets us compute the position of the arrow on the Y-axis. The exact position of the arrow on the X-axis is determined depending on the given openness ratio - Prixing uses an <code>AccelerateInterpolator</code> to make the stretching out/retract effect less linear. Drawing the arrow on the <code>Canvas</code> is done pretty basically with a combination of <code>Canvas#clipRect(int, int, int, int)</code> and <code>Canvas#drawBitmap(Bitmap, int, int, Paint)</code></p>

<h3>Fly-in app menu usage 101</h3>

<p>The <code>RootView</code> includes a nice feature that helps users to discover the hidden menu as well as the swipe capability. This feature called &#8220;menu hint&#8221; consists of animating the drawer as if it were bouncing the first time the user sees it. From my point of view, this is not the best option to teach the user the menu can be found below the host. Displaying the first <code>Activity</code> with an opened application menu which closes automatically after a given delay is probably better. We finally decided to go for the bouncing animation because we wanted the user to see the content of the application first. Now that you are familiar with <code>Interpolator</code>s you can easily understand the <code>PageHintInterpolator</code> used by the <code>RootView</code> when the &#8220;menu hint&#8221; is enabled:</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="kn">package</span> <span class="n">fr</span><span class="o">.</span><span class="na">epicdream</span><span class="o">.</span><span class="na">android</span><span class="o">.</span><span class="na">prixing</span><span class="o">.</span><span class="na">view</span><span class="o">.</span><span class="na">animation</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.view.animation.BounceInterpolator</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.view.animation.DecelerateInterpolator</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.view.animation.Interpolator</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'><span class="cm">/**</span>
</span><span class='line'><span class="cm"> * A custom {@link Interpolator} reproducing the effect of an object thrown in</span>
</span><span class='line'><span class="cm"> * the air, starting to fall and bouncing at the end</span>
</span><span class='line'><span class="cm"> * </span>
</span><span class='line'><span class="cm"> * @author Cyril Mottier</span>
</span><span class='line'><span class="cm"> */</span>
</span><span class='line'><span class="kd">public</span> <span class="kd">class</span> <span class="nc">PageHintInterpolator</span> <span class="kd">implements</span> <span class="n">Interpolator</span> <span class="o">{</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">private</span> <span class="n">Interpolator</span> <span class="n">mDecelerateInterpolator</span> <span class="o">=</span> <span class="k">new</span> <span class="n">DecelerateInterpolator</span><span class="o">();</span>
</span><span class='line'>    <span class="kd">private</span> <span class="n">Interpolator</span> <span class="n">mBounceInterpolator</span> <span class="o">=</span> <span class="k">new</span> <span class="n">BounceInterpolator</span><span class="o">();</span>
</span><span class='line'>
</span><span class='line'>    <span class="nd">@Override</span>
</span><span class='line'>    <span class="kd">public</span> <span class="kt">float</span> <span class="nf">getInterpolation</span><span class="o">(</span><span class="kt">float</span> <span class="n">t</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="c1">// The purpose of this is pretty simple :</span>
</span><span class='line'>        <span class="c1">// - mDecelerateInterpolator for t &lt; 0.33</span>
</span><span class='line'>        <span class="c1">// - mBounceInterpolator for t &gt;= 0.33</span>
</span><span class='line'>        <span class="k">if</span> <span class="o">(</span><span class="n">t</span> <span class="o">&lt;</span> <span class="mf">0.33</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>            <span class="k">return</span> <span class="n">mDecelerateInterpolator</span><span class="o">.</span><span class="na">getInterpolation</span><span class="o">(</span><span class="n">t</span> <span class="o">/</span> <span class="mf">0.33f</span><span class="o">);</span>
</span><span class='line'>        <span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
</span><span class='line'>            <span class="k">return</span> <span class="mi">1</span><span class="n">f</span> <span class="o">-</span> <span class="n">mBounceInterpolator</span><span class="o">.</span><span class="na">getInterpolation</span><span class="o">((</span><span class="n">t</span> <span class="o">-</span> <span class="mf">0.33f</span><span class="o">)</span> <span class="o">/</span> <span class="mf">0.67f</span><span class="o">);</span>
</span><span class='line'>        <span class="o">}</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'><span class="o">}</span>
</span></code></pre></td></tr></table></div></figure>


<h3>Using the fly-in app menu between Activities</h3>

<p>Let&#8217;s conclude this article with the answer to a puzzle I gave at the end of the preceeding one: How to seemlessly open/close the <code>RootView</code> between <code>Activity</code>s. Indeed, when I started working at Prixing, I discovered an enormous existing code base mainly based on tons of <code>Activity</code>s. We wanted to release a radically different version quite rapidly so we had to deal with all the existing <code>Activity</code>s, rather than switching them to <code>Fragment</code>s. As a result, we started thinking about a way to make the transition between <code>Activity</code>s as natural as possible, and rapidly came up with a simple idea: Faking that the current <code>Activity</code> hasn&#8217;t changed simply by applying the same state to the opened <code>Activity</code>.</p>

<p>The <code>Activity</code> transition in the Prixing application relies on the exact same technique the Android framework uses to restore an <code>Activity</code> after it has been destroyed in low memory conditions. As a result, everytime a new <code>Activity</code> needs to be opened, we save the the interesting part of the current UI state using <code>View#onSaveInstanceState()</code>/<code>View#saveHierarchyState(SparseArray&lt;Parcelable&gt;)</code> and re-apply it to the newly created <code>Activity</code> thanks to <code>View#onRestoreInstanceState(Parcelable)</code>/<code>View#restoreHierarchyState(SparseArray&lt;Parcelable&gt;)</code></p>

<p>I have to admit this is a pretty advanced technique but it works pretty great. Of course I haven&#8217;t given all the details here to make it work perfectly, but I hope you understand the main idea. Behind the scene we had to develop a custom <code>ScrollView</code> that saves its current scrolling state for the menu. Indeed, it is impossible to save the <code>ListView</code> state at a pixel level in Android 2.1, and the framework&#8217;s <code>ScrollView</code> doesn&#8217;t save its scrolling position<sup>1</sup>. Moreover, we implemented an <code>OnLayoutListener</code>-equivalent on our <code>RootView</code> to indicate that the menu close animation should be performed after the <code>Activity</code> has opened. Finally, since it is used on all <code>Activity</code>s, we worked hard on making the menu as light-weight as possible, flattening the <code>View</code> hierarchy and creating custom <code>View</code>s. For instance each feature in the menu is a made of a single <code>AppMenuItemView</code> which directly extends <code>View</code> and manages an icon, a title, a subtitle, an annotation and a divider.</p>

<h3>Conclusion</h3>

<p>That&#8217;s it! You now have all of the technical details to create stunning fly-in app menus. Some may say all of the tricks given in this post are just details but keep in mind details are what makes the difference. Details matter, so do not be afraid about spending a lot of time working on them. It will make your application better, more polished, more appreciated and hence more downloaded and used. I sincerely hope I have given all the tips and tricks required to reproduce all of the features that <code>Prixing</code>&#8217;s sliding menu has. If not, feel free to post a comment below and I will be pleased to answer your questions. I will surely continue revealing some Android UI development tricks we used while developing the third version of Prixing in future articles, so stay tuned!</p>

<p>Thanks to <a href="http://twitter.com/#!/franklinharper">@franklinharper</a> for reading drafts of this</p>

<hr />

<ol>
<li>Some of you may wonder &#8220;Why the hell is this not already managed by the Android <code>ScrollView</code>?&#8221;. That&#8217;s completely normal and here is the reason of it. Android is based on the idea that on a configuration change the content of a screen may change dramatically (for example the layout may be completely different). As a result, having a <code>ScrollView</code> in the portrait orientation doesn&#8217;t mean its height/content will be the same in the landscape orientation. Because of this it is not accurate to save and restore the current scrolling value by default.</li>
</ol>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[The Making of Prixing #2: Swiping the Fly-in App Menu]]></title>
    <link href="http://cyrilmottier.com/2012/05/29/the-making-of-prixing-2-swiping-the-fly-in-app-menu/"/>
    <updated>2012-05-29T00:00:00+02:00</updated>
    <id>http://cyrilmottier.com/2012/05/29/the-making-of-prixing-2-swiping-the-fly-in-app-menu</id>
    <content type="html"><![CDATA[<p>The previous article of the &#8220;The making of Prixing&#8221; series was a brief introduction to the fly-in app menu. I gave a lot of Android UI development tips and tricks that may be helpful to create such a widget in your application. Obviously, the fly-in app menu is a little bit more advanced than what I described. It requires more than a single post to do a complete review of the techniques you may need to create your own implementation of a sliding menu. Let&#8217;s continue the in-depth study, focusing on gesture interaction.</p>

<p>In the first article we ended up creating a very basic fly-in app menu. Indeed, the widget we created was closable/openable only programmatically or using a simple click gesture. The latter obviously works like a charm but it has a cruel lack of naturalness and intuitiveness. Having a closing/opening animation of the host makes the user want to interact with the object as he/she would in the real world using a well known gesture: the swipe gesture.</p>

<!-- More -->


<p>Having a drawer the user can move precisely is the best way to make your UI feel like it is an extension of the real world. Have you ever played video games in which it is impossible to shoot a tree or move a basic object like a book? Pretty frustrating, isn&#8217;t it? Users usually hate being artificially blocked or unable to do something he/she wants to. UI development in general follows the exact same rule: Do not block your users, let them do whatever they want. The figure below shows some of the available gestures:</p>

<p><a href="http://cyrilmottier.com/media/2012/05/the-making-of-prixing-2-swiping-the-fly-in-app-menu/gestures_large.png"><img class="center" src="http://cyrilmottier.com/media/2012/05/the-making-of-prixing-2-swiping-the-fly-in-app-menu/gestures.png"></a></p>

<p>The purpose of this second article is to give you all the requirements you need to add the swipe gesture capability to your fly-in app menu. To be honest, the swipe gesture is far from being new. It is pretty natural to mobile (iOS, Android, Windows mobile, etc.) users. It has been spread so much it is now now available in lots of mobile applications nowadays. In Prixing, the main problem we had was to imbricate horizontally scrollable components (<code>ViewPager</code>, <code>MapView</code>, etc.) in another swipable component (the <code>RootView</code>). This obviously leads to a simple question: Which component has the right to intercept the gesture?1. The Android documentation gives a partial answer to this fundamental question: &#8220;You should never use a <code>ScrollView</code> with a <code>ListView</code>, since <code>ListView</code> takes care of its own scrolling.&#8221;. This is actually true but several ways to overcome the issue exist:</p>

<ul>
<li><p><strong>No swiping</strong>: The easiest way to implement tricky things is not to implement them! As I like to say: if you don&#8217;t want to have trouble, stay at home and do nothing. The problem with this method is it makes your life boring. I am not this kind of guy.</p></li>
<li><p><strong>Smart swiping</strong>: This technique consists of first looking at the top-most (in the drawing order)<code>View</code> which wants to deal with the gesture. In this case, if the component can scroll horizontally in the direction of the swipe gesture, then let it scroll. If it has already reached its maximum position, let the scrollable container intercepts the gesture. This pattern is used in the latest version of GMail. Indeed, when browsing your emails, the <code>ViewPager</code> won&#8217;t scroll to the next page until the <code>WebView</code> has not scrolled to the edge. The main problem with this technique is it requires the <code>canScrollHorizontally(int)</code> method which is only available starting from API 14. Moreover you need to be able to determine the <code>View</code> that consumed the gesture (aka <code>TouchTarget</code> in the Android source code). I couldn&#8217;t find a public method allowing us to determine this <code>View</code><sup>1</sup> and Prixing had to run on devices with Android 2.1+ so we decided to use another technique.</p></li>
<li><p><strong>Bezel swiping</strong>: This technique consists of intercepting a swipe gesture if and only if it starts near from the edge of the <code>View</code>. Bezel swiping is usually implemented looking at the position of the first gesture&#8217;s <code>TouchEvent</code>: the <code>ACTION_DOWN</code>. This is how Chrome for Android lets you navigate between your tabs. I don&#8217;t consider it as perfect because you may end up with some gesture mismatch but it makes your menu <strong>always</strong> accessible. In Prixing, we decided to go for it!</p></li>
</ul>


<h3>Handling touch events</h3>

<p>The Android framework provides everything you need to handle touch events. The most important method is <code>onTouchEvent(MotionEvent)</code>. It is called by the system when a <code>MotionEvent</code> (the class representing a touch event) occurred in your <code>View</code>. This is where you put the code that will make the host follow the user&#8217;s finger. Unfortunately, implementing <code>onTouchEvent(MotionEvent)</code> will not be enough as it may never be called by the system in case another <code>View</code> - deeper in the <code>View</code> hierarchy - consumes the touch event first. In order to be able to intercept the touch you will simply have to override <code>onInterceptTouchEvent(MotionEvent)</code> in your <code>RootView</code>. I strongly suggest you read the documentation of this <a href="http://developer.android.com/reference/android/view/ViewGroup.html#onInterceptTouchEvent(android.view.MotionEvent">method</a>) as it has a fairly complicated interaction with <a href="http://developer.android.com/reference/android/view/View.html#onTouchEvent(android.view.MotionEvent"><code>onTouchEvent(MotionEvent)</code></a>) If you are not familiar with the event dispatching system in Android you can have a look at the great &#8220;Mastering the Android Touch System&#8221; presentation Dave Smith - <a href="http://twitter.com/#!/devunwired">@devunwired</a> - gave at AnDevCon III. I didn&#8217;t attend the talk, but looking at the <a href="http://www.andevcon.com/AndevCon_III/downloadpresentation.aspx?aid=Mastering_the_Android_Touch_System_pdf.zip&amp;sid=6">slides</a> and the <a href="https://github.com/devunwired/custom-touch-examples">source code</a> clearly suggested to me that the talk was great.</p>

<h3>Using platform-provided constants</h3>

<p>If you look closely to the source code of some UI widgets included in the framework, you will see they use various constants. The vast majority of these constants can be easily retrieved thanks to the <code>ViewConfiguration</code> class. You should always use this class whenever you need to create your own UI widgets. In fact, the provided values have been widely tested by the Android team. For instance, we will later use the &#8220;touch slop&#8221; constant which describes the distance a touch can wander before we think the user is scrolling. This value is expressed in pixels and can be accessed via a call to <code>getScaledTouchSlop()</code>. Please note the static unscaled counter part method <code>getTouchSlop()</code> is deprecated and should never be used anymore as it doesn&#8217;t scale the constant to match the screen density.</p>

<p>If you really want to use your own dimensions, always remember to scale them appropriately to the current device. This will ensure your widgets will always behave the same regardless of the device they are running on. Dimension scaling can be done pretty easily relying on the resource system or manually using the code provided below:</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="kd">final</span> <span class="kt">float</span> <span class="n">density</span> <span class="o">=</span> <span class="n">getResources</span><span class="o">().</span><span class="na">getDisplayMetrics</span><span class="o">().</span><span class="na">density</span><span class="o">;</span>
</span><span class='line'><span class="n">mScaledValue</span> <span class="o">=</span> <span class="o">(</span><span class="kt">int</span><span class="o">)</span> <span class="o">(</span><span class="n">UNSCALED_VALUE</span> <span class="o">*</span> <span class="n">density</span> <span class="o">+</span> <span class="mf">0.5f</span><span class="o">);</span>
</span></code></pre></td></tr></table></div></figure>


<p><em><strong>Note</strong>: The information given in this article never mentions multitouch capabilities. This may seem irrevelevant when dealing with a one-finger-only-gesture but this is not the case. Try sliding the host drawer and touching the screen with another finger and you will see it &#8220;jumps&#8221; from one finger to another. This strange behavior happens because the current implementation of the <code>RootView</code> in the Prixing application doesn&#8217;t take into account actions such as <code>MotionEvent#ACTION_POINTER_[DOWN|UP]</code>. That&#8217;s definitely something we have on our ToDo list. It just has a low priority compared to the thousands of other tasks.</em></p>

<h3>When can a gesture be considered as a swipe?</h3>

<p>The Prixing application uses two separate algorithms to determine if a swipe gesture has been started. Indeed, the swipe-to-open algorithm is a little bit more complicated than the swipe-to-close one. In order to get a complete understanding of how to implement such a gesture, we will mainly focus on the most technical one: the swipe-to-open gesture. The implementation involves several constants and techniques that may be difficult to explain textually only. As a consequence, I created a figure (it also gave me a chance to play around with the new amazing Photoshop CS6!) laying everything down. Please note the figure is available in high definition by simply clicking on it:</p>

<p><a href="http://cyrilmottier.com/media/2012/05/the-making-of-prixing-2-swiping-the-fly-in-app-menu/bezel_swipe_start_large.png"><img class="center" src="http://cyrilmottier.com/media/2012/05/the-making-of-prixing-2-swiping-the-fly-in-app-menu/bezel_swipe_start.png"></a></p>

<p>A gesture always starts with a <code>MotionEvent</code> whose action is <code>ACTION_DOWN</code> (the red surrounded arrow). In order to consider this touch event as valid to start a swipe gesture, it must happen on a thin area on the left of the <code>View</code>. In the preceding figure, this area is represented by the translucent green rectangle on the left of the screen. The width of this area is very important. Having a narrow bezel area may make your sliding menu difficult to open. On the contrary, a too large bezel area results in gesture mismatches. Android has no support for bezel swiping by default, as a result, we spent a lot of time at Prixing looking for the perfect dimension. We finally ended up with 30dp.</p>

<p>Having an <code>ACTION_DOWN</code> next to the left edge of the <code>View</code> is far from being enough to consider it as the starting point of a swipe gesture. Indeed, some noisy <code>ACTION_MOVE</code>s may be generated by the system as the user&#8217;s finger is on screen. This is perfectly normal and you have to deal with this. Fortunately, Android includes a method to determine the distance beyond which a gesture is considered as a drag: <code>ViewConfiguration#getScaledTouchEvent()</code>. On every Android build I have seen, the returned value is equal to 8dp scaled to the current display density. As a consequence, the fly-in app menu considers a gesture as accurate and intercepts it when the travelled distance is greater than the touch slop threshold. Technically, it means:</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="n">Math</span><span class="o">.</span><span class="na">hypot</span><span class="o">((</span><span class="n">mCurrX</span> <span class="o">-</span> <span class="n">mStartX</span><span class="o">),</span> <span class="o">(</span><span class="n">mCurrY</span> <span class="o">-</span> <span class="n">mStartY</span><span class="o">))</span> <span class="o">&gt;</span> <span class="n">mTouchSlop</span>
</span></code></pre></td></tr></table></div></figure>


<p>In order to minimize gesture mismatches, we also added a few other conditions to our <code>RootView</code>. All of them are only applied to the swipe-to-open gesture:</p>

<ul>
<li><p>The direction of the gesture must be left-to-right. From a technical point of view, it requires all <code>MotionEvent</code>s to have increasing values on the X-axis.</p></li>
<li><p>The gesture is valid only when the distance made by the traveled distance is greater than <code>ViewConfiguration#getScaledPagingTouchSlop()</code> (16dp) on the X-axis. This method has been introduced with API 8 so you may need to use the <code>ViewConfigurationCompat</code> class or copy its implementation into your code (<code>getScaledPagingTouchSlop()</code> is twice the value returned by <code>getScaledTouchSlop()</code>).</p></li>
</ul>


<p>The algorithm described previously could be summed up pretty simply using the graphic above. In order to consider a gesture as a bezel swiping gesture, we need to ensure all <code>MotionEvent</code>s occur in the striped area, respect the left-to-right direction, and go out of the stripped area via its right edge.</p>

<h3>Dragging the host</h3>

<p>Now it&#8217;s action time! The swipe gesture has been intercepted and we have to drag the host according to user actions. The trick here is to reuse what we have already discovered in the first article of this series: <code>offsetLeftAndRight(int)</code>. As long as the <code>onTouchEvent(MotionEvent)</code> receives <code>MotionEvent#ACTION_MOVE</code>s, the <code>RootView</code> reads the position of the <code>MotionEvent</code> on the X axis and translates the host accordingly. Remember that after being intercepted, the rest of the gesture&#8217;s <code>MotionEvent</code>s are passed to our <code>onTouchEvent(MotionEvent)</code> method.</p>

<h3>Ending a swipe gesture?</h3>

<p>This is where the magic happens! As a UI developer, managing the end of a gesture is awesome. This is where you have to study the gesture as precisely as possible to graphically reflect what the user wants. So we are at the exact moment the user removed his/her finger from the screen. We need to make sure the <code>RootView</code> animates to one of its stable state (opened or closed). This is done in a few steps described on the diagram below. As usual, clicking on it opens the high definition version.</p>

<p><a href="http://cyrilmottier.com/media/2012/05/the-making-of-prixing-2-swiping-the-fly-in-app-menu/action_up_diagram_large.png"><img class="center" src="http://cyrilmottier.com/media/2012/05/the-making-of-prixing-2-swiping-the-fly-in-app-menu/action_up_diagram.png"></a></p>

<h3>Velocity is very important</h3>

<p>This diagram explains almost everything except how to handle velocity. Indeed, <code>RootView</code> actually looks at the velocity of the gesture using the <code>VelocityTracker</code> helper class. This may be used in some cases to determine whether the host has been thrown rapidly enough to close or open the <code>RootView</code>. The best example of this is when you do a pretty &#8220;short&#8221; (let&#8217;s say 32dp) swipe gesture. Tracking the velocity will let the sliding menu be closed/opened whenever the velocity has gone beyond a certain threshold (<code>ViewConfiguration#getScaledMinimumFlingVelocity()</code>). One may also need to normalize the velocity using the <code>ViewConfiguration#getScaledMaximumFlingVelocity()</code> method. When crafting your own UI widgets, always take velocity into account. Velocity is a well known notion and managing it will make your component even more realistic and usable.</p>

<h3>Conclusion</h3>

<p>That&#8217;s it for now. I think we have been through a lot in this second part. It gave you all the elements to create stunning actionable UI widgets. In the third part of this series I will concentrate on some other details such as parallax translation, menu fading, selection arrows and menu hints. We will also cover a point lots of developers have been asking me to reveal: <code>Activity</code> transitions. Indeed, Prixing is made up of tens of <code>Activity</code>. Having animated transitions like we do is &#8220;normally&#8221; impossible on Android &#8230; Shake up your brain cells about it and feel free to leave a comment below if you have an idea of how I managed to do it on Prixing. Stay tuned for more!</p>

<p>Thanks to <a href="http://twitter.com/#!/franklinharper">@franklinharper</a> for reading drafts of this</p>

<hr />

<ol>
<li>Some of you may ask how GMail succeed to do it. I have not reverse-engineered the application but I am pretty sure they did it very easily. Each page of the <code>ViewPager</code> being a <code>WebView</code>, the touch target is always the <code>WebView</code>. Knowing that, you simply have to call <code>canScrollHorizontally(int)</code> on the <code>WebView</code> of the currently selected page.</li>
</ol>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[The Making of Prixing #1: Fly-in App Menu]]></title>
    <link href="http://cyrilmottier.com/2012/05/22/the-making-of-prixing-fly-in-app-menu-part-1/"/>
    <updated>2012-05-22T00:00:00+02:00</updated>
    <id>http://cyrilmottier.com/2012/05/22/the-making-of-prixing-fly-in-app-menu-part-1</id>
    <content type="html"><![CDATA[<p><em><strong>Note</strong>: Everything I published on this website in the past had nothing to do with what I was doing at work. But now for Prixing I&#8217;m changing that, because I think it can be a great opportunity for me to give other developers some advanced Android UI development tips and tricks. As this is the first article linked to my professional work I also have to add a full disclosure: I work for Prixing, but the opinions expressed in my blogs or anywhere else, are my own, and have nothing to do with my employer.</em></p>

<p>We, at Prixing, released a brand new version of our Android application in the middle of April. To sum up, Prixing is a startup created by the French entrepreneur <a href="http://twitter.com/#!/ericlarch">Eric Larchevêque</a>. It aims to help people find product information and the best prices in a localized manner. The company currently only targets the French market but the application can be downloaded regardless of your location. Go to the Prixing&#8217;s <a href="http://play.google.com/store/apps/details?id=fr.epicdream.beamy">Google Play page</a> to download it on your Android device (the current version is only dedicated to handsets) and play with it!</p>

<!-- More -->


<p>I started working at Prixing as the lead mobile software engineer in January of this year. As a huge fan of the Android platform, I mainly worked on making the Android application easier to use and fancier. As a result, tons of changes and improvements were made. After the release of the application, I received several questions regarding the implementation of the UI. I sincerely appreciate having curious developers asking me how I implemented this or that. This series is an attempt to answer all of the questions I received. Instead of sharing great tips to a very restricted set of developers I thought it was way better to share them globally via some blog posts.</p>

<p><em><strong>Note</strong>: Everything I will talk about in this series will probably never feature source code. It is absolutely intentional. Prixing&#8217;s source code is obviously not open-source and chances are high it will remain closed-source in the future. The purpose of these articles is to describe the techniques and methods to use to make astonishing UIs rather than giving ready-to-use snippets of code. Nevertheless, I may open source some interesting and reusable snippets of code in the future. Feel free to leave a comment below so I can anticipate the average number of motivated developers.</em></p>

<p>In this first post we will start with one of the most important UI widgets in Prixing: the fly-in app menu. The figure below gives you a screenshot of the UI widget on a Galaxy Nexus. You can also click on the picture to access a high resolution screenshot and look at the details but I strongly suggest you download the application to fully see how the Prixing fly-in app menu works and what it looks like.</p>

<p><a href="http://cyrilmottier.com/media/2012/05/the-making-of-prixing-fly-in-app-menu-part-1/app_menu_large.png"><img class="center" src="http://cyrilmottier.com/media/2012/05/the-making-of-prixing-fly-in-app-menu-part-1/app_menu.png"></a></p>

<p>I can already hear some of you saying &#8220;That&#8217;s a Facebook-like menu!&#8221;, &#8220;It looks like Path on iOS!&#8221;<sup>1</sup> etc. Indeed, in addition to technical questions, I also received some messages from people who don&#8217;t consider the fly-in app menu as an Android UI pattern. I think I talked a lot lately about what I consider Androidy or not (cf my thoughts dealing with <a href="http://www.cyrilmottier.com/2012/05/03/splash-screens-are-evil-dont-use-them/">splash screens</a> and the <a href="http://www.cyrilmottier.com/2012/03/28/the-pull-to-refresh-an-anti-ui-pattern-on-android/">pull-to-refresh</a> UI patterns). I am not going to talk about it in this series mainly dedicated to development techniques. I am sure some people will soon talk about it and describe whether it is <a href="http://www.androiduipatterns.com/">good</a> or <a href="http://alexanderblom.se/2012/04/23/android-navigation-and-spotify/">not</a>. However, I would like to outline my point and make it clear. Personally, I don&#8217;t think the fly-in app menu is a straight Android UI pattern. I actually believe it is a UI pattern not related to any platform at all. Applied to Android, this pattern works pretty well and doesn&#8217;t go fundamentally against Android principles. The only problem I have with it is the back stack is totally messed up. When looking closer at the pattern you can notice it is pretty much like a classical two-panes screen (in Google Talk or GMail for tablets) mixed with a plain old <code>SlidingDrawer</code>. We decided to use the fly-in app menu pattern in Prixing for three main reasons:</p>

<ul>
<li><p>It is directly accessible from everywhere, regardless of how deep you are in the screen hierarchy, using a simple click and/or swipe gesture</p></li>
<li><p>It presents items in list-manner rather than a paged-manner. This is a pretty big advantage when dealing with a large amount of items as a list-based menu is more understandable than paged-dashboards</p></li>
<li><p>It is not dedicated to Android nor iOS. Consequently, we can have overall application usage consistency among our mobile applications</p></li>
</ul>


<p>I recently found a lot of fly-in app menu implementations (Facebook, 8tracks, Evernote, Spotify, etc.) but found none as polished as the Prixing one. Of course, most implementations are running great but they lack naturalness, easiness, smoothness, etc. or a combination of it. I am not saying the implementation included in Prixing is perfect as we still have some improvements to make but I think it contains a lot of interesting concepts you may need if you want to implement your fly-in app menu or simply enhance it.</p>

<h3>Introduction</h3>

<p>Implementing a fly-in menu requires building a custom layout. Creating a class inheriting from <code>ViewGroup</code> helps you to precisely control how components are being laid out and drawn. Being the root <code>View</code> in Prixing&#8217;s <code>View</code> hierarchy, we named it <code>RootView</code>. The <code>RootView</code> basically contains two child <code>View</code>s: the menu that has to be laid out on the left of the screen and the content view we called the host (mainly because it is always a <code>TitleBarHost</code><sup>2</sup>, a custom implementation of the <code>ActionBar</code> holder paradigm)). The purpose of the <code>RootView</code>&#8217;s <code>onLayout</code> is to lay out the menu and the host in a stacked fashion as a <code>FrameLayout</code> would do. The only difference remains in the width taken by the menu which is currently the entire available width minus the app menu button width (44dp).</p>

<h3><code>RootView</code> == <code>SlidingDrawer</code>?</h3>

<p>As we discussed earlier, the <code>RootView</code> is pretty much like a <code>SlidingDrawer</code>. As a consequence, APIs are very similar and include methods to action the <code>RootView</code> in animated fashion - <code>animate[Close|Open|Toggle]()</code> - or not - <code>[close|open|toggle]()</code> - and some methods to retrieve the current <code>RootView</code>&#8217;s state - <code>is[Opened|Moving|Animating]()</code>. The first natural feature to implement is the &#8220;open-by-clicking&#8221; the app-menu button. In order to do so, we simply applied an <code>OnClickListener</code> to the app-menu button that does nothing more than calling <code>RootView#animateToggle()</code>.</p>

<h3>Scrolling content using <code>Scroller</code></h3>

<p>Implementing open/close animations can be pretty simple starting from Android 3.0, thanks to the new animation framework. Unfortunately, Prixing had to be compatible with devices running on Android down to the version 2.1. As a consequence, we decided to implement the open/close animation manually. To be honest, it can be done fairly easily using classes from the Android framework. Animating a value can be done manually or using a <code>Scroller</code>/<code>OverScroller</code>. <code>Scroller</code> is a helper class that can be used to compute position values of objects scrolling or flinging in a 2 dimensional space. Once you want to start animating the menu simply call <code>Scroller#startScroll</code> and keep calling <code>Scroller#computeOffset</code> every 16ms (60 frames per second) using a <code>Handler</code> and the <code>Handler#postDelayed(Runnable, long)</code> method. In the <code>Runnable</code> that gets executed every 16ms, reading the current position of the <code>Scroller</code> gives you the position at which your object should be translated to.</p>

<h3>Actually translating the host using <code>offsetLeftAndRight</code></h3>

<p>Translating the host value is done by adding, in the <code>onLayout</code> an integer containing the value to add to the original X position of the host. We will call this variable <code>mHostOffsetX</code>. Updating <code>mHostOffsetX</code> in the previously described <code>Runnable</code> and calling the well known <code>requestLayout()</code> would get the job done. Using this method would run perfectly but your application may suffer from severe lags. Indeed, using <code>requestLayout()</code> repeatedly is usually a bad idea as it forces the system to measure and layout all <code>View</code>s in the hierarchy. Translating the host view (in other words, your entire content) doesn&#8217;t require it to be laid out again as nothing but the position of the host has changed. Fortunately, the system provides a great method called <code>offsetLeftAndRight(int)</code> that will translate the host by the given amount of pixels from its current position. Do not forget to call <code>invalidate()</code> to force the <code>RootView</code> to redraw itself and reflect the translation on screen.</p>

<h3>Optimized rendering</h3>

<p>Since Android 2.1, the system avoids rendering a <code>View</code> when it is not visible. A <code>View</code> is considered as &#8220;not visible&#8221; when its bounds are outside screen bounds or if it is entirely covered by a <code>View</code> which returns <code>true</code> to a call to <code>View#isOpaque()</code>. To ensure the rendering pipeline does not try to uselessly draw the menu when it is completely hidden (closed state), just set its visibility to <code>View.GONE</code>. It won&#8217;t help in many cases (API level greater to 2.1) but using this trick is pretty straightforward and easy to include in your code. In other words, setting the menu visibility to <code>View#GONE</code> will ensure your application runs the same as it would have without the menu.</p>

<h3>Smoother closing/opening animations</h3>

<p>If you look attentively to the opening/closing animation you will probably notice it is pretty &#8220;brutal&#8221;. Indeed, the drawer opens/closes in a linear fashion. Because of this, the user has a strange and negative feeling the menu &#8220;crashes&#8221; abruptly when it has arrived at its final position. This &#8220;crash&#8221; is actually due to the default behavior of the <code>Scroller</code> class. By default, the <code>Scroller</code> computes the current position of an object using a <code>LinearInterpolator</code>. This means the current position is determined by the following formula (simplified to a single axis):</p>

<p>x<sub>cur</sub>(t<sub>cur</sub>) = x<sub>start</sub> + distance * ((t<sub>cur</sub> - t<sub>start</sub>) / duration)</p>

<p>In this formula the position (xcurrent) is a function of the current time. <em>distance</em> indicates the overall distance of the animation and <em>duration</em> the total duration of the animation. The main problem with this formula is it doesn&#8217;t include an interpolation function. This is actually a simplified version of the complete formula based of the hypothesis interpolator(t) = t. The complete formula is given below:</p>

<p>x<sub>cur</sub>(t<sub>cur</sub>) = x<sub>start</sub> + distance * interpolator((t<sub>cur</sub> - t<sub>start</sub>) / duration)</p>

<p><em>interpolator(t)</em> is a function defined on [0, 1]. It usually returns values in the [0, 1] range but this is not mandatory as having returned values outside of this range will indicate overshooting animations. By modifying the <code>Interpolator</code>, you can easily change the way the animation performs. In Prixing, we started by using some of the framework-provided <code>Interpolator</code>s but weren&#8217;t satisfied so we created a <code>SmoothInterpolator</code> which is basically a polynomial function:</p>

<p>interpolator(t) = (t-1)<sup>5</sup> + 1</p>

<p>The difference between the two interpolators is given on the figure below. The green curve describes the <code>Interpolator</code> used in the current build of Prixing. The red curve is the <code>Scroller</code>&#8217;s default <code>Interpolator</code>:</p>

<p><img class="center" src="http://cyrilmottier.com/media/2012/05/the-making-of-prixing-fly-in-app-menu-part-1/interpolators.png"></p>

<p>As you can easily see, passing a <code>SmoothInterpolator</code> when creating your <code>Scroller</code> will make the animation way smoother. The drawer will open/close very rapidly at the beginning but will slow down at the end to reach quietly and smoothly its final position. Do not hesitate to play around with <code>Interpolator</code>s as it helps you create stunning animation curves and may make your UI way more polished from a user point of view.</p>

<h3>Some interesting additional features</h3>

<p>This first article concentrates on having a basic <code>RootView</code> that can be opened/closed programmatically or via a simple click on the app-menu button. In the manner of Angry Birds, Prixing uses the system menu button to easily toggle the <code>RootView</code>. It is implemented at the <code>Activity</code> level by calling <code>RootView#animateToggle()</code> in <code>Activity#onKeyUp(int, KeyEvent)</code> but it could also be implemented at the <code>View</code> level using <code>View#onKeyUp(int, KeyEvent)</code></p>

<p><em><strong>Note</strong>: Eagle eyed people may have noticed the current implementation of Prixing is based on <code>Activity#onKeyDown(int, KeyEvent)</code> rather than <code>Activity#onKeyUp(int, KeyEvent)</code>. This is definitely a bug of mine that has been fixed in a recent release.</em></p>

<p>To prevent the user from finishing the current screen when the menu is open, it could be smart to first ensure the menu is closed. You can do it by simply calling <code>RootView#animateClose()</code> in <code>Activity#onBackPressed()</code> when the menu is fully opened.</p>

<p>Being an actively used control, we need to ensure the app menu button is very easily accessible. The best way to do so is to virtually enlarge the touchable area of the button. I seriously don&#8217;t know why but this is not something that is done by default on the <code>ActionBar</code>. The <code>UINavigationBar</code> - iOS <code>ActionBar</code> equivalent has a built-in similar mechanism which makes all buttons impressively accessible. Prixing is based on a custom implementation of the <code>ActionBar</code> so we have simply set a <code>TouchDelegate</code> to the app menu button. It enlarges the touchable area with a 30dp wide frame. If you want to do it I strongly suggest you read a previous article of mine dealing with <a href="http://www.cyrilmottier.com/2012/02/16/listview-tips-tricks-5-enlarged-touchable-areas/">enlarged touchable areas</a>.</p>

<h3>Conclusion</h3>

<p>That&#8217;s it, at least for now! We have covered everything you need to create a panel that can slide from a closed state to an open state or vice versa. In future articles we will continue enhancing our <code>RootView</code> by managing state of the art features such as bezel swiping, parallax translation, menu fading, selection arrow, menu hint, etc. I have tried to cover everything in this article but I may have forgot some interesting techniques. Do not hesitate to tell me if you want more explanations on a particular feature. Stay tuned for more.</p>

<p>Thanks to <a href="http://twitter.com/#!/foxykeep">@foxykeep</a> and <a href="http://twitter.com/#!/franklinharper">@franklinharper</a> for reading drafts of this</p>

<hr />

<ol>
<li><p>When I wrote the article dealing with the <a href="http://www.cyrilmottier.com/2012/01/17/starting-considering-android-as-a-capable-os/">scrolling info panel</a>, I criticized how poor, in term of functionalities, the Android version of the application was compared to the iOS one. I explained how to implement a scrolling info panel and I recently received an update of the Path application that includes the UI widget. I really don&#8217;t know if Path used my article to implement it. This fly-in app menu is something the Android Path app is also missing. If you are a developer at Path, feel free to use these tricks and post a comment to thank me in return!</p></li>
<li><p>Implementing a fly-in app menu with the built-in Android <code>ActionBar</code> requires using several awful hacks one of which consists of considering the <code>View</code> returned by <code>Window#getDecorView()</code> as a <code>FrameLayout</code>. As a bitter enemy of hacks I couldn&#8217;t resolve myself to do it and decided to write my own implementation of the <code>ActionBar</code> paradigm. Let&#8217;s be honest: this is far from being ideal&#8230;</p></li>
</ol>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Splash Screens are Evil, Don't Use Them!]]></title>
    <link href="http://cyrilmottier.com/2012/05/03/splash-screens-are-evil-dont-use-them/"/>
    <updated>2012-05-03T00:00:00+02:00</updated>
    <id>http://cyrilmottier.com/2012/05/03/splash-screens-are-evil-dont-use-them</id>
    <content type="html"><![CDATA[<p><em><strong>Note</strong>: People who bought my book dealing with Android development will probably notice this article looks like a section of the fourth chapter &#8220;UI &amp; UX: major components for a great user experience and the Android logic&#8221;. Let&#8217;s be honest, this blog post is pretty much an enhanced translation of a section of my book. For those who don&#8217;t know about this book, written in French, the title is &#8220;Développez pour Android&#8221;. Released about a year ago, it deals with Android development in general and particularly focuses on making highly optimized Android applications. If you are interested in this book, you can buy/download it <a href="http://www.digitbooks.fr/catalogue/9782815002028.html">here</a>.</em></p>

<p>I have recently seen many Android applications starting with what I call a splash screen. A splash screen is an image that takes the entire screen space and usually shows branding information about the application (logo of the company, logo of the application, etc.). This screen is generally visible for a small amount of time while the application is starting or loading some resources in the background. I am pretty sure you have already seen some of the popular Android applications below featuring a splash screen on startup:</p>

<!-- More -->


<p><img class="center" src="http://cyrilmottier.com/media/2012/05/splash-screens-are-evil-dont-use-them/popular_apps_splash_screens.jpg"></p>

<p>Once again, from my point of view, the splash screen paradigm is a port of the iOS equivalent. Some of you may start thinking I hate iOS because it influences Android in a really bad way. I often consider lots of mistakes in Android applications are due to stupid ports of iOS apps to Android. However I don&#8217;t consider iOS as a crappy mobile platform. I honestly believe iOS is an awesome mobile OS. Issues are not related to OSes themselves but to how people incorrectly understand them and use them. The splash screen is one of the best example of how people are misleading OSes in general. Being widely used on iOS, the UI pattern is also actively discouraged by Apple! Indeed, if you look closely to the iOS documentation you will notice Apple encourages developers to use launch images. Launch images are very different from splash screens as they are images used to pretend an application launched rapidly. On iOS, the system displays the launch image instantly when the user starts your application and until the app is fully ready to use. As soon as your app is ready for use, it displays its first screen, replacing the launch placeholder image. As a result, supplying a launch image is the best way to improve user experience. The graphic below shows you the launch image on the right that is used in the built-in &#8220;Stock&#8221; iOS apps:</p>

<p><img class="center" src="http://cyrilmottier.com/media/2012/05/splash-screens-are-evil-dont-use-them/launch_image.jpg"></p>

<p>The iOS documentation clearly specifies launch images should not be used as an opportunity to display branding information. Unfortunately, rules are made to be by-passed and iOS folks understood that. I honestly can&#8217;t blame them! They have simply used a functionality offered by the framework and slightly modified launch images to use them as splash screens. What is very disappointing to my mind is the same pattern is currently happening on Android. I am strongly convinced splash screens are not appropriate on Android for several reasons I would like to share with you:</p>

<ul>
<li><p><strong>A splash screen prevents the user from using the application.</strong> As far as I know, it is not explicitly written in Android guidelines but Android has been primarily designed to help the user achieving and completing tasks rather than offering features. In order to do so, the entire system focuses on what users want to do and letting them do it as quickly as possible. This fastness is achieved by rendering the overall UI in a insanely fast fashion and never blocking the user. Some of the best examples of this are the notification area (I guess iOS users will always remember the so annoying and blocking popups - <code>UIAlertView</code>s - when receiving a text message pre iOS5), the advanced multitasking mechanism, the launcher widgets, the fast transition animations (I don&#8217;t have the exact numbers but the default transition between two <code>Activity</code> is twice as fast as the transition between two <code>UIViewController</code>s put in a <code>UINavigationController</code>), etc. In a nutshell, being blocked is not something an Android user is used to nor wants to be confronted with.</p></li>
<li><p><strong>Most of the time, it is not necessary</strong> A splash screen can be used to make resources available before an application starts. Personally I think it is not necessary in 98% of the cases. It may be useful for applications actively relying on heavy resources such as Google Earth, Sky Map, or games but this is not applicable to simple utility applications such as feed readers, social network apps, news readers, etc. You should not require a network connection at startup nor do heavy computations. Always keep in mind, <code>Activity</code> launching is blazingly fast on Android. The Android team at Google spent a lot of time - and I am sure they are still spending a lot of time working on it - ensuring applications and the <code>Activity</code> class launches very rapidly. As a result it is quite easy to have an application and its first <code>Activity</code> up and ready in less than 400ms. Also always keep in mind that an application displaying a splash screen is also completely up and running from a system perspective.</p></li>
<li><p><strong>Displaying a launch image or splash screen in not part of the framework<sup>1</sup></strong>. I don&#8217;t know the exact percentage of the Android documentation I have read at least once but I assure you the number is pretty high! I have never seen a method, class or xml resource explicitly dealing with launch images or splash screens. This obviously proves the Android team never considered the launch image trick as necessary or easy to implement.</p></li>
<li><p><strong>Adding once-viewed resources increase the size of your APKs</strong>. In order to make a great splash screen, one may usually need to add several resources to the APK (bitmaps, layouts, 9-patchs, etc.). This may uselessly and drastically increase the size of your APK making it more difficult to download/install. It may also drive several of your users mad if they have a pretty memory-constrained device. I think the best way to demonstrate the horrible consequences of launch images is to give the example of a universal iOS app (a universal app is an app running both on iPad and iPhone). As I previously explained, iOS fakes fast application startup rapidly displaying a launch image. If you look closely at the iOS documentation, you will notice the iPhone requires two default images (only in portrait, one for each density - 320x480 and 640x960) while the iPad requires 4 images (one for each orientation and density - 768x1004, 1536x2008, 1024x748 and 2048x1496). Knowing iOS requires launch images encoded using the PNG compression algorithm, you will likely create an application that is almost 5Mo-sized (depending on how much your launch images are compressed) and only displays a splash screen!</p></li>
<li><p><strong>Implementing a great splash screen is very difficult and tedious</strong> Developing on Android requires dealing with a lot of resolutions, densities, orientations, etc. In general, the built-in resource switching mechanism is enough. In the context of splash screen development in which absolute layouts are usually required, it is generally not sufficient. Moreover, you also have to deal with Android&#8217;s <code>Activity</code> lifecycle. I have seen many application falsely redisplaying a splash screen in low memory conditions, because the developers forgot to save the splash-screen-has-been-displayed flag in <code>onSaveInstance(Bundle)</code>. The worst bug I am used to see is an app auto-magically restarting itself after the user got out of it. This is mostly because splash screen are implemented using a <code>Runnable</code> posted with a certain delay in a given <code>Handler</code>. Not removing it from the <code>Handler</code>&#8217;s queue in <code>onPause()</code> will let the application restart itself. Developers should rather focus on making their app launch time as short as possible rather than designing a well-working splash screen. Equally, designers should spend more time on making Android apps Androidy&#8230;</p></li>
<li><p><strong>Users don&#8217;t care about branding at launch time</strong>. When a user is starting an application, he/she is expecting it to fully fulfill what it is intended for. Making your applications responsive and fast is part of that job. Having a splash screen or a long startup time is the best option to do the complete opposite of what the user wants. If you really need to brand your application (and I encourage you to do so to create visually unique looking apps), I strongly suggest you to style the <code>ActionBar</code>, add an &#8216;About&#8217; screen, use the background as a display area, etc. Doing in-app branding is the best opportunity to spread your message to your users as it will remain visible on all application&#8217;s screens. Believe me, as a user, when I open the Facebook app, I already know I am using the Facebook app. There is no need to display a huge Facebook logo in the middle of my screen.</p></li>
<li><p><strong>A splash screen indicates a single-entry point application</strong>. Just a few application use this technique but Android applications may have several entry points. The best examples of that are Maps, Google+, Contacts/Phone or, more recently, Facebook. This can be done very easily using the appropriate <code>&lt;intent-filter /&gt;</code>s on your entry point activities in the Android manifest. I&#8217;m not saying this is something that is easy to apprehend for a user but it&#8217;s available from a framework perspective. This feature is not supported by iOS. Because of this, lots of people falsely consider an app has a single entry point and use it to add a splashscreen.</p></li>
<li><p><strong>In a multitasking context, launch images have no meaning</strong>. In an ideal multitasked environment (ideal means en environment with access to unlimited resources), a splash screen is diplayed only once: the first and only time an application is started. Indeed, once an application is started, there is no need to display the splash screen again as the application will always remain in memory. Android has been primarily designed as a massively multitasked OS and therefore doesn&#8217;t stick to the splash screen paradigm at all.</p></li>
</ul>


<h2>Conclusion</h2>

<p>When Apple launched the first iOS SDK, it may have made a great decision by enabling developers to fake a fast application startup via a launch image. Unfortunately, iOS evolution - iOS now runs on several densities and devices and supports multitaking - and the fact that developers completely hacked the way launch images are used made it a big mistake. Spending time on ensuring applications are opened rapidly would have been a better option. On the other hand, Android has been built to deal with an insanely large amount of devices. Please start taking this into account and continue fighting against the iOS enthousiasts who think the iOS way is the only way. iOS and Android are both awesome mobile OSes. They both have some particularities that need to be taken into account when developing applications. Understanding an iOS app is appropriate on iOS, and an Android app is appropriate on Android, etc. is the path to making awesome multiplatform applications.</p>

<hr />

<ol>
<li>Android has actually always had a built-in mechanism similar to launch images. I won&#8217;t talk about it as it could be the topic of an entire article. Moreover, writing about it in an article severely criticizing the splash screen paradigm would be the best way to make this blog post pointless.</li>
</ol>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Tweeted Android Development Tips]]></title>
    <link href="http://cyrilmottier.com/2012/04/20/android-tips-tweets/"/>
    <updated>2012-04-20T00:00:00+02:00</updated>
    <id>http://cyrilmottier.com/2012/04/20/android-tips-tweets</id>
    <content type="html"><![CDATA[<p>Some of you (or should I say some of my followers - <a href="http://twitter.com/#!/cyrilmottier">@cyrilmottier</a>) may have noticed I have been tweeting several tips dealing with Android development lately. I received a lot of great feedback about those tips and I would like to thank everybody for their support. Some people also asked me to make a blog post gathering together all of the Android dev tips I have tweeted; so here it is.. Starting from now, I will try to update this article as soon as I tweet a new tip. Have fun with these tips and feel free to use the comment system at the bottom of this page if you have any question.</p>

<!-- More -->


<ul>
<li><p><a href="https://twitter.com/cyrilmottier/status/206009115036762112">25 May 2012</a>: ‪‪Null your ViewStub references after being inflated (mViewStub = null). It lets the GC garbage it and saves memory. #androidtip #androiddev‬</p></li>
<li><p><a href="http://twitter.com/cyrilmottier/status/198426116803923970">9 May 2012</a>: ‪‪#androidtip‬ (for experts): Create custom Views with some texts in it using Layout (<a href="http://developer.android.com/reference/android/text/Layout.html">http://developer.android.com/reference/android/text/Layout.html</a>) and its subclasses. ‪#androiddev‬</p></li>
<li><p><a href="http://twitter.com/cyrilmottier/status/198426116803923970">4 May 2012</a>: ‪#androidtip‬: When working with ContentProviders you often have to play with Uris. ContentUris is here to help you (<a href="http://developer.android.com/reference/android/content/ContentUris.html">http://developer.android.com/reference/android/content/ContentUris.html</a>)</p></li>
<li><p><a href="http://twitter.com/#!/cyrilmottier/status/197665804152614912">2 May 2012</a>: #androidtip: Need a &#8220;triplean&#8221; in your code (a boolean with 3 possible values : unknown, true and false)? Use a Boolean (null, true, false)</p></li>
<li><p><a href="http://twitter.com/#!/cyrilmottier/status/197002943285833728">30 Apr 2012</a>: #androidtip: Starting API 11, you can draw dividers between your Views in a LinearLayout (<a href="http://developer.android.com/reference/android/widget/LinearLayout.html#setShowDividers(int">http://developer.android.com/reference/android/widget/LinearLayout.html#setShowDividers(int)</a>)) #androiddev #android</p></li>
<li><p><a href="http://twitter.com/#!/cyrilmottier/status/195856078888640512">25 Apr 2012</a>: #androidtip: If you want to know if an URL is valid, HTTP, HTTPS, etc. use the android.webkit.URLUtil (<a href="http://developer.android.com/reference/android/webkit/URLUtil.html">http://developer.android.com/reference/android/webkit/URLUtil.html</a>) class</p></li>
<li><p><a href="http://twitter.com/#!/cyrilmottier/status/195168854811488257">25 Apr 2012</a>: #androidtip: Starting from API 11 you can reuse Bitmap (using BitmapFactory#Options#inBitmap) in order to avoid memory allocations.</p></li>
<li><p><a href="http://twitter.com/#!/cyrilmottier/status/194807119919329281">24 Apr 2012</a>: #androidtip When displaying web content in a Fragment you can use the WebViewFragment: a Fragment managing a WebView. #androiddev</p></li>
<li><p><a href="http://twitter.com/#!/cyrilmottier/status/192984704998313986">19 Apr 2012</a>: Use android:foreground on your FrameLayout to overlay a <selector /> Drawable on opaque images in itemviews</p></li>
<li><p><a href="http://twitter.com/#!/cyrilmottier/status/192603618992603137">18 Apr 2012</a>: Check whether a View is actually visible using View#isShown(). It will check your View visibility AND all of its ancestors</p></li>
<li><p><a href="http://twitter.com/#!/cyrilmottier/status/192243273723682817">17 Apr 2012</a>: Remember you can start the Settings app from yours on a given screen using the actions described in <a href="http://developer.android.com/reference/android/provider/Settings.html">http://developer.android.com/reference/android/provider/Settings.html</a></p></li>
<li><p><a href="http://twitter.com/#!/cyrilmottier/status/191881718070906880">16 Apr 2012</a>: Pre-populate Intent chooser using LabeledIntents (Intent with a name/icon) and the Intent#EXTRA_INITIAL_INTENTS extra</p></li>
<li><p><a href="http://twitter.com/#!/cyrilmottier/status/190787853456916480">13 Apr 2012</a>: When creating your own custom view with scrollable content, don&#8217;t forget to use EdgeEffect (<a href="http://developer.android.com/reference/android/widget/EdgeEffect.html">http://developer.android.com/reference/android/widget/EdgeEffect.html</a>)</p></li>
<li><p><a href="http://twitter.com/#!/cyrilmottier/status/190435662514757632">12 Apr 2012</a>: Need View#onConfigurationChanged on API &lt; 8? Use a BroadcastReceiver or forward your Activity&#8217;s onConfigurationChanged. Here&#8217;s a sample of using a BroadcastReceiver: <a href="http://gist.github.com/2367432">http://gist.github.com/2367432</a></p></li>
<li><p><a href="http://twitter.com/#!/cyrilmottier/status/190075082155114496">11 Apr 2012</a>: Stop uselessly fetching resources when your WebViews aren&#8217;t visible anymore with WebView#<a href="">onPause|onResume</a> (API >= 11)</p></li>
<li><p><a href="http://twitter.com/#!/cyrilmottier/status/190056328377540609">11 Apr 2012</a>: With split content (ListView + content), call setActivated(true) on the appropriate item view to indicate the current section</p></li>
<li><p><a href="http://twitter.com/#!/cyrilmottier/status/189693005085679616">10 Apr 2012</a>: Don&#8217;t forget to use android:textIsSelectable=&#8221;true&#8221; (API >= 11) on your TextView to let users copy your TextView content</p></li>
<li><p><a href="http://twitter.com/#!/cyrilmottier/status/188258116700352512">6 Apr 2012</a>: Java 5 accepts return type refinement. Return your object type instead of Object in Adapter#getItem(int). It saves you a cast</p></li>
<li><p><a href="http://twitter.com/#!/cyrilmottier/status/187521417179443200">4 Apr 2012</a>: Do not forget to call HandlerThread.quit() (or HandlerThread.getLooper().quit() if API &lt; 5) when you no longer need it</p></li>
<li><p><a href="http://twitter.com/#!/cyrilmottier/status/187167379585900545">3 Apr 2012</a>: Stop developing countdown algorithms, use the built-in CountDownTimer (<a href="http://developer.android.com/reference/android/os/CountDownTimer.html">http://developer.android.com/reference/android/os/CountDownTimer.html</a>) #android #androiddev</p></li>
<li><p><a href="http://twitter.com/#!/cyrilmottier/status/186803096373051394">2 Apr 2012</a>: Add margins to your ListView selection areas using a SelectionBoundsAdjuster (<a href="http://developer.android.com/reference/android/widget/AbsListView.SelectionBoundsAdjuster.html">http://developer.android.com/reference/android/widget/AbsListView.SelectionBoundsAdjuster.html</a>) #android #androiddev</p></li>
</ul>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA["Pull-to-refresh": an Anti UI Pattern on Android]]></title>
    <link href="http://cyrilmottier.com/2012/03/28/the-pull-to-refresh-an-anti-ui-pattern-on-android/"/>
    <updated>2012-03-28T00:00:00+02:00</updated>
    <id>http://cyrilmottier.com/2012/03/28/the-pull-to-refresh-an-anti-ui-pattern-on-android</id>
    <content type="html"><![CDATA[<p><em><strong>Note</strong>: This article has been written prior to the recent article on <a href="http://techcrunch.com/2012/03/27/pull-to-refresh-the-patent/">Techcrunch</a> which states &#8220;pull-to-refresh&#8221; has been patented by Twitter. I agree with most of this article when it comes to iOS. My only disagreement is I don&#8217;t think this patent is the reason why Apple didn&#8217;t use it in their applications &#8230;</em></p>

<p>As an iOS &amp; Android developer/user I spend a lot of time looking at and playing with mobile applications. Since 2007 (the year mobile really had a leap forward thanks to the iPhone), mobile UI patterns have been introduced, enhanced and reused by applications. The Android platform has always been a very productive environment for UI designers and recently has become even more so. This rapid growth and evolution is probably a direct consequence of the increasing number of Android developers and applications. Recently, I have noticed some emerging UI patterns. Among them is the well known &#8220;pull-to-refresh&#8221; pattern.</p>

<p>As far as I know, &#8220;pull-to-refresh&#8221; has been primarily developed on iOS. It consists of adding an additional cell at the top of your <code>ListView</code> that remains hidden most of the time. As suggested by its name, you can pull down your ListView to make the widget appear. When you pull enough, a smooth animation indicates you can release the <code>ListView</code> in order to launch the refresh process. The cell contents switches to an activity indicator for the duration of the refresh. When the refreshing has been completed, the list scrolls in order to hide the additional cell. The screenshots below show you the complete interaction model. Please note I have used the official Twitter application. However, it doesn&#8217;t mean I appreciate this application. To be honest, I think it is in my top 10 of the least Androidy or should I say the most iOSy on Android &#8230; From my point of view, Twitter on Android is exactly the kind of app you shouldn&#8217;t do (grouped <code>UITableView</code>, <code>UINavigationBar</code>, <code>UITabBar</code>, <code>UISegmentedControl</code>, iOS look &#8216;n feel, etc.).</p>

<!-- More -->


<p><img class="center" src="http://cyrilmottier.com/media/2012/03/the-pull-to-refresh-an-anti-ui-pattern-on-android/pull_to_refresh.jpg"></p>

<p>To be honest, I love this UI pattern on iOS. I think it is extremely &#8220;natural&#8221;: most recent items are usually on top of the list so it&#8217;s natural to scroll further to the top to access to the most recent items. It totally fits iOS platform philosophy. When it comes to Android, lots of developers and companies have a tendency to reproduce this pattern on the Android version of their application. I consider it a huge mistake and here is my point of view:</p>

<ul>
<li><p>The &#8216;pull-to-refresh&#8217; UI pattern is mainly dedicated to power users. I honestly don&#8217;t think it is as intuitive as a simple but clear &#8220;Refresh&#8221; button. Lots of developers use this UI pattern without thinking about their actual audience and how technophile they are. Most of the time a &#8220;Refresh&#8221; button would have been way easier to implement from a developer perspective and to use from a user point of view. I believe this is one of the main reasons Apple never used it in any of their stock iOS applications.</p></li>
<li><p>A lot of people primarily consider &#8216;pull-to-refresh&#8217; as a way to save space on screen. I can&#8217;t disagree with this argument! It obviously saves space as nothing is visible on screen at all! Hiding the essential refresh button from normal users will probably just leave room for another useless button. On iOS, the framework forces the developer to have a single button on the right of the <code>UINavigationBar</code> (<code>ActionBar</code> equivalent on iOS)<sup>1</sup>. Saving as much space as possible on iOS may be a good practice, it is not a big issue on Android. On Android, the system will automatically adapt the <code>ActionBar</code> appearance to ensure the maximum amount of actions is visible. You often have enough room to add two or three actions (regardless of the device you are running on) which is enough to maintain the main features on screen. For instance, in the Twitter application, it would have been possible to have a &#8220;Refresh&#8221; button next to the &#8220;New tweet&#8221; button.</p></li>
<li><p>The pull-to-refresh pattern is not easily visible to the user. The Android UI philosophy is to make the UI as clean and sober as possible. Unfortunately developers have a tendency to misunderstand this UI rule. They often over-engineer the UI by putting buttons everywhere, making their applications look like a cockpit! The actual rule is to make the UI as clear as possible by <strong>prioritizing</strong> and ensuring it remains accessible. Keep in mind that a mobile application is not intended to give the same level of functionality as its desktop/web equivalent. A mobile app has to be concise and has to provide an extremely well designed small subset of all of the product&#8217;s features. On iOS, people may see &#8220;pull-to-refresh&#8221; quite easily when the screen is displayed or when they are rapidly flinging the <code>UITableView</code> to its top. In that case, the list will bounce when reaching the top edge, letting the user see the &#8220;pull-to-refresh&#8221; widget. As far as I know, there is no equivalent on Android as all implementations are only visible from the very top of the <code>ListView</code>.</p></li>
<li><p>You have to be at the top of the <code>ListView</code> to refresh it. This may be easy on iOS as a click on the status bar automatically scrolls all <code>UIScrollView</code>s on screen to their top. Unfortunately this is not a default behavior on Android. As a result, a user who has reached the bottom of a <code>ListView</code> will have to scroll all the way up to the first item and then ask for a &#8216;Refresh&#8217;. Pretty boring, isn&#8217;t it?</p></li>
<li><p>It is not compliant with how Android represents scrollable contents. To my mind, this is the biggest issue when using &#8220;pull-to-refresh&#8221; in Android apps. On iOS, most scrollable containers inherit from <code>UIScrollView</code> which nicely &#8216;bounces&#8217; when at least one of the edges is reached. As a result, creating a UI widget on top of a <code>UIScrollView</code> will let you benefit from the amazingly great bouncing mechanic that Apple implemented. It improves consistency and enforces its adoption by the users. Because of this, enhancing the &#8216;edge bouncing&#8217; property with a &#8220;pull-to-refresh&#8221; widget is pretty natural to iOS users. Android users are not familiar with bouncing scrollable containers<sup>2</sup>. I am not saying Google didn&#8217;t make a mistake when they released the first version of Android not including such a nice behavior. It&#8217;s probably because the early Android devices had screens with lots of afterglow: having a bouncing animation would have resulted in having a blurry screen while the <code>ListView</code> would be springing back to its final position. I&#8217;m not happy with this either but I consider we now have to deal with it and stop misleading the user by changing how scrollable containers scroll at every new release. Google recently introduced the edge effect (see <a href="http://developer.android.com/reference/android/widget/EdgeEffect.html"><code>EdgeEffect</code></a> for more information) so we have to stick to it. The pull-to-refresh is clearly not compatible with the edge effect (see screenshot below).</p></li>
</ul>


<p><img class="center" src="http://cyrilmottier.com/media/2012/03/the-pull-to-refresh-an-anti-ui-pattern-on-android/edge_effect.jpg"></p>

<ul>
<li><p>Most of the time the &#8216;pull-to-refresh&#8217; is not necessary: I have seen many applications using the &#8216;pull-to-refresh&#8217; pattern for items having a low &#8220;update rate&#8221;. As a consequence, implementing the &#8220;pull-to-refresh&#8221; pattern in those cases is almost useless. There is a little chance the list will need to be updated while the user is looking at it. Android has several mechanisms and callbacks you may use to refresh the contents when appropriate. Always prefer considering a smart and automatic refreshing mechanism. There is nothing better than simplifying the UI by anticipating what the user wants and doing it for him. For instance, you can look for new contents at every <code>onResume</code> calls, every X minutes, etc. You may also use components such as <code>Service</code> to refresh your contents in the background at fixed intervals of time (that has no equivalent on iOS) or the Cloud 2 Device Messaging (C2DM) service to push the new contents only when strictly necessary.</p></li>
<li><p>When visible, the &#8220;pull-to-refresh&#8221; widget is pretty intrusive compared to a regular &#8220;Refresh&#8221; button. The best example of this is probably the latest GMail application. When tapping on the &#8220;Refresh&#8221; button, it turns into an indeterminate <code>ProgressBar</code> while refreshing. You can continue reading your contents while still knowing whether or not the refresh is in progress.</p></li>
</ul>


<h3>Conclusion</h3>

<p>I know some of you totally disagree with what I said in this article. As a huge fan of the &#8216;pull-to-refresh&#8217; UI pattern on iOS I can&#8217;t blame you. I just wanted to show you that stupidly porting UI widgets from one platform to another is never a good practice. Please always consider platform differences when developing an application on different OSes. If you are like me, a developer using an Android device a daily basis and surrounded by iOS users (designer, boss, etc.) then you will have to fight everyday to explain that Android is different. It may sound weird to say that to people who &#8220;think different&#8221; but I actually do it everyday. It&#8217;s an ongoing fight. When I develop an application on several platforms I always ensure they all have the same set of functionalities but I always redesign the UI where necessary. That&#8217;s the price to pay to get an Android app on Android, an iOS app on iOS, etc. and have non-disoriented users.</p>

<hr />

<ol>
<li><p>Technically speaking you can add several buttons to a <code>UINavigationBar</code>. For instance you may add a button on the left but this area is often reserved by the &#8220;back&#8221; button. You may also add a control in the center of the <code>UINavigationBar</code> but you will lose the <code>UINavigationBar</code>&#8217;s title. If you really want to add several buttons on the right of your <code>UINavigationBar</code>, you will often end up with tricks such as using a custom view (a <code>UISegmentedControl</code> for instance) in your <code>UIBarButtonItem</code>.</p></li>
<li><p>I know some of you may mention some manufacturers implementations. Personally, I love how the <code>UIScrollView</code> (and of course its <code>UITableView</code> descendant) bounces on iOS but most of the implementations I have seen on Android so far are not great. They either don&#8217;t feel natural or are not consistent with the rest of the system. For instance, Samsung implemented it, and the movement is quite OK. But is not consistent with the rest of the framework: neither <code>View</code> (which has a basic scrolling support) nor <code>ScrollView</code> (even worse!) bounce.</p></li>
</ol>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[ListView Tips & Tricks #5: Enlarged Touchable Areas]]></title>
    <link href="http://cyrilmottier.com/2012/02/16/listview-tips-tricks-5-enlarged-touchable-areas/"/>
    <updated>2012-02-16T00:00:00+01:00</updated>
    <id>http://cyrilmottier.com/2012/02/16/listview-tips-tricks-5-enlarged-touchable-areas</id>
    <content type="html"><![CDATA[<p><em><strong>Edit (02/24/12)</strong>: Fix a potential <code>NullPointerException</code> in the removeDelegate(TouchDelegate) method of TouchDelegate</em></p>

<p>Some of you may wonder why I have decided to publish a new article in the ListView Tips &amp; Tricks series. Indeed, in the last <a href="http://www.cyrilmottier.com/2011/11/23/listview-tips-tricks-4-add-several-clickable-areas/">article</a>, I mentioned the fourth post was the latest of the series. Actually, at the time of the writing it was true but I recently came up with a new topic! As a result, I will stop saying such and such an article is the final of the series and I will never be wrong again!</p>

<p>I also would like to give you a quick recap of the topics we have already covered (please note it is not necessary - but highly encouraged - to read the previous tips in order to fully understand the article below):</p>

<ul>
<li><a href="http://www.cyrilmottier.com/2011/06/20/listview-tips-tricks-1-handle-emptiness/">ListView Tips &amp; Tricks #1: Handling emptiness</a></li>
<li><a href="http://www.cyrilmottier.com/2011/07/05/listview-tips-tricks-2-section-your-listview/">ListView Tips &amp; Tricks #2: Sectioning your ListView</a></li>
<li><a href="http://www.cyrilmottier.com/2011/08/08/listview-tips-tricks-3-create-fancy-listviews/">ListView Tips &amp; Tricks #3: Create fancy ListViews</a></li>
<li><a href="http://www.cyrilmottier.com/2011/11/23/listview-tips-tricks-4-add-several-clickable-areas/">ListView Tips &amp; Tricks #4: Add several clickable areas</a></li>
</ul>


<!-- More -->


<p>Moreover, all of those articles are based on some snippets of code that have been all gathered in a single Android application. You can download/clone the source code of this application on GitHub using the following link:</p>

<p><a href="http://github.com/cyrilmottier/ListViewTipsAndTricks">http://github.com/cyrilmottier/ListViewTipsAndTricks</a></p>

<p><em><strong>Note</strong>: This article is mainly dedicated to <code>ListView</code>s. The main reason behind this is enlarging touchable areas if often necessary in itemviews containing lots of controls (<code>Button</code>, <code>CheckBox</code>, etc.). Please remember the trick explained in this article doesn&#8217;t only apply to <code>ListView</code>s. It can be used everywhere in the system as long as you use <code>View</code>s &#8230; which, I guess, is often the case when developing an application.</em></p>

<p>In the previous article of this ListView Tips &amp; Tricks series, we have discovered several way to enlarge touchables areas. The main purpose of those techniques is to ensure the user correctly and easily access to secondary actions (star an item, select an item, etc.). Ensuring your users don&#8217;t get frustrated because of their actions are not being recognized is very important. Chances are high that an angry user will rate your application with a bad comment or worse uninstall the application.</p>

<p>A great example of a easy-to-interact-with application is the new GMail application. Personally, I love using it because you can navigate through the sections seamlessly and flawlessly. The UI is clean and responds precisely, which has not always been the case&#8230; Even if the select and star controls are pretty tiny (graphically speaking), they are easy to check/uncheck. To sum up, the general design remains clean and simple while the size of the controls does not influence the correctness of user interactions. The screenshot below shows an itemview from the new GMail application:</p>

<p><a href="http://cyrilmottier.com/media/2012/02/listview-tips-tricks-5-enlarged-touchable-areas/gmail_itemview.png"><img class="center" src="http://cyrilmottier.com/media/2012/02/listview-tips-tricks-5-enlarged-touchable-areas/gmail_itemview_small.png"></a></p>

<p>More than being a reference to me, the GMail application is also highly featured on the new Android Design website - which, by the way, I highly recommend you to read. For instance, the Android design team decided to use the GMail application to give an explanation of how to create contextual icons on Android. Go to the &#8216;Small / Contextual Icons&#8217; of the <a href="http://developer.android.com/design/style/iconography.html">Iconography</a> section to read the recommendations. The actual problem of this guideline is it only describes iconography. Knowing a touchable area has to be at least as big as a 30x30dp square and Google requires a 16x16dp icon brings us to a big question: How to reconciliate designers with ergonomists ?</p>

<p>My previous ListView Tips &amp; Tricks article gave us some advices:</p>

<ul>
<li>Adding padding to controllable <code>View</code>s</li>
<li>Adding a transparent safe-frame to all images used in controls</li>
<li>Enlarging view bounds using <code>fill_parent</code> or manually setting a dimension</li>
</ul>


<p>All these techniques are working perfectly and are pretty familiar to developers. Unfortunately they also bring you several issues as these methods don&#8217;t let you have a precise control over the touchable areas. For instance, the first technique involves modifying the general layout of your itemviews (padding has an effect on how <code>View</code>s are laid out) and may not let you entirely fill vertically the parent. The second technique makes reusing the image fairly difficult. There&#8217;s a good chance the safe-frame won&#8217;t be necessary if the image is reused somewhere else. In other words, those techniques can be pretty hazardous to use and may not be your best option.</p>

<p>Fortunately, Android gives you an amazing way to enlarge touchable areas. The principle consists on forwarding <code>MotionEvent</code>s (an object describing a touch) from a <code>View</code>&#8217;s rectangle area to another <code>View</code>. This can be done natively creating a <code>TouchDelegate</code> and attaching it to a <code>View</code>, the touches of which needing to be forwarded to another <code>View</code> (the delegate <code>View</code>). This class gives you a finer control over how <code>MotionEvent</code>s are consumed. You can obviously have a look at the <a href="http://developer.android.com/reference/android/view/TouchDelegate.html"><code>TouchDelegate</code></a> documentation on the Android developer website. As usual, I will follow the &#8220;show me the code&#8221; path instead of procrastinating. We will simply develop a tiny application emulating GMail behavior. It will display a list of cheeses that can be independantly (un)selected and/or (un)starred. The screenshot below gives you an overview of the result we are targeting. The red rectangles define touchable areas that will (un)select the itemview. Blue rectangles describes the area allowing the user to (un)star the itemview:</p>

<p><a href="http://cyrilmottier.com/media/2012/02/listview-tips-tricks-5-enlarged-touchable-areas/target_itemview.png"><img class="center" src="http://cyrilmottier.com/media/2012/02/listview-tips-tricks-5-enlarged-touchable-areas/target_itemview_small.png"></a></p>

<p>On the screenshot below you can easily notice (especially on the left of the itemview) the touchable area overlaps the actual <code>TextView</code> bounds.</p>

<h3>A custom <code>View</code> as itemview</h3>

<p>Most of the time, UIs are based on XML layouts. This type of declaration if usually enough to create a UI. However, sometimes you may require a finer control over the <code>View</code> hierarchy: be notified the size of a <code>View</code> has changed, be notified a layout pass has been performed (starting from API 11, this is now possible from outside of a <code>View</code> using the <a href="http://developer.android.com/reference/android/view/View.OnLayoutChangeListener.html"><code>OnLayoutChangeListener</code></a>), etc. This is the main reason why I have decided to develop my own custom <code>View</code> for the purpose of this sample. The XML <code>View</code> hierarchy of our custom itemview is given below:</p>

<figure class='code'> <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
</pre></td><td class='code'><pre><code class='xml'><span class='line'><span class="cp">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;</span>
</span><span class='line'><span class="nt">&lt;merge</span> <span class="na">xmlns:android=</span><span class="s">&quot;http://schemas.android.com/apk/res/android&quot;</span> <span class="nt">&gt;</span>
</span><span class='line'>
</span><span class='line'>    <span class="nt">&lt;ImageButton</span>
</span><span class='line'>        <span class="na">android:id=</span><span class="s">&quot;@+id/btn_select&quot;</span>
</span><span class='line'>        <span class="na">android:layout_width=</span><span class="s">&quot;wrap_content&quot;</span>
</span><span class='line'>        <span class="na">android:layout_height=</span><span class="s">&quot;wrap_content&quot;</span>
</span><span class='line'>        <span class="na">android:layout_gravity=</span><span class="s">&quot;center_vertical&quot;</span>
</span><span class='line'>        <span class="na">android:background=</span><span class="s">&quot;@null&quot;</span>
</span><span class='line'>        <span class="na">android:src=</span><span class="s">&quot;@drawable/btn_check_off_normal&quot;</span> <span class="nt">/&gt;</span>
</span><span class='line'>
</span><span class='line'>    <span class="nt">&lt;TextView</span>
</span><span class='line'>        <span class="na">android:id=</span><span class="s">&quot;@+id/content&quot;</span>
</span><span class='line'>        <span class="na">android:layout_width=</span><span class="s">&quot;0dp&quot;</span>
</span><span class='line'>        <span class="na">android:layout_height=</span><span class="s">&quot;wrap_content&quot;</span>
</span><span class='line'>        <span class="na">android:layout_gravity=</span><span class="s">&quot;center_vertical&quot;</span>
</span><span class='line'>        <span class="na">android:layout_weight=</span><span class="s">&quot;1&quot;</span>
</span><span class='line'>        <span class="na">android:ellipsize=</span><span class="s">&quot;end&quot;</span>
</span><span class='line'>        <span class="na">android:paddingLeft=</span><span class="s">&quot;6dp&quot;</span>
</span><span class='line'>        <span class="na">android:paddingRight=</span><span class="s">&quot;6dp&quot;</span>
</span><span class='line'>        <span class="na">android:singleLine=</span><span class="s">&quot;true&quot;</span>
</span><span class='line'>        <span class="na">android:textAppearance=</span><span class="s">&quot;?android:attr/textAppearanceLarge&quot;</span> <span class="nt">/&gt;</span>
</span><span class='line'>
</span><span class='line'>    <span class="nt">&lt;ImageButton</span>
</span><span class='line'>        <span class="na">android:id=</span><span class="s">&quot;@+id/btn_star&quot;</span>
</span><span class='line'>        <span class="na">android:layout_width=</span><span class="s">&quot;wrap_content&quot;</span>
</span><span class='line'>        <span class="na">android:layout_height=</span><span class="s">&quot;wrap_content&quot;</span>
</span><span class='line'>        <span class="na">android:layout_gravity=</span><span class="s">&quot;center_vertical&quot;</span>
</span><span class='line'>        <span class="na">android:background=</span><span class="s">&quot;@null&quot;</span>
</span><span class='line'>        <span class="na">android:src=</span><span class="s">&quot;@drawable/btn_star_off_normal&quot;</span> <span class="nt">/&gt;</span>
</span><span class='line'>
</span><span class='line'><span class="nt">&lt;/merge&gt;</span>
</span></code></pre></td></tr></table></div></figure>


<p>The Java counterpart of our itemview is where all the magic happens as this is where <code>TouchDelegate</code>s are set. The trick consists on listening to <code>onLayout(boolean, int, int, int, int)</code> calls and re-apply the correct <code>TouchDelegate</code> if the size of the itemview has changed (we suppose child <code>View</code>s cannot change their position/size if the parent keeps the same size)</p>

<figure class='code'><figcaption><span>LargeTouchableAreasView.java  </span></figcaption>
 <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
<span class='line-number'>56</span>
<span class='line-number'>57</span>
<span class='line-number'>58</span>
<span class='line-number'>59</span>
<span class='line-number'>60</span>
<span class='line-number'>61</span>
<span class='line-number'>62</span>
<span class='line-number'>63</span>
<span class='line-number'>64</span>
<span class='line-number'>65</span>
<span class='line-number'>66</span>
<span class='line-number'>67</span>
<span class='line-number'>68</span>
<span class='line-number'>69</span>
<span class='line-number'>70</span>
<span class='line-number'>71</span>
<span class='line-number'>72</span>
<span class='line-number'>73</span>
<span class='line-number'>74</span>
<span class='line-number'>75</span>
<span class='line-number'>76</span>
<span class='line-number'>77</span>
<span class='line-number'>78</span>
<span class='line-number'>79</span>
<span class='line-number'>80</span>
<span class='line-number'>81</span>
<span class='line-number'>82</span>
<span class='line-number'>83</span>
<span class='line-number'>84</span>
<span class='line-number'>85</span>
<span class='line-number'>86</span>
<span class='line-number'>87</span>
<span class='line-number'>88</span>
<span class='line-number'>89</span>
<span class='line-number'>90</span>
<span class='line-number'>91</span>
<span class='line-number'>92</span>
<span class='line-number'>93</span>
<span class='line-number'>94</span>
<span class='line-number'>95</span>
<span class='line-number'>96</span>
<span class='line-number'>97</span>
<span class='line-number'>98</span>
<span class='line-number'>99</span>
<span class='line-number'>100</span>
<span class='line-number'>101</span>
<span class='line-number'>102</span>
<span class='line-number'>103</span>
<span class='line-number'>104</span>
<span class='line-number'>105</span>
<span class='line-number'>106</span>
<span class='line-number'>107</span>
<span class='line-number'>108</span>
<span class='line-number'>109</span>
<span class='line-number'>110</span>
<span class='line-number'>111</span>
<span class='line-number'>112</span>
<span class='line-number'>113</span>
<span class='line-number'>114</span>
<span class='line-number'>115</span>
<span class='line-number'>116</span>
<span class='line-number'>117</span>
<span class='line-number'>118</span>
<span class='line-number'>119</span>
<span class='line-number'>120</span>
<span class='line-number'>121</span>
<span class='line-number'>122</span>
<span class='line-number'>123</span>
<span class='line-number'>124</span>
<span class='line-number'>125</span>
<span class='line-number'>126</span>
<span class='line-number'>127</span>
<span class='line-number'>128</span>
<span class='line-number'>129</span>
<span class='line-number'>130</span>
<span class='line-number'>131</span>
<span class='line-number'>132</span>
<span class='line-number'>133</span>
<span class='line-number'>134</span>
<span class='line-number'>135</span>
<span class='line-number'>136</span>
<span class='line-number'>137</span>
<span class='line-number'>138</span>
<span class='line-number'>139</span>
<span class='line-number'>140</span>
<span class='line-number'>141</span>
<span class='line-number'>142</span>
<span class='line-number'>143</span>
<span class='line-number'>144</span>
<span class='line-number'>145</span>
<span class='line-number'>146</span>
<span class='line-number'>147</span>
<span class='line-number'>148</span>
<span class='line-number'>149</span>
<span class='line-number'>150</span>
<span class='line-number'>151</span>
<span class='line-number'>152</span>
<span class='line-number'>153</span>
<span class='line-number'>154</span>
<span class='line-number'>155</span>
<span class='line-number'>156</span>
<span class='line-number'>157</span>
<span class='line-number'>158</span>
<span class='line-number'>159</span>
<span class='line-number'>160</span>
<span class='line-number'>161</span>
<span class='line-number'>162</span>
<span class='line-number'>163</span>
<span class='line-number'>164</span>
<span class='line-number'>165</span>
<span class='line-number'>166</span>
<span class='line-number'>167</span>
<span class='line-number'>168</span>
<span class='line-number'>169</span>
<span class='line-number'>170</span>
<span class='line-number'>171</span>
<span class='line-number'>172</span>
<span class='line-number'>173</span>
<span class='line-number'>174</span>
<span class='line-number'>175</span>
<span class='line-number'>176</span>
<span class='line-number'>177</span>
<span class='line-number'>178</span>
<span class='line-number'>179</span>
<span class='line-number'>180</span>
<span class='line-number'>181</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="kn">package</span> <span class="n">com</span><span class="o">.</span><span class="na">cyrilmottier</span><span class="o">.</span><span class="na">android</span><span class="o">.</span><span class="na">listviewtipsandtricks</span><span class="o">.</span><span class="na">widget</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'><span class="kn">import</span> <span class="nn">java.util.ArrayList</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.content.Context</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.graphics.Canvas</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.graphics.Color</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.graphics.Paint</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.graphics.Paint.Style</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.graphics.Rect</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.util.AttributeSet</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.view.LayoutInflater</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.view.TouchDelegate</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.view.View</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.view.ViewGroup</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.widget.ImageButton</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.widget.LinearLayout</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.widget.TextView</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'><span class="kn">import</span> <span class="nn">com.cyrilmottier.android.listviewtipsandtricks.R</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">com.cyrilmottier.android.listviewtipsandtricks.view.TouchDelegateGroup</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'><span class="kd">public</span> <span class="kd">class</span> <span class="nc">LargeTouchableAreasView</span> <span class="kd">extends</span> <span class="n">LinearLayout</span> <span class="o">{</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="kt">int</span> <span class="n">TOUCH_ADDITION</span> <span class="o">=</span> <span class="mi">20</span><span class="o">;</span>
</span><span class='line'>    <span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="kt">int</span> <span class="n">COLOR_SELECT_AREA</span> <span class="o">=</span> <span class="n">Color</span><span class="o">.</span><span class="na">argb</span><span class="o">(</span><span class="mi">50</span><span class="o">,</span> <span class="mi">255</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span> <span class="mi">0</span><span class="o">);</span>
</span><span class='line'>    <span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="kt">int</span> <span class="n">COLOR_STAR_AREA</span> <span class="o">=</span> <span class="n">Color</span><span class="o">.</span><span class="na">argb</span><span class="o">(</span><span class="mi">50</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span> <span class="mi">255</span><span class="o">);</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">public</span> <span class="kd">interface</span> <span class="nc">OnLargeTouchableAreasListener</span> <span class="o">{</span>
</span><span class='line'>        <span class="kt">void</span> <span class="nf">onSelected</span><span class="o">(</span><span class="n">LargeTouchableAreasView</span> <span class="n">view</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">selected</span><span class="o">);</span>
</span><span class='line'>
</span><span class='line'>        <span class="kt">void</span> <span class="nf">onStarred</span><span class="o">(</span><span class="n">LargeTouchableAreasView</span> <span class="n">view</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">starred</span><span class="o">);</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">private</span> <span class="kd">static</span> <span class="kd">class</span> <span class="nc">TouchDelegateRecord</span> <span class="o">{</span>
</span><span class='line'>        <span class="kd">public</span> <span class="n">Rect</span> <span class="n">rect</span><span class="o">;</span>
</span><span class='line'>        <span class="kd">public</span> <span class="kt">int</span> <span class="n">color</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'>        <span class="kd">public</span> <span class="nf">TouchDelegateRecord</span><span class="o">(</span><span class="n">Rect</span> <span class="n">_rect</span><span class="o">,</span> <span class="kt">int</span> <span class="n">_color</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>            <span class="n">rect</span> <span class="o">=</span> <span class="n">_rect</span><span class="o">;</span>
</span><span class='line'>            <span class="n">color</span> <span class="o">=</span> <span class="n">_color</span><span class="o">;</span>
</span><span class='line'>        <span class="o">}</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">private</span> <span class="kd">final</span> <span class="n">ArrayList</span><span class="o">&lt;</span><span class="n">touchdelegaterecord</span><span class="o">&gt;</span> <span class="n">mTouchDelegateRecords</span> <span class="o">=</span> <span class="k">new</span> <span class="n">ArrayList</span><span class="o">&lt;</span><span class="n">largetouchableareasview</span><span class="o">.</span><span class="na">touchdelegaterecord</span><span class="o">&gt;();</span>
</span><span class='line'>    <span class="kd">private</span> <span class="kd">final</span> <span class="n">Paint</span> <span class="n">mPaint</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Paint</span><span class="o">();</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">private</span> <span class="n">ImageButton</span> <span class="n">mSelectButton</span><span class="o">;</span>
</span><span class='line'>    <span class="kd">private</span> <span class="n">ImageButton</span> <span class="n">mStarButton</span><span class="o">;</span>
</span><span class='line'>    <span class="kd">private</span> <span class="n">TextView</span> <span class="n">mTextView</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">private</span> <span class="n">TouchDelegateGroup</span> <span class="n">mTouchDelegateGroup</span><span class="o">;</span>
</span><span class='line'>    <span class="kd">private</span> <span class="n">OnLargeTouchableAreasListener</span> <span class="n">mOnLargeTouchableAreasListener</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">private</span> <span class="kt">int</span> <span class="n">mTouchAddition</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">private</span> <span class="kt">boolean</span> <span class="n">mIsStarred</span><span class="o">;</span>
</span><span class='line'>    <span class="kd">private</span> <span class="kt">boolean</span> <span class="n">mIsSelected</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">private</span> <span class="kt">int</span> <span class="n">mPreviousWidth</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span><span class="o">;</span>
</span><span class='line'>    <span class="kd">private</span> <span class="kt">int</span> <span class="n">mPreviousHeight</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">public</span> <span class="nf">LargeTouchableAreasView</span><span class="o">(</span><span class="n">Context</span> <span class="n">context</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="kd">super</span><span class="o">(</span><span class="n">context</span><span class="o">);</span>
</span><span class='line'>        <span class="n">init</span><span class="o">(</span><span class="n">context</span><span class="o">);</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">public</span> <span class="nf">LargeTouchableAreasView</span><span class="o">(</span><span class="n">Context</span> <span class="n">context</span><span class="o">,</span> <span class="n">AttributeSet</span> <span class="n">attrs</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="kd">super</span><span class="o">(</span><span class="n">context</span><span class="o">,</span> <span class="n">attrs</span><span class="o">);</span>
</span><span class='line'>        <span class="n">init</span><span class="o">(</span><span class="n">context</span><span class="o">);</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">private</span> <span class="kt">void</span> <span class="nf">init</span><span class="o">(</span><span class="n">Context</span> <span class="n">context</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>
</span><span class='line'>        <span class="n">setOrientation</span><span class="o">(</span><span class="n">LinearLayout</span><span class="o">.</span><span class="na">HORIZONTAL</span><span class="o">);</span>
</span><span class='line'>        <span class="n">setDescendantFocusability</span><span class="o">(</span><span class="n">ViewGroup</span><span class="o">.</span><span class="na">FOCUS_BLOCK_DESCENDANTS</span><span class="o">);</span>
</span><span class='line'>
</span><span class='line'>        <span class="n">mTouchDelegateGroup</span> <span class="o">=</span> <span class="k">new</span> <span class="n">TouchDelegateGroup</span><span class="o">(</span><span class="k">this</span><span class="o">);</span>
</span><span class='line'>        <span class="n">mPaint</span><span class="o">.</span><span class="na">setStyle</span><span class="o">(</span><span class="n">Style</span><span class="o">.</span><span class="na">FILL</span><span class="o">);</span>
</span><span class='line'>
</span><span class='line'>        <span class="kd">final</span> <span class="kt">float</span> <span class="n">density</span> <span class="o">=</span> <span class="n">context</span><span class="o">.</span><span class="na">getResources</span><span class="o">().</span><span class="na">getDisplayMetrics</span><span class="o">().</span><span class="na">density</span><span class="o">;</span>
</span><span class='line'>        <span class="n">mTouchAddition</span> <span class="o">=</span> <span class="o">(</span><span class="kt">int</span><span class="o">)</span> <span class="o">(</span><span class="n">density</span> <span class="o">*</span> <span class="n">TOUCH_ADDITION</span> <span class="o">+</span> <span class="mf">0.5f</span><span class="o">);</span>
</span><span class='line'>
</span><span class='line'>        <span class="n">LayoutInflater</span><span class="o">.</span><span class="na">from</span><span class="o">(</span><span class="n">context</span><span class="o">).</span><span class="na">inflate</span><span class="o">(</span><span class="n">R</span><span class="o">.</span><span class="na">layout</span><span class="o">.</span><span class="na">large_touchable_areas_view</span><span class="o">,</span> <span class="k">this</span><span class="o">);</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="nd">@Override</span>
</span><span class='line'>    <span class="kd">protected</span> <span class="kt">void</span> <span class="nf">onFinishInflate</span><span class="o">()</span> <span class="o">{</span>
</span><span class='line'>        <span class="kd">super</span><span class="o">.</span><span class="na">onFinishInflate</span><span class="o">();</span>
</span><span class='line'>
</span><span class='line'>        <span class="n">mSelectButton</span> <span class="o">=</span> <span class="o">(</span><span class="n">ImageButton</span><span class="o">)</span> <span class="n">findViewById</span><span class="o">(</span><span class="n">R</span><span class="o">.</span><span class="na">id</span><span class="o">.</span><span class="na">btn_select</span><span class="o">);</span>
</span><span class='line'>        <span class="n">mSelectButton</span><span class="o">.</span><span class="na">setOnClickListener</span><span class="o">(</span><span class="k">new</span> <span class="n">OnClickListener</span><span class="o">()</span> <span class="o">{</span>
</span><span class='line'>            <span class="nd">@Override</span>
</span><span class='line'>            <span class="kd">public</span> <span class="kt">void</span> <span class="nf">onClick</span><span class="o">(</span><span class="n">View</span> <span class="n">v</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>                <span class="n">setItemViewSelected</span><span class="o">(!</span><span class="n">mIsSelected</span><span class="o">);</span>
</span><span class='line'>                <span class="k">if</span> <span class="o">(</span><span class="n">mOnLargeTouchableAreasListener</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>                    <span class="n">mOnLargeTouchableAreasListener</span><span class="o">.</span><span class="na">onSelected</span><span class="o">(</span><span class="n">LargeTouchableAreasView</span><span class="o">.</span><span class="na">this</span><span class="o">,</span> <span class="n">mIsSelected</span><span class="o">);</span>
</span><span class='line'>                <span class="o">}</span>
</span><span class='line'>            <span class="o">}</span>
</span><span class='line'>        <span class="o">});</span>
</span><span class='line'>
</span><span class='line'>        <span class="n">mStarButton</span> <span class="o">=</span> <span class="o">(</span><span class="n">ImageButton</span><span class="o">)</span> <span class="n">findViewById</span><span class="o">(</span><span class="n">R</span><span class="o">.</span><span class="na">id</span><span class="o">.</span><span class="na">btn_star</span><span class="o">);</span>
</span><span class='line'>        <span class="n">mStarButton</span><span class="o">.</span><span class="na">setOnClickListener</span><span class="o">(</span><span class="k">new</span> <span class="n">OnClickListener</span><span class="o">()</span> <span class="o">{</span>
</span><span class='line'>            <span class="nd">@Override</span>
</span><span class='line'>            <span class="kd">public</span> <span class="kt">void</span> <span class="nf">onClick</span><span class="o">(</span><span class="n">View</span> <span class="n">v</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>                <span class="n">setItemViewStarred</span><span class="o">(!</span><span class="n">mIsStarred</span><span class="o">);</span>
</span><span class='line'>                <span class="k">if</span> <span class="o">(</span><span class="n">mOnLargeTouchableAreasListener</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>                    <span class="n">mOnLargeTouchableAreasListener</span><span class="o">.</span><span class="na">onStarred</span><span class="o">(</span><span class="n">LargeTouchableAreasView</span><span class="o">.</span><span class="na">this</span><span class="o">,</span> <span class="n">mIsStarred</span><span class="o">);</span>
</span><span class='line'>                <span class="o">}</span>
</span><span class='line'>            <span class="o">}</span>
</span><span class='line'>        <span class="o">});</span>
</span><span class='line'>
</span><span class='line'>        <span class="n">mTextView</span> <span class="o">=</span> <span class="o">(</span><span class="n">TextView</span><span class="o">)</span> <span class="n">findViewById</span><span class="o">(</span><span class="n">R</span><span class="o">.</span><span class="na">id</span><span class="o">.</span><span class="na">content</span><span class="o">);</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="nd">@Override</span>
</span><span class='line'>    <span class="kd">protected</span> <span class="kt">void</span> <span class="nf">onLayout</span><span class="o">(</span><span class="kt">boolean</span> <span class="n">changed</span><span class="o">,</span> <span class="kt">int</span> <span class="n">l</span><span class="o">,</span> <span class="kt">int</span> <span class="n">t</span><span class="o">,</span> <span class="kt">int</span> <span class="n">r</span><span class="o">,</span> <span class="kt">int</span> <span class="n">b</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="kd">super</span><span class="o">.</span><span class="na">onLayout</span><span class="o">(</span><span class="n">changed</span><span class="o">,</span> <span class="n">l</span><span class="o">,</span> <span class="n">t</span><span class="o">,</span> <span class="n">r</span><span class="o">,</span> <span class="n">b</span><span class="o">);</span>
</span><span class='line'>
</span><span class='line'>        <span class="kd">final</span> <span class="kt">int</span> <span class="n">width</span> <span class="o">=</span> <span class="n">r</span> <span class="o">-</span> <span class="n">l</span><span class="o">;</span>
</span><span class='line'>        <span class="kd">final</span> <span class="kt">int</span> <span class="n">height</span> <span class="o">=</span> <span class="n">b</span> <span class="o">-</span> <span class="n">t</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'>        <span class="k">if</span> <span class="o">(</span><span class="n">width</span> <span class="o">!=</span> <span class="n">mPreviousWidth</span> <span class="o">||</span> <span class="n">height</span> <span class="o">!=</span> <span class="n">mPreviousHeight</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>
</span><span class='line'>            <span class="n">mPreviousWidth</span> <span class="o">=</span> <span class="n">width</span><span class="o">;</span>
</span><span class='line'>            <span class="n">mPreviousHeight</span> <span class="o">=</span> <span class="n">height</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'>            <span class="n">mTouchDelegateGroup</span><span class="o">.</span><span class="na">clearTouchDelegates</span><span class="o">();</span>
</span><span class='line'>
</span><span class='line'>            <span class="c1">//@formatter:off</span>
</span><span class='line'>            <span class="n">addTouchDelegate</span><span class="o">(</span>
</span><span class='line'>                    <span class="k">new</span> <span class="nf">Rect</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span> <span class="n">mSelectButton</span><span class="o">.</span><span class="na">getWidth</span><span class="o">()</span> <span class="o">+</span> <span class="n">mTouchAddition</span><span class="o">,</span> <span class="n">height</span><span class="o">),</span>
</span><span class='line'>                    <span class="n">COLOR_SELECT_AREA</span><span class="o">,</span>
</span><span class='line'>                    <span class="n">mSelectButton</span><span class="o">);</span>
</span><span class='line'>
</span><span class='line'>            <span class="n">addTouchDelegate</span><span class="o">(</span>
</span><span class='line'>                    <span class="k">new</span> <span class="nf">Rect</span><span class="o">(</span><span class="n">width</span> <span class="o">-</span> <span class="n">mStarButton</span><span class="o">.</span><span class="na">getWidth</span><span class="o">()</span> <span class="o">-</span> <span class="n">mTouchAddition</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span> <span class="n">width</span><span class="o">,</span> <span class="n">height</span><span class="o">),</span>
</span><span class='line'>                    <span class="n">COLOR_STAR_AREA</span><span class="o">,</span>
</span><span class='line'>                    <span class="n">mStarButton</span><span class="o">);</span>
</span><span class='line'>            <span class="c1">//@formatter:on</span>
</span><span class='line'>
</span><span class='line'>            <span class="n">setTouchDelegate</span><span class="o">(</span><span class="n">mTouchDelegateGroup</span><span class="o">);</span>
</span><span class='line'>        <span class="o">}</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">private</span> <span class="kt">void</span> <span class="nf">addTouchDelegate</span><span class="o">(</span><span class="n">Rect</span> <span class="n">rect</span><span class="o">,</span> <span class="kt">int</span> <span class="n">color</span><span class="o">,</span> <span class="n">View</span> <span class="n">delegateView</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="n">mTouchDelegateGroup</span><span class="o">.</span><span class="na">addTouchDelegate</span><span class="o">(</span><span class="k">new</span> <span class="n">TouchDelegate</span><span class="o">(</span><span class="n">rect</span><span class="o">,</span> <span class="n">delegateView</span><span class="o">));</span>
</span><span class='line'>        <span class="n">mTouchDelegateRecords</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="k">new</span> <span class="n">TouchDelegateRecord</span><span class="o">(</span><span class="n">rect</span><span class="o">,</span> <span class="n">color</span><span class="o">));</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="nd">@Override</span>
</span><span class='line'>    <span class="kd">protected</span> <span class="kt">void</span> <span class="nf">dispatchDraw</span><span class="o">(</span><span class="n">Canvas</span> <span class="n">canvas</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="k">for</span> <span class="o">(</span><span class="n">TouchDelegateRecord</span> <span class="n">record</span> <span class="o">:</span> <span class="n">mTouchDelegateRecords</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>            <span class="n">mPaint</span><span class="o">.</span><span class="na">setColor</span><span class="o">(</span><span class="n">record</span><span class="o">.</span><span class="na">color</span><span class="o">);</span>
</span><span class='line'>            <span class="n">canvas</span><span class="o">.</span><span class="na">drawRect</span><span class="o">(</span><span class="n">record</span><span class="o">.</span><span class="na">rect</span><span class="o">,</span> <span class="n">mPaint</span><span class="o">);</span>
</span><span class='line'>        <span class="o">}</span>
</span><span class='line'>        <span class="kd">super</span><span class="o">.</span><span class="na">dispatchDraw</span><span class="o">(</span><span class="n">canvas</span><span class="o">);</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">setOnLargeTouchableAreasListener</span><span class="o">(</span><span class="n">OnLargeTouchableAreasListener</span> <span class="n">listener</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="n">mOnLargeTouchableAreasListener</span> <span class="o">=</span> <span class="n">listener</span><span class="o">;</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">public</span> <span class="n">TextView</span> <span class="nf">getTextView</span><span class="o">()</span> <span class="o">{</span>
</span><span class='line'>        <span class="k">return</span> <span class="n">mTextView</span><span class="o">;</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">setItemViewSelected</span><span class="o">(</span><span class="kt">boolean</span> <span class="n">selected</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="k">if</span> <span class="o">(</span><span class="n">mIsSelected</span> <span class="o">!=</span> <span class="n">selected</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>            <span class="n">mIsSelected</span> <span class="o">=</span> <span class="n">selected</span><span class="o">;</span>
</span><span class='line'>            <span class="n">mSelectButton</span><span class="o">.</span><span class="na">setImageResource</span><span class="o">(</span><span class="n">mIsSelected</span> <span class="o">?</span> <span class="n">R</span><span class="o">.</span><span class="na">drawable</span><span class="o">.</span><span class="na">btn_check_on_normal</span> <span class="o">:</span> <span class="n">R</span><span class="o">.</span><span class="na">drawable</span><span class="o">.</span><span class="na">btn_check_off_normal</span><span class="o">);</span>
</span><span class='line'>        <span class="o">}</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">setItemViewStarred</span><span class="o">(</span><span class="kt">boolean</span> <span class="n">starred</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="k">if</span> <span class="o">(</span><span class="n">mIsStarred</span> <span class="o">!=</span> <span class="n">starred</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>            <span class="n">mIsStarred</span> <span class="o">=</span> <span class="n">starred</span><span class="o">;</span>
</span><span class='line'>            <span class="n">mStarButton</span><span class="o">.</span><span class="na">setImageResource</span><span class="o">(</span><span class="n">mIsStarred</span> <span class="o">?</span> <span class="n">R</span><span class="o">.</span><span class="na">drawable</span><span class="o">.</span><span class="na">btn_star_on_normal</span> <span class="o">:</span> <span class="n">R</span><span class="o">.</span><span class="na">drawable</span><span class="o">.</span><span class="na">btn_star_off_normal</span><span class="o">);</span>
</span><span class='line'>        <span class="o">}</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'><span class="o">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>As explained in the fourth article of this series, I consider the <code>CheckBox</code> widget as badly implemented. To overcome all problems, I simply decided not to use it! The entire code emulates <code>CheckBox</code>es using <code>ImageButton</code>s. Please note I made nothing to manage extra states (pressed, focused, etc.) because it was not the main purpose of this article. In production code, you should always ensure the appearance of a control changes depending on its current state.</p>

<h3>One <code>TouchDelegate</code>, two <code>TouchDelegate</code>s, three&#8230;</h3>

<p>A <code>View</code> manages a single <code>TouchDelegate</code>. It other words, it means, by default, you can&#8217;t have several &#8216;delegation areas&#8217; for a single <code>View</code>. To overcome this problem, I have created a very basic class called <code>TouchDelegateGroup</code> that is basically a <code>TouchDelegate</code> containing several <code>TouchDelegate</code>s and forward <code>MotionEvent</code> to the correct one. I have to confess the implementation is pretty hacky (at least the constructor) but this is the only way to overcome the fact <code>TouchDelegate</code> is not an interface, has no no-arg constructor and does not manage null arguments. The code of the <code>TouchDelegateGroup</code> is given below:</p>

<figure class='code'><figcaption><span>TouchDelegateGroup.java  </span></figcaption>
 <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
<span class='line-number'>56</span>
<span class='line-number'>57</span>
<span class='line-number'>58</span>
<span class='line-number'>59</span>
<span class='line-number'>60</span>
<span class='line-number'>61</span>
<span class='line-number'>62</span>
<span class='line-number'>63</span>
<span class='line-number'>64</span>
<span class='line-number'>65</span>
<span class='line-number'>66</span>
<span class='line-number'>67</span>
<span class='line-number'>68</span>
<span class='line-number'>69</span>
<span class='line-number'>70</span>
<span class='line-number'>71</span>
<span class='line-number'>72</span>
<span class='line-number'>73</span>
<span class='line-number'>74</span>
<span class='line-number'>75</span>
<span class='line-number'>76</span>
<span class='line-number'>77</span>
<span class='line-number'>78</span>
<span class='line-number'>79</span>
<span class='line-number'>80</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="kn">package</span> <span class="n">com</span><span class="o">.</span><span class="na">cyrilmottier</span><span class="o">.</span><span class="na">android</span><span class="o">.</span><span class="na">listviewtipsandtricks</span><span class="o">.</span><span class="na">view</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'><span class="kn">import</span> <span class="nn">java.util.ArrayList</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.graphics.Rect</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.view.MotionEvent</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.view.TouchDelegate</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.view.View</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'><span class="kd">public</span> <span class="kd">class</span> <span class="nc">TouchDelegateGroup</span> <span class="kd">extends</span> <span class="n">TouchDelegate</span> <span class="o">{</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="n">Rect</span> <span class="n">USELESS_HACKY_RECT</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Rect</span><span class="o">();</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">private</span> <span class="n">ArrayList</span><span class="o">&lt;</span><span class="n">touchdelegate</span><span class="o">&gt;</span> <span class="n">mTouchDelegates</span><span class="o">;</span>
</span><span class='line'>    <span class="kd">private</span> <span class="n">TouchDelegate</span> <span class="n">mCurrentTouchDelegate</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">public</span> <span class="nf">TouchDelegateGroup</span><span class="o">(</span><span class="n">View</span> <span class="n">uselessHackyView</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="c1">// I know this is pretty hacky. Unfortunately there is no other way to</span>
</span><span class='line'>        <span class="c1">// create a TouchDelegate containing TouchDelegates since TouchDelegate</span>
</span><span class='line'>        <span class="c1">// is not an interface ...</span>
</span><span class='line'>        <span class="kd">super</span><span class="o">(</span><span class="n">USELESS_HACKY_RECT</span><span class="o">,</span> <span class="n">uselessHackyView</span><span class="o">);</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">addTouchDelegate</span><span class="o">(</span><span class="n">TouchDelegate</span> <span class="n">touchDelegate</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="k">if</span> <span class="o">(</span><span class="n">mTouchDelegates</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>            <span class="n">mTouchDelegates</span> <span class="o">=</span> <span class="k">new</span> <span class="n">ArrayList</span><span class="o">&lt;</span><span class="n">touchdelegate</span><span class="o">&gt;();</span>
</span><span class='line'>        <span class="o">}</span>
</span><span class='line'>        <span class="n">mTouchDelegates</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="n">touchDelegate</span><span class="o">);</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">removeTouchDelegate</span><span class="o">(</span><span class="n">TouchDelegate</span> <span class="n">touchDelegate</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="k">if</span> <span class="o">(</span><span class="n">mTouchDelegates</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>            <span class="n">mTouchDelegates</span><span class="o">.</span><span class="na">remove</span><span class="o">(</span><span class="n">touchDelegate</span><span class="o">);</span>
</span><span class='line'>            <span class="k">if</span> <span class="o">(</span><span class="n">mTouchDelegates</span><span class="o">.</span><span class="na">isEmpty</span><span class="o">())</span> <span class="o">{</span>
</span><span class='line'>                <span class="n">mTouchDelegates</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
</span><span class='line'>            <span class="o">}</span>
</span><span class='line'>        <span class="o">}</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">clearTouchDelegates</span><span class="o">()</span> <span class="o">{</span>
</span><span class='line'>        <span class="k">if</span> <span class="o">(</span><span class="n">mTouchDelegates</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>            <span class="n">mTouchDelegates</span><span class="o">.</span><span class="na">clear</span><span class="o">();</span>
</span><span class='line'>        <span class="o">}</span>
</span><span class='line'>        <span class="n">mCurrentTouchDelegate</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="nd">@Override</span>
</span><span class='line'>    <span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">onTouchEvent</span><span class="o">(</span><span class="n">MotionEvent</span> <span class="n">event</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>
</span><span class='line'>        <span class="n">TouchDelegate</span> <span class="n">delegate</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'>        <span class="k">switch</span> <span class="o">(</span><span class="n">event</span><span class="o">.</span><span class="na">getAction</span><span class="o">())</span> <span class="o">{</span>
</span><span class='line'>            <span class="k">case</span> <span class="n">MotionEvent</span><span class="o">.</span><span class="na">ACTION_DOWN</span><span class="o">:</span>
</span><span class='line'>                <span class="k">if</span> <span class="o">(</span><span class="n">mTouchDelegates</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>                    <span class="k">for</span> <span class="o">(</span><span class="n">TouchDelegate</span> <span class="n">touchDelegate</span> <span class="o">:</span> <span class="n">mTouchDelegates</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>                        <span class="k">if</span> <span class="o">(</span><span class="n">touchDelegate</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>                            <span class="k">if</span> <span class="o">(</span><span class="n">touchDelegate</span><span class="o">.</span><span class="na">onTouchEvent</span><span class="o">(</span><span class="n">event</span><span class="o">))</span> <span class="o">{</span>
</span><span class='line'>                                <span class="n">mCurrentTouchDelegate</span> <span class="o">=</span> <span class="n">touchDelegate</span><span class="o">;</span>
</span><span class='line'>                                <span class="k">return</span> <span class="kc">true</span><span class="o">;</span>
</span><span class='line'>                            <span class="o">}</span>
</span><span class='line'>                        <span class="o">}</span>
</span><span class='line'>                    <span class="o">}</span>
</span><span class='line'>                <span class="o">}</span>
</span><span class='line'>                <span class="k">break</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'>            <span class="k">case</span> <span class="n">MotionEvent</span><span class="o">.</span><span class="na">ACTION_MOVE</span><span class="o">:</span>
</span><span class='line'>                <span class="n">delegate</span> <span class="o">=</span> <span class="n">mCurrentTouchDelegate</span><span class="o">;</span>
</span><span class='line'>                <span class="k">break</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'>            <span class="k">case</span> <span class="n">MotionEvent</span><span class="o">.</span><span class="na">ACTION_CANCEL</span><span class="o">:</span>
</span><span class='line'>            <span class="k">case</span> <span class="n">MotionEvent</span><span class="o">.</span><span class="na">ACTION_UP</span><span class="o">:</span>
</span><span class='line'>                <span class="n">delegate</span> <span class="o">=</span> <span class="n">mCurrentTouchDelegate</span><span class="o">;</span>
</span><span class='line'>                <span class="n">mCurrentTouchDelegate</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
</span><span class='line'>                <span class="k">break</span><span class="o">;</span>
</span><span class='line'>        <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>        <span class="k">return</span> <span class="n">delegate</span> <span class="o">==</span> <span class="kc">null</span> <span class="o">?</span> <span class="kc">false</span> <span class="o">:</span> <span class="n">delegate</span><span class="o">.</span><span class="na">onTouchEvent</span><span class="o">(</span><span class="n">event</span><span class="o">);</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'><span class="o">}</span>
</span></code></pre></td></tr></table></div></figure>


<h3>The most simple ListActivity ever</h3>

<p>The code of the <code>ListActivity</code> is given below. As you may have noticed, it is really similar to the code we have written in the fourth article of this serie. Normally there is nothing new for you in here:</p>

<figure class='code'><figcaption><span>LargeTouchableAreasListActivity.java  </span></figcaption>
 <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
<span class='line-number'>56</span>
<span class='line-number'>57</span>
<span class='line-number'>58</span>
<span class='line-number'>59</span>
<span class='line-number'>60</span>
<span class='line-number'>61</span>
<span class='line-number'>62</span>
<span class='line-number'>63</span>
<span class='line-number'>64</span>
<span class='line-number'>65</span>
<span class='line-number'>66</span>
<span class='line-number'>67</span>
<span class='line-number'>68</span>
<span class='line-number'>69</span>
<span class='line-number'>70</span>
<span class='line-number'>71</span>
<span class='line-number'>72</span>
<span class='line-number'>73</span>
<span class='line-number'>74</span>
<span class='line-number'>75</span>
<span class='line-number'>76</span>
<span class='line-number'>77</span>
<span class='line-number'>78</span>
<span class='line-number'>79</span>
<span class='line-number'>80</span>
<span class='line-number'>81</span>
<span class='line-number'>82</span>
<span class='line-number'>83</span>
<span class='line-number'>84</span>
<span class='line-number'>85</span>
<span class='line-number'>86</span>
<span class='line-number'>87</span>
<span class='line-number'>88</span>
<span class='line-number'>89</span>
<span class='line-number'>90</span>
<span class='line-number'>91</span>
<span class='line-number'>92</span>
<span class='line-number'>93</span>
<span class='line-number'>94</span>
<span class='line-number'>95</span>
<span class='line-number'>96</span>
<span class='line-number'>97</span>
<span class='line-number'>98</span>
<span class='line-number'>99</span>
<span class='line-number'>100</span>
<span class='line-number'>101</span>
<span class='line-number'>102</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'>
</span><span class='line'><span class="kn">package</span> <span class="n">com</span><span class="o">.</span><span class="na">cyrilmottier</span><span class="o">.</span><span class="na">android</span><span class="o">.</span><span class="na">listviewtipsandtricks</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'><span class="kn">import</span> <span class="nn">static</span> <span class="n">com</span><span class="o">.</span><span class="na">cyrilmottier</span><span class="o">.</span><span class="na">android</span><span class="o">.</span><span class="na">listviewtipsandtricks</span><span class="o">.</span><span class="na">data</span><span class="o">.</span><span class="na">Cheeses</span><span class="o">.</span><span class="na">CHEESES</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.app.ListActivity</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.os.Bundle</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.view.View</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.view.ViewGroup</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.widget.BaseAdapter</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">android.widget.ListView</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'><span class="kn">import</span> <span class="nn">com.cyrilmottier.android.listviewtipsandtricks.widget.LargeTouchableAreasView</span><span class="o">;</span>
</span><span class='line'><span class="kn">import</span> <span class="nn">com.cyrilmottier.android.listviewtipsandtricks.widget.LargeTouchableAreasView.OnLargeTouchableAreasListener</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'><span class="kd">public</span> <span class="kd">class</span> <span class="nc">LargeTouchableAreasListActivity</span> <span class="kd">extends</span> <span class="n">ListActivity</span> <span class="o">{</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="n">String</span> <span class="n">STAR_STATES</span> <span class="o">=</span> <span class="s">&quot;listviewtipsandtricks:star_states&quot;</span><span class="o">;</span>
</span><span class='line'>    <span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="n">String</span> <span class="n">SELECTION_STATES</span> <span class="o">=</span> <span class="s">&quot;listviewtipsandtricks:selection_states&quot;</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">private</span> <span class="kt">boolean</span><span class="o">[]</span> <span class="n">mStarStates</span><span class="o">;</span>
</span><span class='line'>    <span class="kd">private</span> <span class="kt">boolean</span><span class="o">[]</span> <span class="n">mSelectionStates</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'>    <span class="nd">@Override</span>
</span><span class='line'>    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">onCreate</span><span class="o">(</span><span class="n">Bundle</span> <span class="n">savedInstanceState</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="kd">super</span><span class="o">.</span><span class="na">onCreate</span><span class="o">(</span><span class="n">savedInstanceState</span><span class="o">);</span>
</span><span class='line'>
</span><span class='line'>        <span class="n">LargeTouchableAreasAdapter</span> <span class="n">adapter</span> <span class="o">=</span> <span class="k">new</span> <span class="n">LargeTouchableAreasAdapter</span><span class="o">();</span>
</span><span class='line'>
</span><span class='line'>        <span class="k">if</span> <span class="o">(</span><span class="n">savedInstanceState</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>            <span class="n">mStarStates</span> <span class="o">=</span> <span class="n">savedInstanceState</span><span class="o">.</span><span class="na">getBooleanArray</span><span class="o">(</span><span class="n">STAR_STATES</span><span class="o">);</span>
</span><span class='line'>            <span class="n">mSelectionStates</span> <span class="o">=</span> <span class="n">savedInstanceState</span><span class="o">.</span><span class="na">getBooleanArray</span><span class="o">(</span><span class="n">SELECTION_STATES</span><span class="o">);</span>
</span><span class='line'>        <span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
</span><span class='line'>            <span class="n">mStarStates</span> <span class="o">=</span> <span class="k">new</span> <span class="kt">boolean</span><span class="o">[</span><span class="n">adapter</span><span class="o">.</span><span class="na">getCount</span><span class="o">()];</span>
</span><span class='line'>            <span class="n">mSelectionStates</span> <span class="o">=</span> <span class="k">new</span> <span class="kt">boolean</span><span class="o">[</span><span class="n">adapter</span><span class="o">.</span><span class="na">getCount</span><span class="o">()];</span>
</span><span class='line'>        <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>        <span class="n">setListAdapter</span><span class="o">(</span><span class="n">adapter</span><span class="o">);</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="nd">@Override</span>
</span><span class='line'>    <span class="kd">protected</span> <span class="kt">void</span> <span class="nf">onSaveInstanceState</span><span class="o">(</span><span class="n">Bundle</span> <span class="n">outState</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>        <span class="kd">super</span><span class="o">.</span><span class="na">onSaveInstanceState</span><span class="o">(</span><span class="n">outState</span><span class="o">);</span>
</span><span class='line'>        <span class="n">outState</span><span class="o">.</span><span class="na">putBooleanArray</span><span class="o">(</span><span class="n">SELECTION_STATES</span><span class="o">,</span> <span class="n">mSelectionStates</span><span class="o">);</span>
</span><span class='line'>        <span class="n">outState</span><span class="o">.</span><span class="na">putBooleanArray</span><span class="o">(</span><span class="n">STAR_STATES</span><span class="o">,</span> <span class="n">mStarStates</span><span class="o">);</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">private</span> <span class="kd">class</span> <span class="nc">LargeTouchableAreasAdapter</span> <span class="kd">extends</span> <span class="n">BaseAdapter</span> <span class="o">{</span>
</span><span class='line'>
</span><span class='line'>        <span class="nd">@Override</span>
</span><span class='line'>        <span class="kd">public</span> <span class="kt">int</span> <span class="nf">getCount</span><span class="o">()</span> <span class="o">{</span>
</span><span class='line'>            <span class="k">return</span> <span class="n">CHEESES</span><span class="o">.</span><span class="na">length</span><span class="o">;</span>
</span><span class='line'>        <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>        <span class="nd">@Override</span>
</span><span class='line'>        <span class="kd">public</span> <span class="n">String</span> <span class="nf">getItem</span><span class="o">(</span><span class="kt">int</span> <span class="n">position</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>            <span class="k">return</span> <span class="n">CHEESES</span><span class="o">[</span><span class="n">position</span><span class="o">];</span>
</span><span class='line'>        <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>        <span class="nd">@Override</span>
</span><span class='line'>        <span class="kd">public</span> <span class="kt">long</span> <span class="nf">getItemId</span><span class="o">(</span><span class="kt">int</span> <span class="n">position</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>            <span class="k">return</span> <span class="n">position</span><span class="o">;</span>
</span><span class='line'>        <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>        <span class="nd">@Override</span>
</span><span class='line'>        <span class="kd">public</span> <span class="n">View</span> <span class="nf">getView</span><span class="o">(</span><span class="kt">int</span> <span class="n">position</span><span class="o">,</span> <span class="n">View</span> <span class="n">convertView</span><span class="o">,</span> <span class="n">ViewGroup</span> <span class="n">parent</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>
</span><span class='line'>            <span class="kd">final</span> <span class="n">LargeTouchableAreasView</span> <span class="n">view</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'>            <span class="k">if</span> <span class="o">(</span><span class="n">convertView</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>                <span class="n">view</span> <span class="o">=</span> <span class="o">(</span><span class="n">LargeTouchableAreasView</span><span class="o">)</span> <span class="n">getLayoutInflater</span><span class="o">().</span><span class="na">inflate</span><span class="o">(</span><span class="n">R</span><span class="o">.</span><span class="na">layout</span><span class="o">.</span><span class="na">large_touchable_areas_item</span><span class="o">,</span> <span class="n">parent</span><span class="o">,</span> <span class="kc">false</span><span class="o">);</span>
</span><span class='line'>                <span class="n">view</span><span class="o">.</span><span class="na">setOnLargeTouchableAreasListener</span><span class="o">(</span><span class="n">mOnLargeTouchableAreasListener</span><span class="o">);</span>
</span><span class='line'>            <span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
</span><span class='line'>                <span class="n">view</span> <span class="o">=</span> <span class="o">(</span><span class="n">LargeTouchableAreasView</span><span class="o">)</span> <span class="n">convertView</span><span class="o">;</span>
</span><span class='line'>            <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>            <span class="n">view</span><span class="o">.</span><span class="na">setItemViewStarred</span><span class="o">(</span><span class="n">mStarStates</span><span class="o">[</span><span class="n">position</span><span class="o">]);</span>
</span><span class='line'>            <span class="n">view</span><span class="o">.</span><span class="na">setItemViewSelected</span><span class="o">(</span><span class="n">mSelectionStates</span><span class="o">[</span><span class="n">position</span><span class="o">]);</span>
</span><span class='line'>            <span class="n">view</span><span class="o">.</span><span class="na">getTextView</span><span class="o">().</span><span class="na">setText</span><span class="o">(</span><span class="n">getItem</span><span class="o">(</span><span class="n">position</span><span class="o">));</span>
</span><span class='line'>
</span><span class='line'>            <span class="k">return</span> <span class="n">view</span><span class="o">;</span>
</span><span class='line'>        <span class="o">}</span>
</span><span class='line'>    <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>    <span class="kd">private</span> <span class="n">OnLargeTouchableAreasListener</span> <span class="n">mOnLargeTouchableAreasListener</span> <span class="o">=</span> <span class="k">new</span> <span class="n">OnLargeTouchableAreasListener</span><span class="o">()</span> <span class="o">{</span>
</span><span class='line'>
</span><span class='line'>        <span class="nd">@Override</span>
</span><span class='line'>        <span class="kd">public</span> <span class="kt">void</span> <span class="nf">onSelected</span><span class="o">(</span><span class="n">LargeTouchableAreasView</span> <span class="n">view</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">selected</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>            <span class="kd">final</span> <span class="kt">int</span> <span class="n">position</span> <span class="o">=</span> <span class="n">getListView</span><span class="o">().</span><span class="na">getPositionForView</span><span class="o">(</span><span class="n">view</span><span class="o">);</span>
</span><span class='line'>            <span class="k">if</span> <span class="o">(</span><span class="n">position</span> <span class="o">!=</span> <span class="n">ListView</span><span class="o">.</span><span class="na">INVALID_POSITION</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>                <span class="n">mSelectionStates</span><span class="o">[</span><span class="n">position</span><span class="o">]</span> <span class="o">=</span> <span class="n">selected</span><span class="o">;</span>
</span><span class='line'>            <span class="o">}</span>
</span><span class='line'>        <span class="o">}</span>
</span><span class='line'>
</span><span class='line'>        <span class="nd">@Override</span>
</span><span class='line'>        <span class="kd">public</span> <span class="kt">void</span> <span class="nf">onStarred</span><span class="o">(</span><span class="n">LargeTouchableAreasView</span> <span class="n">view</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">starred</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>            <span class="kd">final</span> <span class="kt">int</span> <span class="n">position</span> <span class="o">=</span> <span class="n">getListView</span><span class="o">().</span><span class="na">getPositionForView</span><span class="o">(</span><span class="n">view</span><span class="o">);</span>
</span><span class='line'>            <span class="k">if</span> <span class="o">(</span><span class="n">position</span> <span class="o">!=</span> <span class="n">ListView</span><span class="o">.</span><span class="na">INVALID_POSITION</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>                <span class="n">mStarStates</span><span class="o">[</span><span class="n">position</span><span class="o">]</span> <span class="o">=</span> <span class="n">starred</span><span class="o">;</span>
</span><span class='line'>            <span class="o">}</span>
</span><span class='line'>        <span class="o">}</span>
</span><span class='line'>    <span class="o">};</span>
</span><span class='line'><span class="o">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>The <code>R.layout.large_touchable_area_item</code> is detailed below:</p>

<figure class='code'><figcaption><span>large_touchable_area_item.xml  </span></figcaption>
 <div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='xml'><span class='line'><span class="cp">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;</span>
</span><span class='line'><span class="nt">&lt;com.cyrilmottier.android.listviewtipsandtricks.widget.LargeTouchableAreasView</span> <span class="na">xmlns:android=</span><span class="s">&quot;http://schemas.android.com/apk/res/android&quot;</span>
</span><span class='line'>    <span class="na">android:layout_width=</span><span class="s">&quot;fill_parent&quot;</span>
</span><span class='line'>    <span class="na">android:layout_height=</span><span class="s">&quot;wrap_content&quot;</span>
</span><span class='line'>    <span class="na">android:padding=</span><span class="s">&quot;6dp&quot;</span> <span class="nt">/&gt;</span>
</span></code></pre></td></tr></table></div></figure>


<h3>Conclusion</h3>

<p>As we have seen, <code>MotionEvent</code> delegation is fairly simple when using a <code>TouchDelegate</code>. The most difficult part is to determine when and how to set the bounds of the rectangular area that will forward <code>MotionEvent</code> to the delegate <code>View</code>. Always consider the work worth it. Having controls that the user can hardly interact with is the best way to frustrate your users. Only a few developers know about the <code>TouchDelegate</code> class and even less use it. And you? Did you know about the <code>TouchDelegate</code> class?</p>
]]></content>
  </entry>
  
</feed>
