使用 Ruby on Rails 和 Eclipse 开发 iPhone 应用程序,第 3 部分: 开发 iPhone 的高级视图

来源:developerWorks 中国 作者:Noel Rappin
  
iPhone 和 iPod touch 使 Mobile Safari 成为风靡美国的手机浏览器。虽然使用 Mobile Safari 呈现普通 Web 页面绰绰有余,但是许多 Web 开发人员都创建了针对 iPhone 的应用程序版本。本文是 “使用 Ruby on Rails 和 Eclipse 开发 iPhone 应用程序” 系列的第 3 部分,介绍当用户浏览到列表结构末尾而应用程序实际上还需要显示一些内容时,应当如何执行操作。

本系列的前两部分介绍了构造一个 Ruby on Rails 应用程序的两个重要方面,这个应用程序可以为 iPhone 和 iPod touch 中的 Mobile Safari 浏览器的用户服务特殊内容。第 1 部分 讨论了如何设置服务器以检测和为 Mobile Safari 提供替代内容。所选用的机制(并不是惟一的实现方法)涉及创建伪 MIME 类型,匹配用户代理字符串和使用 Rails 的 respond_to 机制。

第 2 部分 探究了可能为 iPhone 或 iPod touch 创建的实际内容。使用 iUI 库作为确保 Web 应用程序遵循 Apple 的界面外观指南的机制。得到的应用程序很像是原生的 iPhone 应用程序。该文章介绍了如何创建向下展开的列表结构,类似于 iPhone 的原生邮件应用程序。Apple 建议使用这种结构,因为这种结构易于浏览并且尺寸较小,即使使用较慢的 Edge 网络连接,也可以快速下载。

本系列的最后这一篇文章将介绍当用户浏览到列表结构末尾而应用程序实际上还需要显示一些内容时,应当如何执行操作。iUI 给内容及表单布局提供一些有用功能。本文还介绍一些为应用程序提供特别改进的功能,例如,捕捉用户电话的旋转以及添加显示在 iPhone 主屏幕中的图标。

要运行示例,需要一些工具。当然,您需要 Ruby 和 Rails。与 Rails 结合使用的编辑器或者集成开发环境(IDE)十分有帮助,例如 Eclipse with Aptana Studio。iPhone 视图屏幕的模拟器也十分有帮助(第 1 部分 讨论了一些选项的优点)。本文使用的示例是 Soups OnLine,这是在我的 Professional Ruby on Rails 一书中最初创建的菜谱交易站点。不过,对于本文来说,该站点的具体细节并不重要。iUI 工具包提供了带有层叠样式表(Cascading Style Sheets,CSS)和 JavaScript 的 iPhone 感观。创建了 rails_iui 插件以将 iUI 功能封装到 Rails 助手以及其他最佳实践的 Rails 用法中。

使用面板处理列表

在撰写完 第 2 部分 时,我已经创建了浏览结构,可以向 iPhone 用户或者 iPod-touch 用户呈现浏览选项列表。一些选项指向按字母顺序或者按最近访问组织的另一个菜谱列表。在这些清单中单击一个菜谱将可能把用户引导到介绍该菜谱的页面。

在设计 iPhone 显示页面中的各个元素时,必须牢记 iPhone 屏幕的细节。我为该应用程序所选的视窗设置将把页面的宽度设为设备当前方位的宽度。由于我希望此 Web 应用程序看上去像是一个原生的 iPhone 应用程序,因此我还禁用了用户进一步放大的功能。因此,确保我的设计在垂直方向不超出 320 像素的 iPhone 宽度十分重要(我将简要介绍定向更改)。如果可以确保页面不超出像素为 320x480 的屏幕,则十分理想。但是,如果用户不得不朝一个方向滚动页面,那么也没问题。

iPhone 界面的其他方面将混合小屏幕尺寸的效果。与普通桌面屏幕相比,iPhone 的像素排列得更加密集,意味着实际手机中显示的字体和图像比模拟屏幕中显示得更小。您可能必须放大字体大小才能看得清。而且,用户用手指点击屏幕不会像鼠标单击一样精确。Apple 建议可单击的目标至少为 44 像素的正方形以获得最佳可用性。

