Текстовые поля – это наиболее часто используемый контрол в WebOS-приложениях. Но когда речь заходит о настройке внешнего вида этого контрола, оказывается что все не так просто. Стандартный вид WebOS приложений не всегда вызывает у пользователей положительные эмоции и Wow-эффект, поэтому довольно часто требуется изменить внешний вид приложения. Как это можно сделать – рассмотрим в этот раз.
“Из коробки” внешний вид текстовых полей ужасен и уныл (см. скриншот):

Это все, чего мы можем добиться, разместив TextField прямо в коде сцены:
simple-scele.html

<div class="palm-hasheader">
  <div class="palm-header">Simple TextField</div>
</div>
<div class="palm-header-spacer"></div>
<div id="SimpleTextField" x-mojo-element="TextField"></div>

simple-assistant.js

function SimpleAssistant() {
}

SimpleAssistant.prototype.setup = function() {
	this.controller.setupWidget('SimpleTextField', {hintText: 'Simple'}, {});
};

Как-то привести TextField к более-менее вменяемому виду можно, поместив его внутрь групбокса, а в групбокс список, а в список элемент списка, а в него враппер, а во враппер лейбл 🙂 (прям как смерть кащщеева):
group-spece.html

<div class="palm-hasheader">
  <div class="palm-header">TextField in Groups</div>
</div>
<div class="palm-header-spacer"></div>
<div class="palm-group">
  <div class="palm-group-title">Single TextField</div>
  <div class="palm-list">
    <div class="palm-row single">
      <div class="palm-row-wrapper textfield-group" x-mojo-focus-highlight="true">
        <div class="title">
          <div id="GroupedSingleTextField" x-mojo-element="TextField"></div>
        </div>
      </div>
    </div>
  </div>
</div>

<div class="palm-group unlabeled">
  <div class="palm-list">
    <div class="palm-row first">
      <div class="palm-row-wrapper textfield-group" x-mojo-focus-highlight="true">
        <div class="title">
          <div class="label">Login</div>
          <div id="GroupedLoginTextField" x-mojo-element="TextField"></div>
        </div>
      </div>
    </div>
    <div class="palm-row last">
      <div class="palm-row-wrapper textfield-group" x-mojo-focus-highlight="true">
        <div class="title">
          <div class="label">Password</div>
          <div id="GroupedPasswordTextField" x-mojo-element="PasswordField"></div>
        </div>
      </div>
    </div>
  </div>
</div>

group-assistant.js

function GroupAssistant() {
}

GroupAssistant.prototype.setup = function() {
	this.controller.setupWidget('GroupedSingleTextField', {hintText: 'Single'}, {});
	this.controller.setupWidget('GroupedLoginTextField', {hintText: 'Your Login...'}, {});
	this.controller.setupWidget('GroupedPasswordTextField', {}, {});
};

Получится что-то вроде этого:

Уже что-то, но опять же, это все стандартный внешний вид, да и групбокс видно, а он не всегда нужен и не всегда уместен.

Остается одно – допиливать все самостоятельно.
Основной проблемой при создании собственных стилей для текстовых полей является то, что при создании, внутрь текстового поля система кладет еще несколько вложенных элементов. Помимо самого текстового поля, внутри еще есть div с подсказкой (задается в атрибутах полем hintText) и div, содержащий копию значения текстового поля, когда это текстовое поле теряет фокус.
Принимая во внимание все выше сказанное, можно приступить к рестайлингу.
styled-scene.html

<div class="palm-hasheader">
  <div class="palm-header">Simple TextField</div>
</div>
<div class="palm-header-spacer"></div>
<div id="StyledLoginTextField" class="styled-textfield" x-mojo-element="TextField"></div>
<div id="StyledPasswordTextField" class="styled-textfield" x-mojo-element="PasswordField"></div>

styled-assistant.js

function StyledAssistant() {
}

StyledAssistant.prototype.setup = function() {
	this.controller.setupWidget('StyledLoginTextField', {hintText: 'Login'}, {});
	this.controller.setupWidget('StyledPasswordTextField', {hintText: 'Password'}, {});
};

sample.css

#mojo-scene-styled-scene-scroller
{
    background: url(../images/background.jpg) repeat;
}

