Разработка приложений для iPhone с применением Ruby on Rails и Eclipse: Часть 3. Разработка более сложных представлений для iPhone

Создание представлений и форм

Устройства iPhone и iPod touch сделали Mobile Safari самым популярным мобильным браузером в США. Хотя Mobile Safari отлично подходит для работы с нормальными Web-страницами, многие Web-разработчики создали специальные версии приложений для iPhone. В третьей части серии "Разработка приложений для iPhone с применением Ruby on Rails и Eclipse" мы объясним, что делать, когда пользователь достигает конца структуры списка, и нужно отображать какой-то контент.

Ноэль Раппин, вице-президент по Rails-разработкам, Pathfinder Development

Ноэль Раппин (Noel Rappin) является вице-президентом по Rails-разработкам компании Pathfinder Development (http://www.pathf.com) и имеет десятилетний опыт в области разработки Web-приложений. Он получил докторскую степень в Технологическом институте штата Джорджия, где учился преподаванию концепции объектно-ориентированного проектирования. Автор книги «Professional Ruby on Rails» и соавтор книг «wxPython in Action» и «Jython Essentials». Подробнее см. на страницах http://www.pathf.com/blogs и http://10printhello.blogspot.com.



27.05.2009

В первых двух частях этой серии рассматриваются два важных аспекта структурирования приложения Ruby on Rails для обслуживания специального контента, отображаемого пользователям браузера Mobile Safari на устройствах iPhone и iPod touch. В первой части говорится о том, как настроить сервер, чтобы он обнаруживал Mobile Safari и передавал в этот браузер альтернативный контент. Выбранный механизм, который не является единственным способом достижения этой цели, предусматривает создание типа pseudo-MIME, согласование последовательности пользователь-агент и применение механизма Rails respond_to.

Во второй части рассматривается реальный контент, который можно создавать для iPhone или iPod touch. В качестве механизма согласования Web-приложения с рекомендациями по форме и содержанию Apple применяется библиотека iUI. Готовые приложения очень похожи на стандартные приложения для iPhone. Мы научились создавать структуры списков для многоуровневой навигации, как в стандартном приложении iPhone Mail. Apple рекомендует такие структуры как компактные и простые для навигации, что позволяет быстро загружать их даже через медленное сетевое соединение Edge.

В этой заключительной статье данной серии рассматривается момент, когда пользователь достигает конца структуры списка, и приложение должно вывести ему ту или иную информацию. Библиотека iUI содержит некоторые полезные функции для управления формой и содержанием. В ней есть также функции, которые придадут вашему приложению некоторый дополнительный блеск, такие как реагирование на поворот устройства в вертикальной плоскости и добавление ярлыка, отображаемого на исходном экране iPhone.

Для работы с примерами нам потребуются несколько инструментов. Конечно, нужен Ruby and Rails. Будет полезен редактор или интегрированная среда разработки (IDE), поддерживающая Rails, такая как Eclipse с Aptana Studio. Также полезен имитатор экрана iPhone (преимущества разных вариантов обсуждаются в первой части). В примере используется сайт рецептов супов Soups OnLine, первоначально созданный для моей книги Professional Ruby on Rails. Однако детали этого сайта для данной статьи не имеют особого значения. Набор инструментов iUI имитирует форму и содержание iPhone при помощи каскадных таблиц стилей (Cascading Style Sheets - CSS) и JavaScript. Для упаковки функций iUI в хелперы и другие практические формы Rails применяется специально созданный модуль rails_iui.

Выход из списка на информативную страницу

Во второй части мы остановились на том, что создали структуру навигации, которая предоставляет пользователю iPhone или iPod набор вариантов выбора. Некоторые из них ведут ко второму списку — рецептов, организованных в алфавитном порядке или по давности обращения. Предполагается, что выбор рецепта в одном из этих списков должен приводить пользователя на страницу с описанием данного рецепта.

При создании отдельных элементов страницы для дисплея iPhone важно соблюдать параметры экрана iPhone. Для своего приложения мы выбрали ширину страницы, совпадающую с шириной экрана устройства при его текущей ориентации. Если мы хотим, чтобы это приложение выглядело как стандартное приложение для iPhone, то пользователя нужно лишить возможности увеличивать изображение. Поэтому важно сохранять ширину iPhone при его вертикальной ориентации в 320 пикселей. (Об изменении ориентации мы еще поговорим.) Если можно сохранять страницу в пределах экрана 320x480 пикселей, то это идеально. Но не страшно, если пользователю придется прокручивать ее в каком-то одном направлении.

Другие характеристики дисплея iPhone ослабляют эффект от малого размера экрана. У iPhone гораздо более плотное расположение пикселей, чем у обычного настольного дисплея, поэтому шрифты и изображения на реальном устройстве кажутся мельче, чем на имитируемом экране. Для читабельности можно увеличить размеры шрифтов. Более того, палец пользователя позиционируется на экране не так точно, как указатель мыши. Для достижения максимального удобства Apple рекомендует делать кликабельные цели со стороной как минимум 44 пикселя.

На рисунке 1 показано, что я с учетом всего этого «наваял» для страницы рецепта. Для упрощения я сохранил стили, предлагаемые iUI.

Рисунок 1. Страница рецепта
Страница отображения рецепта

В целях упрощения доступа к функциям iUI код Rails для этой страницы использует некоторые хелперы rails_iui. Это файл app/views/recipes/show.iphone.erb. Единственное изменение, которое нужно внести в контроллер, — добавление строки format.iphone в соответствующий блок действия контроллера respond_to, как показано в листинге 1.

Листинг 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, которые обертывают теги div определенными классами, заданными iUI.

Первый из них – это расположенный в начале фрагмента хендлер panel, который заключает тег div в класс panel. Класс panel устанавливает границу элемента в соответствии с размером устройства, добавляет поля в 10 пикселей и наносит на страницу фоновый цвет и полоски. Это имитирует страницу настроек и другие страницы iPhone.

Другая особенность этого экрана – прямоугольные рамки со скругленными углами. В Mobile Safari это легко достигается при помощи особого параметра CSS -webkit-border-radius, который в данном случае имеет значение 10px. Внутри панелей iUI для указания границ таких прямоугольных рамок используется тег fieldset. Кроме радиуса границ, селектор панели > fieldset задает также верхнее поле, белый фон, толщину рамки и текст высотой 16 пунктов с выравниванием по правому краю (как у отдельного элемента страницы параметров iPhone). Хелпер блока fieldset Rails_iui размещает пару тегов fieldset.

Я сказал, что текст в fieldset выровнен по правому краю, хотя текст на рис.1 выровнен по левому краю. Дело в том, что существуют другие классы CSS, которые изменяют выравнивание текста. Класс row, присутствующий в списке ингредиентов, устанавливает высоту блока в 42 пикселя, подходящую для одной строки в группе строк внутри прямоугольной рамки. Внутри класса row тег label устанавливает режим текста bold и помещает этот текст в конец строки. Примером стандартной версии этого формата служит страница параметров, где названия выровнены по левому краю, а переключатели расположены справа.

Rails_iui определяет два хелпера для строк, и в данном примере в целях демонстрации используются оба. Версия row содержит один аргумент типа строки и необязательный блок. Строка содержит текст названия, а блок отображает эту строку. (Как и во всех хелперах блоков Rails, в версии без блока в качестве разделителей применяется выходная пара <%= шаблона ERb, а в версии с блоком — просто %lt;%). Хелпер в качестве единственного содержания строки row_label помещает в тег названия текст блока.


Формы

Mobile Safari обладает рядом функций, предназначенных для преодоления возможных ограничений, связанных с отображением форм на маленьком экране. Наиболее очевидные из этих функций — программная клавиатура для ввода текста и большая линейка прокрутки для списков select— автоматически доступны в качестве средства Web-разработки iPhone. Однако эти элементы занимают место на экране, так что помните, что ниже поля и панели ввода Mobile Safari пользователи мало что увидят.

Для текстовых полей Mobile Safari определяет два специальных атрибута, управляющих поведением программной клавиатуры: autocorrect и autocapitalize. Оба по умолчанию включены, но могут быть выключены путем присвоения им значения off. Атрибут auto-correct управляет тем, будет ли пользователь видеть подсказки по орфографии, отображаемые под полем ввода. Атрибут auto-capitalize открывает новое предложение с прописной буквы. Этими атрибутами можно управлять либо при помощи Rails, передавая атрибут как часть HTML-опций текста, либо при помощи тегов пароля: :autocorrect => "off". Выключите их, если имеется высокая вероятность того, что пользователь будет вводить текст, не являющийся словами или предложением, такой как логин или пароль.

Вот форма поиска, которую я составил для Soups OnLine. Как сказано в первой части, кнопка Search (поиск) на панели инструментов рисуется методом хелпера панели инструментов rails_iui <%= iui_toolbar "Soups OnLine", new_search_url %>.

Я внес в метод хелпера, приведенный в первой части, одно мелкое изменение: целевая ссылка кнопки заменена на 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).

