Статьи

Отзывчивый пользовательский интерфейс с Eclipse и SWT

Недавно у меня возникла проблема, заключающаяся в том, что мой «хорошо продуманный» дизайн представления не уменьшился разумно. Я понял, что гибкость, позволяющая упорядочить видовые части в стопках произвольных размеров в окне рабочей среды Eclipse , не совсем облегчает разработку привлекательных пользовательских интерфейсов. По крайней мере, если вы стремитесь к более чем набору действий, размещенных вокруг списка, таблицы или дерева.

По счастливой случайности я также потратил некоторое время на адаптивный веб-дизайн, так как мы планируем капитальный ремонт codeaffine.com . Именно тогда у меня появилась идея «спасти» мою концепцию пользовательского интерфейса, сделав ее более чувствительной к корректировкам размера. Поскольку результат выглядит довольно многообещающим, я решил поделиться опытом (и кодом в виде GitHub Gist ), хотя материал несколько экспериментальный 1 .

Настройка сцены

Сначала вы можете посмотреть это короткое видео (10 секунд), которое демонстрирует, что я имею в виду под «отзывчивостью к изменениям размера»:

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

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

Как это реализовано? 2

Для меня очевидным моментом для начала были SWT Layouts . Но прямое решение, основанное на одной из известных мне схем, казалось трудным. Так что я попытал счастья с созданным вручную.

Идея заключалась в использовании шкалы диапазонов ширины в качестве единицы измерения для алгоритма компоновки. Все элементы управления связаны с отдельным хранилищем для связанных данных макета. Хранилище позволяет настраивать различные параметры для каждого диапазона. Теперь алгоритм может подобрать соответствующую конфигурацию для фактической ширины компоновки и расположить элементы управления соответственно 3 .

Учитывая это, казалось естественным вызывать пользовательский макет ScaleLayout сопровождаемый перечислением Scale и реализацией данных макета ScaleData . Следующий фрагмент кода показывает, как использовать последний:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class ViewContentScaleConfig {
 
  private final ScaleData selectorData;
  private final ScaleData seperatorData;
  private final ScaleData detailData;
 
  [...]
 
  void configure() {
    layoutSuperCompact();
    layoutCompact();
    [...]
  }
  private void layoutCompact() {
    selectorData.on( Scale.COMPACT )
      .setMargin( 5, 3, 0, 0 );
    seperatorData.on( Scale.COMPACT )
      .setWidth( 1 ).setMargin( 5, 0, 0, 0 );
    detailData.on( Scale.COMPACT )
      .setMargin( 3, 3, 2, 2 );
  }
 
  private void layoutSuperCompact() {
    selectorData.on( Scale.SUPER_COMPACT )
      .tie( seperatorData ).setMargin( 3, 0, 3, 0 );
    seperatorData.on( Scale.SUPER_COMPACT )
      .tie( detailData ).setHeight( 1 );
    detailData.on( Scale.SUPER_COMPACT )
      .setMargin( 0, 8, 0, 0 );
  }
}

ScaleData облегчает ScaleData настройку атрибутов, что, я думаю, не ScaleData пояснений. Более примечательным является вызов связывания, который объединяет данные макета для заданного значения Scale , поскольку он определяет, как ScaleLayout элементы управления в определенном диапазоне.

Алгоритм размещения

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

Чтобы изменить это управление может быть привязано к другому. Обратите внимание, что допускается только одно ScaleData Scale и ScaleData . Фактически это организует элементы управления в одном или нескольких несвязанных списках.

Теперь элементы управления заголовком списка будут выстроены горизонтально. Кроме того, элементы управления конкретным списком будут расположены впоследствии под главным элементом управления. Это делается таким образом, что элементы управления списком отображаются в виде столбца. Ширина такого столбца определяется элементом управления с наибольшей предпочтительной шириной. Вычисления высоты для разных элементов управления столбца следуют тем же правилам, которые описаны выше для ширины 4 .

sc7

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

Поставщик весов

Недостающий кусок, чтобы заставить ScaleLayout действительно работать, является ориентиром. Масштаб должен быть связан с определенной композицией вашего пользовательского интерфейса. Изменение ширины этого «базового» композита может изменить размещение в «масштабе». И эта информация должна распространяться по всей структуре композиции. Корневая компоновка видовой части, очевидно, является хорошим выбором для использования в качестве контрольной точки.

Для этой цели существует класс ScaleProvider который принимает композитный объект — опорную точку — в качестве параметра конструктора, а экземпляр ScaleLayout в свою очередь, принимает ScaleProvider качестве параметра конструктора. Вот как алгоритм компоновки получает свою систему отсчета.

Кроме того, ScaleProvider предлагает возможность регистрации слушателя. Это, например, позволяет сопоставить режимы отображения элемента управления со значениями Scale . Принцип иллюстрируется селектором вариантов использования в видео выше. Реализация селектора может переключаться между двумя режимами: STANDARD и COMPACT . В следующем фрагменте показано, как изменения режима инициируются событиями изменения масштаба:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
class SelectorModeUpdater implements ScaleListener {
 
  private final InfoSelector selector;
 
  SelectorModeUpdater( InfoSelector selector ) {
    this.selector = selector;
  }
 
  public void scaleChanged( ScaleEvent event ) {
    if( Scale.SUPER_COMPACT == event.getNewScale() ) {
      selector.setMode( Mode.COMPACT );
    } else {
      selector.setMode( Mode.STANDARD );
    }
  }
}

Аналогичное сопоставление используется для запуска изменений внешнего вида панели действий.

Вывод

Подход адаптивного пользовательского интерфейса значительно улучшает внешний вид дизайна моего представления, поскольку теперь он адаптируется к различным размерам. Однако я должен отметить, что у ScaleLayout есть некоторые недостатки, которые должны быть устранены, прежде чем он станет универсальным решением. Во-первых, алгоритм раскладки, вероятно, слишком упрощен. Во-вторых, подход с фиксированным масштабом негибок и вызывает своего рода семантическую связь. В-третьих, конфигурация ScaleData имеет тенденцию становиться немного многословной …

Но вещи могут развиваться в последующих итерациях, и для изобретательной души это может послужить хорошим вдохновением или отправной точкой. И, кстати, в этом отношении мне очень любопытно решение, которое Холгер и Джорди представят для RAP / Tabris в своем выступлении « Создание адаптивных приложений SWT с RAP на EclipseCon 2014» . В частности, так как они также охватывают обработку ресурсов, которую я полностью пропустил в этом посте.

Для тех, кто любит играть, я предоставляю код реализации ScaleLayout в виде GitHub: https://gist.github.com/fappel/9168399

  1. Обратите внимание, что в этом посте нет намерения представить исчерпывающий документ о том, как адаптировать адаптивные концепции веб-дизайна к приложениям для богатых клиентов. У меня нет достаточного опыта в этом вопросе, и у меня нет мнения, действительно ли это желательно.
  2. На самом деле это был вопрос от Moritz Post, который я получил во время написания этой статьи. Вероятно, я не должен был делиться видео заранее
  3. В случае, если кто-то задается вопросом: я не занимаюсь изменениями высоты, поскольку они не создают проблем для моего дизайна пользовательского интерфейса ( принцип KISS )
  4. Gist скачать содержит демо, которое показывает, как на самом деле это работает