.styled-textfield input[type=text], .styled-textfield input[type=password] {
  width: 274px !important;
  -webkit-border-radius:15px;
  margin:15px;
  padding: 8px 8px;
  border:1px solid #ccc;
  display:block !important;
  font-size: 0.8em;
}
.styled-textfield div:nth-child(2) {display:none;visibility:hidden;}
.styled-textfield .hint-text 
{
  margin: 9px 0 0 23px !important;color:#666;
  font-size: 0.8em;
}

И вот, у нас сцена с двумя текстовыми полями. Каждое текстовое поле имеет скругления и свой шрифт. Выглядит все это как-то так:

И никаких списков или групбоксов 🙂

Скачать исходный код примера.

Previous ArticleNext Article
Технический директор IT-Dimension, компании-разработчика кросс-платформенного программного обеспечения

Leave a Reply

Your email address will not be published. Required fields are marked *

P.

Plug-In Development Kit (PDK) для Palm WebOS доступно для скачивания

Инструментарий для разработки native-приложений для Palm WebOS – Plug-In Development Kit (PDK) доступен для загрузки. PDK позволяет писать приложения для WebOS, используя C++ и OpenGL ES, а также разрабатывать компоненты WebOS-приложений на С++.
С выходом этого инструментария для разработчиков открывается ну просто немерянное поле для творчества. Ведь на C++ можно сделать кучу всего полезного, чего [еще] нельзя сделать средствами JavaScript. 3D-игры, например. И вобще игры с хорошей графикой. Я уже думаю над чем-то подобным.

В общем, Качаем PDK для Palm WebOS и знакомимся с официальной документацией.

У.

Управление электропитанием (Power Management) в Palm WebOS

В WebOS пользователь может вручную указать интервал, по истечению которого, если устройство не используется, оно переходит в спящий режим. Этот интервал может варьироваться вдиапазоне от 30 секунд до 3х минут.

В некоторых приложениях может возникнуть необходимость держать устройство включенным по истечению интервала, заданного пользователем (это может быть актуально, например, для приложений, воспроизводящих видео или аудио). Для поддержания устройства в активном состоянии в WebOS существует специальный API. О нем и пойдет речь в этот раз.

Итак, нам понадобится тестовое приложение. Создаем проект и в нем сцену main.

app/views/main/main-scene.html

<div class="palm-hasheader">
  <div class="palm-header">Power Management Test</div>
</div>
<div class="palm-header-spacer"></div>
<div id="TimeoutPicker" x-mojo-element="IntegerPicker"></div>
<div id="StartActivityButton" x-mojo-element="Button"></div>
<div id="StopActivityButton" x-mojo-element="Button"></div>
<div id="ExitButton" x-mojo-element="Button"></div>
<div id="info" class="palm-body-text"></div>

Сцена содержит виджет для выбора таймаута, в течении которого устройство не должно засыпать, а также кнопки:

  • Переход в активносе состояние
  • Выход из активного состояния
  • Выход из приложения

app/assistants/main-assistant.js

function MainAssistant() {
}

MainAssistant.prototype.setup = function() {
    this.controller.setupWidget("TimeoutPicker",
        {
            modelProperty: 'value',
            label: 'Timeout (minutes)',
            min: 01,
            max: 15,
            padNumbers: true
        },
        this.timeoutModel =
        {
            value: 1
        });
    this.controller.setupWidget("StartActivityButton", {},
        this.startButtonModel = {label: "Start Activity"});
    this.controller.setupWidget("StopActivityButton", {},
        this.stopButtonModel = {label: "Stop Activity", disabled: true});
    this.controller.setupWidget("ExitButton", {}, {label: "Exit"});

    Mojo.Event.listen($(StartActivityButton), 
        Mojo.Event.tap, this.onStartActivity.bind(this));
    Mojo.Event.listen($(StopActivityButton), 
        Mojo.Event.tap, this.onStopActivity.bind(this));
    Mojo.Event.listen($(ExitButton), Mojo.Event.tap, this.onExit.bind(this));

    this.counter = 0;
}

MainAssistant.prototype.onStartActivity = function(event) {
}

MainAssistant.prototype.onStopActivity = function() {
}

MainAssistant.prototype.onExit = function(event) {
    this.controller.stageController.getAppController().closeAllStages();
    window.close();
}

MainAssistant.prototype.cleanup = function(event) {
    Mojo.Event.stopListening($(StartActivityButton), Mojo.Event.tap, this.onStartActivity);
    Mojo.Event.stopListening($(StopActivityButton), Mojo.Event.tap, this.onStopActivity);
    Mojo.Event.stopListening($(ExitButton), Mojo.Event.tap, this.onExit);
}