记住这一点,图 1 显示了我在菜谱显示页面中提供的内容。我保持了 iUI 中提供的样式以使一切变得更简单。


图 1. 菜谱显示页面
菜谱显示页面

此页面的 Rails 代码利用一些 rails_iui 助手以简化对 iUI 功能的访问。此文件为 app/views/recipes/show.iphone.erb。启用此功能所需的惟一一处控制器更改是将 format.iphone 代码行添加到相应控制器操作的 respond_to 代码块中,如下所示:


清单 1. 菜单显示代码
                
    <% panel do %>
      <% if @recipe.has_image? %>
        <%= image_tag(@recipe.soup_image.public_filename, :align => :left,
            :height => 80, :width => 80, 
            :style => "padding: 5px" ) %>
      <% else %>
        &nbsp;
      <% end %>
      <div>Servings: <%= @recipe.servings %></div>
      <br/>
      <div>Description:</div>
      <div><%= @recipe.description %></div><br/>
      <div>Ingredients:</div>
      <% fieldset do %>
        <% for ingredient in @recipe.ingredients %>
          <% row_label do %>
            <%= h ingredient.display_string %>
          <% end %>
        <% end %>
      <% end %>
      <div>Directions:</div>
      <% fieldset do %>
        <%= row @recipe.directions %>
      <% end %>
      <div>Tags: <%= h @recipe.tag_list.to_s %></div>
    <% end %>
            

在撰写本文时,iUI CSS 结构有一些特殊的地方,大多数情况与一些限制有关,即一些特殊类的出现必须响应其他的标记。无论如何,这段代码都使用一些 rails_iui 代码块助手,这些助手将用 iUI 所定义的特定 CSS 类封装 div 标记。

第一个助手是位于代码段顶部的处理程序 panel,这是带有 panel 类的 div 标记的包装器。panel 类将把元素的边界设为设备框的大小,添加 10 个像素的填充,并且设置页面的背景颜色和条纹。这将模拟 iPhone 设置页面。

此屏幕的另一个独特的特征是圆角矩形。在 Mobile Safari 中,用名为 -webkit-border-radius 的自定义 CSS 属性可以轻松地进行处理,在本例中,该属性被设为 10px。在 iUI 面板内,fieldset 标记用于指定圆角矩形的边界。除了边界半径以外,面板 > 字段集选择器还将设置顶部空白、白色背景、边界及 16 个点的右对齐文本(就像您在 iPhone 设置页面的单个元素中看到的那样)。rails_iui 将 fieldset 代码块助手定义为放置 fieldset 标记对。

现在,当看到图 1 中的文本都是左对齐时,fieldset 中的文本是右对齐的。那是因为有更多更改文本对齐的 CSS 类。您在配料清单中看到的 row 类将设置 42 像素高的块,该块适用于圆角矩形内的一叠行中的一行。在 row 类中,label 标记将把文本设为粗体并将它放回到该行的末尾。可以在设置页面中看到其最初版本,其中标签左对齐,设置切换在右侧。

rails_iui 为行定义了两个助手,出于演示目的,本例中同时使用了这两个助手。row 版本将获取一个实参、字符串和可选块。该字符串用作标签文本,块是行内容(与所有 Rails 块助手一样,非块版本使用 ERb 模板的输出对 <%= 分隔,而块版本只使用 %lt;%)。row_label 助手将获取一个块并将块文本(而非其他行内容)放入标签标记中。





表单

Mobile Safari 提供了很多精心设计的功能,用于克服在小型触摸屏中输入表单数据的潜在限制。这些功能中最显而易见的是用于文本输入的软键盘和用于 select 列表的较大的滚动条,iPhone Web 开发人员必然会用到这些功能。但是,在调用时,这些元素需要占用屏幕空间,因此请记住,如果超出字段和 Mobile Safari 输入面板,您的用户无法看到太多页面。

