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 не є повністю ідентичним тому, що має бути, але демонструє основну ідею. Демонстрацію роботи Ви можете побачити у відеоуроці.