Рисунок 2. Дисплей поиска
Дисплей поиска

Форма состоит из поля для ввода текста, разворачивающегося списка и выключателя, построенного iUI и имитирующего стандартный элемент управления iPhone. Чтобы эта форма заработала, начнем с контроллера. В приложении Soups OnLine уже существует класс SearchController для создания настольной формы поиска. Работу контроллера new легко модифицировать (листинг 3).

Листинг 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. Под компактным я в данном случае понимаю класс, состоящий всего лишь из списка аксессоров (accessors):

      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.

Листинг 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>

На первые три четверти это самая стандартная форма Rails. Отображение начинается с перерисовки панели инструментов, так как это представление отвечает за всю страницу. Затем следует обычный оператор form_for и теги текстового поля и развертывающегося меню, также стандартные. Вызов toggle представляет собой хелпер rails_iui, использующий имеющиеся в iUI классы переключателей. Код HTML, получаемый посредством этого хелпера, выглядит как в листинге 5:

Листинг 5. 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 содержит классы CSS toggle, thumb, toggleOn и toggleOff, которые рисуют элемент выключателя и создают JavaScript для его модификации при нажатии. Однако iUI не связывает переключатель с элементом формы, так что здесь вступает в игру rails_iui. Во-первых, хелпер помещает первоначальное значение выключателя в скрытое поле. Это значение и будет передаваться в форму. Кроме того, хелпер rails_iui добавляет элемент управления событиями JavaScript onclick для переключения div. Этот хендлер изменяет значение скрытого поля на противоположное. Если rails_iui загружен, хелпер toggle доступен для любого блока form_for.