对于文本字段,Mobile Safari 将定义用于控制软键盘行为的两个自定义属性:autocorrect 和 autocapitalize。默认情况下,两个属性的值都为 on,但是可以设为 off 以删除功能。自动更正功能将控制用户是否会看到显示在输入字段下方的常见拼写错误的更正建议。自动大写功能将使用一个大写字母开始一条新语句。您可以使用 Rails 进行控制,方法是将属性作为文本的 HTML 选项的一部分传递,或者是使用密码标记控制::autocorrect => "off"。如果用户极有可能键入非单词或语句的文本,例如登录字段或密码字段,请将这些标记关闭。

下面是我为 Soups OnLine 创建的搜索表单。如 第 1 部分 中所指定,工具栏中的 Search 按钮是由 rails_iui 工具栏助手方法 <%= iui_toolbar "Soups OnLine", new_search_url %> 绘制的。

我对 第 1 部分 中所示的助手方法做了一处小改动:按钮链接改为 self 目标,这将导致刷新整个屏幕,而不是对列表横向浏览。我做出这项更改是基于如下理论:搜索不属于真正的列表浏览行为并且其行为应当有所不同。工具栏方法现在类似清单 2。


清单 2. iui_toolbar 助手方法
                
    def iui_toolbar(initial_caption, search_url = nil)
      back_button = button_link_to("", "#", :id => "backButton")
      header = content_tag(:h1, initial_caption, :id => "header_text")
      search_link = if search_url 
                    then button_link_to("Search", search_url, :id => "searchButton",
                        :target => "_self") 
                    else ""
                    end 
      content = [back_button, header, search_link].join("\n")
      content_tag(:div, content, :class => "toolbar")
    end
            

我构建的搜索屏幕十分简单,再次使用了一个最小功能集,并用于一个较小的屏幕。


图 2. 搜索界面
搜索界面

该表单包含文本输入字段、选择下拉框和切换开关,该开关是由 iUI 构建的,用于模拟原生 iPhone 切换控件。为了让此表单正常工作,我从控制器开始处理。SearchController 类已经在 Soups OnLine 应用程序中,用于创建桌面搜索表单。修改 new 控制器操作十分简单。


清单 3. SearchController 操作
                
    def new
      @search = Search.new
      @tag_cloud = TagCloud.calculate(Recipe)
      @tag_counts = TagCloud.tag_counts(Recipe)
      @tags = @tag_cloud.keys.sort
      respond_to do |format|
        format.html 
        format.iphone
      end
    end
    

Search 对象是一个小模型对象,用于允许 Rails 视图使用那些需要将表单映射到 Rails 模型对象的表单构建器方法。这个对象比较小 — 此时,该类只是存取器列表:

      class Search
        attr_accessor :keyword, :tags, :ingredients
      end    
            

稍后,该类将是放置实际搜索逻辑的好位置,以防阻碍 Recipe 类。

TagCloud 代码行用于创建放在下拉列表中的可用标记列表。代码将使用 acts_as_taggable_on_steroids 插件,该插件的详细信息与本文无关。需要注意的是 @tags 将包含字符串列表。

最后,respond_to 块将处理 iPhone 请求。注意,尽管本文的第二部分中的列表操作曾经很细致地指定 :layout => false,但是此控制器并非如此。差别在于调用操作的方式。列表操作是通过默认的 iUI Asynchronous JavaScript + XML (Ajax) 操作调用的,意味着它们要替代现有元素,并且因此无需刷新整个布局。如本文所示,Search 按钮是用 _self 的目标调用的,iUI 将它解析为普通 HTML 链接,刷新整个屏幕 — 意味着需要绘制布局。

绘制此布局的视图屏幕几乎是典型的 Rails 表单,如下所示:


清单 4. 搜索表单的视图代码
                
    <%= iui_toolbar "Soups OnLine", new_search_url %>
    <div selected="true">
      <% form_for @search do |f| %>
        <table>
          <tr>
            <th>Keyword:</th>
            <td><%= f.text_field :keyword %></td>
          </tr>
          <tr>
            <th>Tag</th>
            <td><%= f.select :tags, @tags, 
                :include_blank => true %></td>
          </tr>
          <tr>
            <th>Ingredients?</th>
            <td>
              <%= f.toggle(:ingredients) %>
            </td>
          </tr>
        </table>
        <%= f.submit "Search" %>
      <% end %>
    </div>
            