В результате получим такой внешний вид приложения:

WebOS Power Management Sample Application

Теперь можно писать логику для обработчиков событий.

Для запуска активного режима приложения необходимо вызвать метод activityStart сервиса palm://com.palm.power/com/palm/power.

MainAssistant.prototype.onStartActivity = function(event) {
    this.counter++;
    this.activity = /* "com.palm.app."  + */
        Mojo.appName + ".activity-" + this.counter;
    this.controller.serviceRequest("palm://com.palm.power/com/palm/power",
    {
         method: "activityStart",
         parameters:
         {
             id: this.activity,
             duration_ms: this.timeoutModel.value * 60 * 1000
         },
         onSuccess: this.activityStartSuccess.bind(this),
         onFailure: this.activityStartFailure.bind(this)
        });
    this.timer = setTimeout(this.onTimer.bind(this),
        this.timeoutModel.value * 60 * 1000 / 2.0);
}

MainAssistant.prototype.onTimer = function(event) {
    if(this.timer)
    {
        clearTimeout(this.timer);
        delete this.timer;
    }
    this.onStopActivity();
}

MainAssistant.prototype.activityStartSuccess = function(event) {
    this.startButtonModel.disabled = true;
    this.stopButtonModel.disabled = false;
    this.controller.modelChanged(this.startButtonModel);
    this.controller.modelChanged(this.stopButtonModel);
    $(info).update("Activity started: " + this.activity);
}

MainAssistant.prototype.activityStartFailure = function(event) {
    $(info).update("Error:<br>" + Object.toJSON(event));
}

Параметры метода activityStart:

  • id – уникальный идентификатор вызова активного режима (можно использовать формат ID-приложения + ID-операции + счетчик).
  • duration_ms – длительность активного режима в миллисекундах. Максимальное значение єтого параметра 900000, что соответствует 15ти минутам.

Возможные проблемы:

  • На эмуляторе вызов activityStart не дает видимого эффекта. Виртуальная машина остается активной всегда.
  • На официальном форуме разработчиков WebOS-приложений неоднократно появлялась информация о том, что активный режим работает только для системных приложений (с идентификатором, начинающимся на com.palm.app). Также была информация что эту проблему исправили и активный режим доступен для разработчиков сторонних приложений, но без устройства это подтвердить нет никакой возможности.
  • По окончанию активного режима приложение не получает никаких уведомлений, и в случае, когда активный режим завершился, а приложение все еще должно держать устройство включенным, надо перезапускать активный режим заново, указывая новый идентификатор вызова. В таком случае очень удобно пользоваться счетсиком. Для того, чтобы вовремя продлить активный режми, можно использовать таймер.

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

MainAssistant.prototype.onStopActivity = function() {
    if(this.activity)
    {
        this.controller.serviceRequest("palm://com.palm.power/com/palm/power", {
             method: "activityEnd",
             parameters:
             {
                 id: "com.palm.app.news.update-1"
             },
             onSuccess: this.activityStopSuccess.bind(this),
             onFailure: this.activityStopFailure.bind(this)
        });
    }
}

MainAssistant.prototype.activityStopSuccess = function(event) {
    this.startButtonModel.disabled = false;
    this.stopButtonModel.disabled = true;
    this.controller.modelChanged(this.startButtonModel);
    this.controller.modelChanged(this.stopButtonModel);
    $(info).update("Activity stopped: " + this.activity);
    delete this.activity;
}

MainAssistant.prototype.activityStopFailure = function(event) {
    $(info).update("Error:<br>" + Object.toJSON(event));
}

MainAssistant.prototype.onExit = function(event) {
    this.controller.stageController.getAppController().closeAllStages();
    window.close();
}

При выходе из приложения, автоматического останова активного режима не происходит, поэтому в методе cleanup() главной формы все вызовы активного режима должны быть завершены.

MainAssistant.prototype.cleanup = function(event) {
    Mojo.Event.stopListening($(StartActivityButton), Mojo.Event.tap, this.onStartActivity);
    Mojo.Event.stopListening($(StopActivityButton), Mojo.Event.tap, this.onStopActivity);
    Mojo.Event.stopListening($(ExitButton), Mojo.Event.tap, this.onExit);
    this.onStopActivity();
}

На этом все.

Скачать исходный код примера.