Чтобы дополнительно выделить кнопку Submit, можно воспользоваться классами CSS iUI whiteButton, blueButton или grayButton, каждый из которых делает кнопку немного более крупной и соответствующей стилю 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 позволяет определять реакцию, которая при изменении ориентации направляет в приложение Rails запрос Ajax. Для управления событиями ориентации Mobile Safari определяет хендлер событий onorientationchange и свойство window.orientation. Rails может создать элемент наблюдателя за событиями и направлять дистанционные вызовы к серверу.

Чтобы инициировать такую реакцию, измените свой макет, как показано в листинге 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>

Между этим файлом и тем, что был создан в первой части серии статей, существует три различия. Во-первых, включены библиотеки JavaScript по умолчанию — для отзыва Ajax требуется прототип. Два других отличия заключаются в методах хелпера rails_iui observe_orientation_change и register_orientation_change. Простейший из них — метод регистрации. Он просто вводит в тег body строку, которая настраивает хендлер событий, как показано в листинге 8.

Листинг 8. Регистрация хелпера реагирования на изменение ориентации
    def register_orientation_change
      'onorientationchange="updateOrientation();"'
    end

Метод наблюдения использует в качестве аргумента все, что можно передать в опцию :url удаленного хелпера, и создает метод updateOrientation(), на который ссылается хелпер регистрации (листинг 9).

Листинг 9. Хелпер наблюдения за изменениями ориентации
    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".) Посредством этого обращения можно делать все, что позволяет шаблон JavaScript Rails RJS, включая замену любого объекта Document Object Model (DOM) на экране.

При помощи этих двух механизмов приложение может легко реагировать на изменение пользователем ориентации своего браузера.


Заключительные замечания по совместимости

Эта серия статей поможет вам приступить к созданию собственного Web-приложения, специализированного для iPhone. Вот еще некоторые моменты, о которых следует помнить:

  • iPhone автоматически обнаруживает то, что напоминает телефонные номера, и позволяет звонить по ним. (iPod не производит такого определения.) На своей странице эту функцию можно выключить при помощи метатега <meta name = "format-detection" content = "telephone=no">, а затем явно включить телефонные номера в форме HTML-ссылок вида <a href="tel:555-1234">555-1234</a>.
  • Ссылки на страницы Google Maps приводят к выходу из Mobile Safari и открытию приложения Maps. Аналогично, ссылки на страницы YouTube открывают приложение YouTube.
  • Функции JavaScript alert, confirm и prompt отлично работают в iPhone, но функция showModalDialog не работает. В iUI класс CSS dialog имитирует поведение диалога, создавая накладное окно в верхней части экрана.
  • Flash, Java™-приложения, Wireless Markup Language (WML), Scalable Vector Graphics (SVG) и Extensible Stylesheet Language Transformation (XSLT) в браузере Mobile Safari пока не работают. Загрузка файлов не поддерживается, хотя с выходом микропрограммного обеспечения для iPhone версии 2.0 это может измениться. Не работают также события mouse-over, всплывающие подсказки (tooltips) и «парящие» (hover) стили.
  • Изображения в форматах Graphics Interchange Format (GIF), Portable Network Graphics (PNG) и Tagged Image File Format (TIFF) после декодирования должны иметь размер не более 2 мегапикселей. Изображения JPEG крупнее 2 мегапикселей подвергаются субдискретизации (но они не должны быть крупнее 32 мегапикселей). Размер отдельных текстовых или медиафайлов не должен превышать 10 Мбайт.
  • iPhone и iPod touch позволяют помещать на экран ярлыки Web-приложений. Чтобы присвоить своему приложению специальный значок, поместите файл PNG в каталог /apple-touch-icon.png. Значок должен помещаться в квадрате с нескругленными углами и стороной 57 пикселей. И не пытайтесь добиться глянца, как у стандартных ярлыков. Операционная система iPhone или iPod touch автоматически скруглит углы и добавит эффект глянца.

Что впереди

Это был замечательный год для iPhone и iPod touch. Несмотря на то, что версия 2.0 добавит стандартные приложения от независимых разработчиков, потребность в Web-приложениях для iPhone будет только расти. Инструментарий iUI и модуль rails_iui позволяют любому разработчику легко придать своему приложению для Mobile Safari великолепный вид.

Ресурсы

Научиться

Получить продукты и технологии

Обсудить

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Мобильные приложения
ArticleID=392005
ArticleTitle=Разработка приложений для iPhone с применением Ruby on Rails и Eclipse: Часть 3. Разработка более сложных представлений для iPhone
publish-date=05272009