这段代码的前四分之三是一个锁定标准(lock-standard)Rails 表单。视图将首先刷新工具栏,因为该视图负责整个页面。然后有一个普通的 form_for 并且文本字段和下拉标记也是标准的。toggle 调用是使用 iUI 提供的 toggle 类的 rails_iui 助手。通过该助手得到的 HTML 类似清单 5:


清单 5. toggle 控件的 HTML
                
    <input id="search_ingredients" name="search[ingredients]" 
        type="hidden" value="OFF" />
    <div class="row">
      <div class="toggle" id="search_ingredients_toggle" 
        onclick="$('search_ingredients').value = 
            ($('search_ingredients').value == 'OFF') ? 'ON' : 'OFF';" 
        toggled="OFF">
          <span class="thumb"></span>
          <span class="toggleOn">ON</span>
          <span class="toggleOff">OFF</span>
      </div>
    </div>
            

iUI 工具包将提供 toggle、thumb、toggleOn 和 toggleOff 的 CSS 类,它们将绘制 indowx.cn/news/hot/2008718/0871882C12G62K71A29HCK52G.html 控件以及一些 JavaScript,从而在被单击后可以切换控件。但是,iUI 不会将 toggle 开关与表单控件绑定在一起,因此在这里引入 rails_iui。首先,该助手将插入带有 toggle 初始值的隐藏字段。该值将被送回到表单。rails_iui 助手还将为 toggle div 添加 JavaScript onclick 事件处理程序。该处理程序将基于当前值的相反值来回更改隐藏字段的值。如果载入 rails_iui,toggle 助手可用于任意一个 form_for 块。

为了进一步优化 Submit 按钮,iUI 提供了 whiteButton、blueButton 和 grayButton CSS 类,这其中的任意一个类都将使按钮变得更大并且更类似 iPhone 风格。





旋转

Mobile Safari 浏览器最特殊的功能之一是用户可以将它旋转 90 度以使用横向或纵向浏览器。虽然浏览器本身可以很好地刷新站点以适应不同的宽度,但是您可能需要更好地控制站点对方向变化的响应。iUI 和 rails_iui 的组合将给您提供两种方法来指定方向变化的行为。

iUI 工具包将跟踪方向变化,并且将 document.body.orient 属性的值更改为 profile 或 landscape。然后,可以根据该属性的值指定 CSS 行为,如清单 6 中的行所示,如果设备处于横向模式,则将更改 h1 标记的边缘和宽度。


清单 6. 基于方向的样例 CSS 更改
                
    body[orient="landscape"] > .toolbar > h1 {
        margin-left: -125px;
        width: 250px;
    }
 

要更精细地控制方向变化行为,rails_iui 插件允许您定义一个回调,当检测到方向变化时,该回调将把一个 Ajax 请求送回到 Rails 应用程序中。Mobile Safari 将定义 onorientationchange 事件处理程序和 window.orientation 属性以处理方向事件。Rails 可以为该事件创建一个 Ajax 监视器,并且对服务器执行一次远程回调。

要使用此回调,请将布局更改为类似清单 7。


清单 7. 使用方向变化回调的布局
                
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
           "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
    <head>
      <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
      <title>Recipes: <%= controller.action_name %></title>
      <meta name = "viewport" 
          content = "width = device-width, user-scalable=no"> 
      <%= stylesheet_link_tag 'iphone' %>
      <%= include_iui_files %>
      <%= javascript_include_tag :defaults %> 
      <%= observe_orientation_change :controller => 'browsers', 
          :action => :orientation_change %>
    </head>

    <body <%= register_orientation_change %>>
      <%= yield %>
    </body>
    </html>
            

此布局文件与在本系列第 1 部分中创建的布局文件之间有三处不同。首先,包括了默认的 JavaScript 库 — Ajax 回调所需的原型。另外两处更改包括 observe_orientation_change 和 register_orientation_change rails_iui 助手方法。register 方法是这两种方法中较为简单的。它所做的只是将字符串输出到设置事件处理程序的主体标记中,如下所示:


清单 8. register 方向变化助手
                
    def register_orientation_change
      'onorientationchange="updateOrientation();"'
    end
            

