QML не предоставляет анимацию взаимодействий кликов в стиле Material Design для Android по умолчанию, но это легко настраивается с помощью примитивов Rectangle. Анимация заключается в том, чтобы в одном родительском объекте Rectangle, при клике, необходимо второй дочерний объект Rectangle растянуть на всю область родительского. При этом дочерний объект будет растягиваться в течении определённого времени и выглядеть будет как расширяющийся круг, но при этом он не будет выходить за пределы родительского объекта.
Для наглядности создадим список элементов, по которым будем производить клики. Для отслеживания кликов будет использоваться область MouseArea, в которой будет отслеживаться несколько сигналов взаимодействия:
- onClicked - в данном сигнале будет останавливаться анимация и выполняться результат взаимодействия со списком;
- onPressed - при сигнале нажатия необходимо запустить анимацию, с предварительной установкой координат анимируемого объекта Rectangle.
- onReleased - при отпускании элемента списка необходимо остановить анимацию;
- onPositionChanged - при смене позиции области также необходимо остановить анимацию.
Для выполнения анимации используется объект PropertyAnimation. В данном объекте выбирается цель анимации, и список свойств, которые будут подвергаться изменению. В случае с анимируемым объектом Rectangl, необходимо расширять его как круг, для этого увеличиваем его свойства width, height и radius с одной и той же величиной. А для того, чтобы полностью заполнить родительский объект, выставим конечную величину свойств в три раза большую, чем ширина родительского элемента.
Также важным свойством родительского элемента является:
clip - активируя данное свойство ( true ), Мы обрезаем дочерние элементы объекта, чтобы они не выходили за границы родительского элемента.
Анимация клика - реализация в коде
import QtQuick 2.5 import QtQuick.Controls 1.4 ApplicationWindow { visible: true width: 640 height: 480 title: qsTr("Hello World") /* Создадим список с несколькими элементами, * по которым будет производитсья анимированный клик * */ ListView { anchors.fill: parent // В объекте находится ... delegate: Item { height: 48 anchors.left: parent.left anchors.right: parent.right // ... прямоугольный фон, Rectangle { id: body anchors.fill: parent color: "white" // дочерние объекты будут обрезаться по области данного родительского элемента clip: true /* ... в котором находится другой фон, который будет * анимированным кругом клика * */ Rectangle { id: colorRect height: 0 width: 0 color: "#e8e8e8" /* Свойство трансформации, в котором будут пересчитываться * стартовые координаты, чтобы был круг в центре клика * */ transform: Translate { x: -colorRect.width / 2 y: -colorRect.height / 2 } } // Надпись в элементе списка Text { text: fragment anchors.left: parent.left anchors.leftMargin: 72 anchors.top: parent.top anchors.bottom: parent.bottom font.pixelSize: 14 renderType: Text.NativeRendering horizontalAlignment: Text.AlignLeft verticalAlignment: Text.AlignVCenter } // Область клика по элементу MouseArea { anchors.fill: parent onClicked: { circleAnimation.stop() } onPressed: { /* При нажатии на элемент выставляем стартовые координаты * фона для анимации круга в элементе * */ colorRect.x = mouseX colorRect.y = mouseY // Запускаем анимацию circleAnimation.start() } onReleased: circleAnimation.stop() onPositionChanged: circleAnimation.stop() } // Анимация свойств PropertyAnimation { id: circleAnimation target: colorRect // Целью задаём круговой фон properties: "width,height,radius" // В анимации изменяем высоту, ширину и радиус закругления from: 0 // Изменяем параметры от о пикселей ... to: body.width*3 // ... до тройного размера ширины элемента списка duration: 300 // в течении 300 милисекунд // По остановке анимации обнуляем высоту и ширину анимированного фона onStopped: { colorRect.width = 0 colorRect.height = 0 } } } } model: listModel } // Модель списка с элементами ListModel { id: listModel ListElement {fragment: qsTr("1-й Фрагмент")} ListElement {fragment: qsTr("2-й Фрагмент")} ListElement {fragment: qsTr("3-й Фрагмент")} ListElement {fragment: qsTr("4-й Фрагмент")} ListElement {fragment: qsTr("5-й Фрагмент")} ListElement {fragment: qsTr("6-й Фрагмент")} ListElement {fragment: qsTr("7-й Фрагмент")} } }
Видеоурок
Результат анимации в стиле Material Design не является полностью идентичным тому, что должно быть, но показывает основную идею. Демонстрацию работы Вы можете увидеть в видеоуроке.