Состояния и переходы в QML
Часто компоненты пользовательского интерфейса можно описать с помощью состояний. Состояние определяет набор изменений свойств и может быть вызвано определенным условием.
Кроме того, к этим переключателям состояния может быть присоединен переход, который определяет, как эти изменения должны быть анимированы, или любые дополнительные действия, которые должны быть применены. Действия также могут применяться при входе в состояние.
Состояния
Состояния в QML определяются с помощью элемента State
, который необходимо привязать к массиву states
любого элемента Item
.
Состояние идентифицируется по имени и в своей простейшей форме состоит из последовательности изменений свойств элементов. Состояние по умолчанию определяется начальными свойствами элемента и имеет имя ""
(пустая строка).
Item {
id: root
states: [
State {
name: "go"
PropertyChanges { ... }
},
State {
name: "stop"
PropertyChanges { ... }
}
]
}
Состояние изменяется путем присвоения нового имени состояния свойству state
элемента, в котором определено состояние.
Item {
id: root
states: [
...
]
Button {
id: goButton
...
onClicked: root.state = "go"
}
}
Управляйте состояниями, используя when
Другой способ управления состояниями – использование свойства when
элемента State
. Свойству when
можно присвоить выражение, которое оценивается как true
, когда следует применять состояние.
Например, светофор может иметь два индикатора. Верхний сигнализирует «стоп» красным цветом, а нижний сигнализирует «идти» зеленым цветом. В этом примере оба индикатора не должны гореть одновременно. Давайте посмотрим на диаграмму диаграммы состояний.
Когда система включается, она автоматически переходит в режим «стоп», что является состоянием по умолчанию. В состоянии "stop"
индикатор light1
меняется на красный, а ligth2
– на черный (выключена).
Внешнее событие теперь может инициировать переключение состояния в состояние "go"
. В состоянии «идти» мы меняем свойства цвета light1
на черный (выключена), а light2
на зеленый, чтобы указать, что пешеходы теперь могут переходить дорогу.
Чтобы реализовать этот сценарий, мы начинаем рисовать наш пользовательский интерфейс для двух индикаторов. Для простоты мы используем 2 прямоугольника с радиусом, равным половине ширины (и ширина равна высоте, что означает, что это квадрат).
Rectangle {
id: light1
x: 25; y: 15
width: 100; height: width
radius: width/2
color: root.black
border.color: Qt.lighter(color, 1.1)
}
Rectangle {
id: light2
x: 25; y: 135
width: 100; height: width
radius: width/2
color: root.black
border.color: Qt.lighter(color, 1.1)
}
Как определено в диаграмме состояний, мы хотим иметь два состояния: одно – состояние "go"
, а другое – состояние "stop"
, где каждое из них меняет цвет соответствующего индикатора светофора на красный или зеленый. Мы устанавливаем свойство state
на stop
, чтобы гарантировать, что начальное состояние нашего светофора будет состоянием stop
.
state: "stop"
states: [
State {
name: "stop"
PropertyChanges { target: light1; color: root.red }
PropertyChanges { target: light2; color: root.black }
},
State {
name: "go"
PropertyChanges { target: light1; color: root.black }
PropertyChanges { target: light2; color: root.green }
}
]
Начальное состояние
Мы могли бы добиться того же эффекта только с состоянием "go"
и без явного состояния "stop"
, установив цвет light1
на красный, а цвет light2
на черный. Начальное состояние ""
, определенное начальными значениями свойств, будет действовать как состояние "stop"
.
Использование PropertyChanges { target: light2; color: "black" }
в этом примере на самом деле не требуется, так как исходный цвет light2
уже черный. В состоянии необходимо только описать, как свойства должны измениться по сравнению с их состоянием по умолчанию (а не с предыдущим состоянием).
Изменение состояния запускается с помощью области обработки событий мыши, которая покрывает весь светофор и при нажатии переключает состояние между "stop"
и "go"
.
MouseArea {
anchors.fill: parent
onClicked: parent.state = (parent.state == "stop"? "go" : "stop")
}
Теперь мы можем успешно изменить состояние светофора. Чтобы сделать пользовательский интерфейс более привлекательным и естественным, мы должны добавить переходы с анимационными эффектами. Переход может быть вызван изменением состояния.
Использование скриптов
Подобную логику можно создать, используя скрипты вместо состояний QML. Однако QML лучше подходит для описания пользовательских интерфейсов, чем JavaScript. По возможности старайтесь писать декларативный код вместо императивного.
Переходы
К каждому элементу можно добавить ряд переходов. Переход выполняется изменением состояния.
Вы можете определить, к какому изменению состояния можно применить конкретный переход, используя свойства from:
и to:
. Эти два свойства действуют как фильтр: когда этот фильтр имеет значение true
, будет применен переход. Вы также можете использовать подстановочный символ "*"
, что означает «любое состояние».
Например, from: "*"; to: "*"
означает «из любого состояния в любое другое состояние» и является значением по умолчанию для from
и to
. Это означает, что переход будет применяться к каждому переключению состояния.
В этом примере мы хотели бы анимировать изменение цвета при переключении состояния с "go"
на "stop"
. Для обратного изменения состояния ("stop"
на "go"
) мы хотим сохранить немедленное изменение цвета и не применять переход.
Мы ограничиваем переход свойствами from
и to
, чтобы отфильтровать изменение состояния только с "go"
на "stop"
. Внутри перехода мы добавляем две анимации цвета для каждого индикатора, которые будут анимировать изменения свойств, определенные в описании состояния.
transitions: [
Transition {
from: "stop"; to: "go"
// from: "*"; to: "*"
ColorAnimation { target: light1; properties: "color"; duration: 2000 }
ColorAnimation { target: light2; properties: "color"; duration: 2000 }
}
]
Вы можете изменить состояние, кликнув на пользовательский интерфейс. Состояние применяется немедленно, и клик изменит состояние во время выполнения перехода. Итак, попробуйте кликнуть на пользовательский интерфейс, когда состояние находится в переходе от "stop"
на "go"
. Вы увидите, что изменения произойдут немедленно.
Вы можете поэкспериментировать с этим пользовательским интерфейсом, например, уменьшая масштаб неактивного индикатора, чтобы выделить активный индикатор.
Для этого вам нужно будет добавить в состояния еще изменение свойства для масштабирования, а также доработать анимацию для свойства масштабирования в переходе.
Другой вариант – добавить состояние "attention"
(внимание), когда индикаторы мигают желтым цветом. Для этого вам нужно будет добавить к переходу последовательную анимацию на одну секунду, ведущую к желтому (свойство анимации to
и одна секунда, ведущая к «черному»).
Возможно, вы также захотите изменить кривую плавности, чтобы сделать ее визуально более привлекательной.