observe 方法将获取可以作为实参传递给远程助手的 :url 选项的内容,并且创建由 register 助手暗示的 updateOrientation() 方法。


清单 9. Observe 方向变化助手
                
    def observe_orientation_change(url_options = {})
      remote = remote_function :url => url_options, 	
    				:with => "'position=' + String(window.orientation)"
      func = "function() { #{remote}; };"
      javascript_tag("function updateOrientation() { #{remote}; }")
    end
  

此方法将使用 Rails 标准 remote_function 助手创建一个 JavaScript 回调(使用传递给该助手的 URL 信息),并且在 script 标记内输出函数。对服务器的回调包含一个参数:position。如果设备处于正常的垂直纵向位置,则变量值为 "0",如果电话沿逆时针方向转动,则变量值为 "90",而如果电话沿顺时针方向转动,则变量值为 "-90"(设备目前不能识别颠倒位置,但是如果将来可以支持这种旋转,则值将是 "180")。通过回调,您可以完成 Rails RJS JavaScript 模板可以完成的所有操作,包括更改屏幕中的任意一个文档对象模型(Document Object Model,DOM)对象。

通过这两种机制,您可以轻松地对改变浏览器方向作出反应。





最后几点兼容性说明

本系列应当为创建 iPhone 专用的 Web 应用程序提供了良好开端。下面是需要牢记的几点:

  • iPhone 将自动检测诸如电话号码之类的内容,并且允许用户使用电话键入这些内容来打电话(iPod 不执行此检测)。您可以用 <meta name = "format-detection" content = "telephone=no"> 元标记关闭页面中的这项功能。然后,通过将电话号码转换为表单 <a href="tel:555-1234">555-1234</a> 的 HTML 链接,您可以明确地识别电话号码。
  • 指向 Google Maps 页面的链接将退出 Mobile Safari 并打开 Maps 应用程序。同样,指向 YouTube 页面的链接将打开 YouTube 应用程序。
  • JavaScript 函数 alert、confirm 和 prompt 也可以在 iPhones 中工作,但是 showModalDialog 不可以。在 iUI 中,dialog CSS 类将模拟一些对话框行为,覆盖在屏幕上面。
  • 现在,不能在 Mobile Safari 浏览器中使用 Flash、Java™ 应用程序、无线标记语言(Wireless Markup Language,WML)、可伸缩向量图形(Scalable Vector Graphics,SVG)和可扩展样式表语言转换(Extensible Stylesheet Language Transformation,XSLT)。不支持文件上传和下载,尽管这种情况可能在 iPhone 固件 2.0 版本中改变。Mouse-over 事件、工具提示和悬浮样式也不起作用。
  • 解码时,图形交换格式(Graphics Interchange Format,GIF)、可移植网络图形(Portable Network Graphics,PNG)和标签图像文件格式(Tagged Image File Format,TIFF)图像必须小于或等于 2M 像素。子采样为大于 2M 像素、小于 32M 像素的 JPEG 图像。单个文本或媒体文件必须小于 10 MB。
  • iPhone 和 iPod touch 允许用户在主屏幕中放置表示特定 Web 应用程序的图标。要给应用程序提供自定义图标,请在 /apple-touch-icon.png 中放置 PNG 文件。图标应当是 57 个像素的方角正方形。请不要尝试包括手机图标拥有的光泽。iPhone 或 iPod-touch 操作系统将自动把角变圆,并且添加光泽效果。




结束语

今年是 iPhone 和 iPod touch 辉煌的一年。当 2.0 版本添加第三方原生应用程序时,对于支持 iPhone 的 Web 应用程序的需求只会增长。iUI 工具包和 rails_iui 插件将继续帮助所有开发人员轻松地创建优秀的 Mobile Safari 应用程序。(责任编辑:A6)


时间:2008-11-18 09:19 来源:developerWorks 中国 作者:Noel Rappin 原文链接

好文,顶一下
(1)
100%
文章真差,踩一下
(0)
0%
------分隔线----------------------------


把开源带在你的身边-精美linux小纪念品
无觅相关文章插件,快速提升流量