Как создать анимированный компонент аккордеона переменного размера в QtQuick/QML

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

Анимация аккордеона

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

Мне удалось реализовать поведение «нажми, чтобы развернуть», но анимации нет. Вот код, который у меня сейчас есть.

AccordionElement.qml

import QtQuick 2.5
import QtQuick.Layouts 1.1

ColumnLayout {
    id: rootElement

    property string title: ""
    property bool isOpen: false
    default property alias accordionContent: contentPlaceholder.data

    anchors.left: parent.left; anchors.right: parent.right

    // Header element
    Rectangle {
        id: accordionHeader
        color: "red"
        anchors.left: parent.left; anchors.right: parent.right
        height: 50
        MouseArea {
            anchors.fill: parent
            Text {
                text: rootElement.title
                anchors.centerIn: parent
            }
            cursorShape: Qt.PointingHandCursor
            onClicked: {
                rootElement.isOpen = !rootElement.isOpen
            }
        }
    }

    // This will get filled with the content
    ColumnLayout {
        id: contentPlaceholder
        visible: rootElement.isOpen
        anchors.left: parent.left; anchors.right: parent.right
    }
}

И вот как он используется из родительского элемента:

Accordion.qml

ColumnLayout {
    Layout.margins: 5

    visible: true

    AccordionElement {
        title: "Title1"
        accordionContent: Rectangle {
            anchors.left: parent.left; anchors.right: parent.right
            height: 20
            color: "green"
        }
    }
    AccordionElement {
        title: "Title2"
        accordionContent: Rectangle {
            anchors.left: parent.left; anchors.right: parent.right
            height: 50
            color: "green"
        }
    }

    AccordionElement {
        title: "Title3"
        accordionContent: Rectangle {
            anchors.left: parent.left; anchors.right: parent.right
            height: 30
            color: "green"
        }
    }

    // Vertical spacer to keep the rectangles in upper part of column
    Item {
        Layout.fillHeight: true
    }
}

Это дает следующий результат (когда все прямоугольники развернуты):

Расширенный

В идеале я хотел бы, чтобы зеленые прямоугольники выкатились из красных прямоугольников (как бумага из принтера). Но я застрял в том, как это сделать. Я попробовал несколько подходов с использованием свойства height, и зеленый прямоугольник исчез, но белое пространство осталось под красным прямоугольником.

Любая помощь будет оценена по достоинству. Есть ли подход, который мне не хватает?


person Mateo Hrastnik    schedule 29.03.2017    source источник


Ответы (1)


Вот быстрый и простой пример:

// AccItem.qml
Column {
  default property alias item: ld.sourceComponent
  Rectangle {
    width: 200
    height: 50
    color: "red"
    MouseArea {
      anchors.fill: parent
      onClicked: info.show = !info.show
    }
  }
  Rectangle {
    id: info
    width: 200
    height: show ? ld.height : 0
    property bool show : false
    color: "green"
    clip: true
    Loader {
      id: ld
      y: info.height - height
      anchors.horizontalCenter: info.horizontalCenter
    }
    Behavior on height {
      NumberAnimation { duration: 200; easing.type: Easing.InOutQuad }
    }
  }
}

// Acc.qml
Column {
  spacing: 5
  AccItem {
    Rectangle {
      width: 50
      height: 50
      radius: 50
      color: "blue"
      anchors.centerIn: parent
    }
  }
  AccItem {
    Rectangle {
      width: 100
      height: 100
      radius: 50
      color: "yellow"
      anchors.centerIn: parent
    }
  }
  AccItem {
    Rectangle {
      width: 75
      height: 75
      radius: 50
      color: "cyan"
      anchors.centerIn: parent
    }
  }
}

Вы напрасно усложняете его якорями и макетами. Кажется, проблема не требует ни одного из них.

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

введите здесь описание изображения

person dtech    schedule 29.03.2017
comment
Кажется, я ColumnLayout причинил мне много неприятностей. Это мой первый проект QML, и я работаю с Android, поэтому некоторые вещи могут сбивать с толку. - person Mateo Hrastnik; 29.03.2017
comment
Может быть макет, может быть якоря. Я не тестировал ваш код. С QML важно сохранять простоту, потому что он часто не соответствует ожиданиям или даже здравому смыслу, когда вы добавляете к нему что-то более сложное. - person dtech; 29.03.2017
comment
Если вы имеете в виду строку anchors.left:parent.left;anchors.right:parent.right, она заставляет элемент растягиваться по горизонтали, чтобы соответствовать его родителю, так что это не проблема. Что касается QML, то он мне не очень нравится. Я бы предпочел использовать HTML, CSS и немного JS для разработки графического интерфейса, но мне нужно использовать QML для этого проекта, поэтому я застрял - person Mateo Hrastnik; 29.03.2017
comment
На самом деле QML имеет несколько очень хороших аспектов, особенно привязку свойств. Как только вы концептуально получите рабочий процесс, он станет более мощным и гибким, чем все, что я использовал раньше, а я использовал практически все. Недостатком являются конструктивные ограничения и ужасное использование памяти, последнее очень вредно для больших проектов, а первое присуще каждому высокоуровневому API. - person dtech; 29.03.2017