QML Book 第五章 動態(tài)元素 2

5.1.4 分組動畫

通常的動畫會比一個屬性的動畫更加復(fù)雜。我們可能希望同時運行多個動畫,或者一個接一個地運行動畫,有時又希望在兩個動畫之間執(zhí)行一個腳本什么的。此時,分組動畫為我們的上述需求提供了一種可能。正如這個名字所表達的那樣,我們可以對動畫進行分組。分組可以通過兩種方式進行:并行或順序。我們可以使用 ParallelAnimation(并行動畫) 或 SequentialAnimation(順序動畫) 元素,它們被用來充當(dāng)其他動畫元素的動畫容器。這些組合的動畫本身就是動畫,并且也可以被獨立地使用。

groupedanimation

當(dāng)啟動時,并行動畫的所有直接子動畫將并行運行。這允許我們同時對不同的屬性應(yīng)用動畫。

// parallelanimation.qml
import QtQuick 2.5

BrightSquare {
    id: root
    width: 600
    height: 400
    property int duration: 3000
    property Item ufo: ufo

    Image {
        anchors.fill: parent
        source: "assets/ufo_background.png"
    }


    ClickableImageV3 {
        id: ufo
        x: 20; y: root.height-height
        text: 'ufo'
        source: "assets/ufo.png"
        onClicked: anim.restart()
    }

    ParallelAnimation {
        id: anim
        NumberAnimation {
            target: ufo
            properties: "y"
            to: 20
            duration: root.duration
        }
        NumberAnimation {
            target: ufo
            properties: "x"
            to: 160
            duration: root.duration
        }
    }
}
parallelanimation_sequence

順序動畫將首先運行第一個子動畫,然后繼續(xù)執(zhí)行接下來的每個子動畫。

// sequentialanimation.qml
import QtQuick 2.5

BrightSquare {
    id: root
    width: 600
    height: 400
    property int duration: 3000

    property Item ufo: ufo

    Image {
        anchors.fill: parent
        source: "assets/ufo_background.png"
    }

    ClickableImageV3 {
        id: ufo
        x: 20; y: root.height-height
        text: 'rocket'
        source: "assets/ufo.png"
        onClicked: anim.restart()
    }

    SequentialAnimation {
        id: anim
        NumberAnimation {
            target: ufo
            properties: "y"
            to: 20
            // 60% of time to travel up
            duration: root.duration*0.6
        }
        NumberAnimation {
            target: ufo
            properties: "x"
            to: 400
            // 40% of time to travel sideways
            duration: root.duration*0.4
        }
    }
}
sequentialanimation_sequence

分組動畫也可以是嵌套的,例如,一個順序的分組動畫可以包含兩個并行的分組動畫作為子動畫,等等。我們可以用一個足球的例子來把它形象化。它的思路是把球從左向右扔,并讓它動起來的行為。

soccer_init

為了理解動畫,我們需要將其分解為對象的整體轉(zhuǎn)換。我們需要記住動畫要做的是動態(tài)的屬性改變。以下是不同的轉(zhuǎn)換:

  • 一個從左到右的 x 值的轉(zhuǎn)換(到達 X1)
  • 一個 y 值從下到上(到達 Y1)的轉(zhuǎn)換,緊接著一個從上到下(到達 Y2)的跳躍轉(zhuǎn)換
  • 在整個動畫持續(xù)時間內(nèi)旋轉(zhuǎn) 360 度(旋轉(zhuǎn)到 ROT1)

動畫的整個持續(xù)時間應(yīng)該是 3 秒。

soccer_plan

我們從一個空的 Item 元素開始,它是寬為 480 和高為 300 的根元素。

import QtQuick 2.5

Item {
    id: root
    width: 480
    height: 300
    property int duration: 3000

    ...
}

我們已經(jīng)定義了整個動畫的持續(xù)時間作為參考,以更好地同步動畫部分。

下一步是添加背景,在我們的例子中是兩個矩形,綠色和藍色的漸變。

    Rectangle {
        id: sky
        width: parent.width
        height: 200
        gradient: Gradient {
            GradientStop { position: 0.0; color: "#0080FF" }
            GradientStop { position: 1.0; color: "#66CCFF" }
        }
    }
    Rectangle {
        id: ground
        anchors.top: sky.bottom
        anchors.bottom: root.bottom
        width: parent.width
        gradient: Gradient {
            GradientStop { position: 0.0; color: "#00FF00" }
            GradientStop { position: 1.0; color: "#00803F" }
        }
    }
soccer_stage1

上面的藍色矩形的高度為 200 像素,而下面的部分則是頂部被錨定在天空的底部并且底部被錨定在根元素上的。

soccer_ball

讓我們把球放到綠色的部分上。這個球是一個圖像,存儲在 “assets/soccer_ball.png” 中,大家也可以將上面的圖片另存為我們自己的圖像資源。開始的時候,我們把它放在左下角,靠近邊緣的位置。

    Image {
        id: ball
        x: 0; y: root.height-height
        source: "assets/soccer_ball.png"

        MouseArea {
            anchors.fill: parent
            onClicked: {
                ball.x = 0;
                ball.y = root.height-ball.height;
                ball.rotation = 0;
                anim.restart()
            }
        }
    }
soccer_stage2

圖像上有一個鼠標點擊區(qū)域。如果球被點擊,球的位置將被重置,動畫重新啟動。

讓我們先從兩個 y 值轉(zhuǎn)換的順序分組動畫開始。

SequentialAnimation {
    id: anim
    NumberAnimation {
        target: ball
        properties: "y"
        to: 20
        duration: root.duration * 0.4
    }
    NumberAnimation {
        target: ball
        properties: "y"
        to: 240
        duration: root.duration * 0.6
    }
}
soccer_stage3

上面的代碼指定了前一個動畫 40% 的動畫持續(xù)時間和后一個動畫 60% 的持續(xù)時間。一個接一個的動畫執(zhí)行作為一個順序分組動畫。轉(zhuǎn)換是在線性的路徑上動態(tài)執(zhí)行的,但是目前還沒有使用曲線效果。曲線效果將在稍后使用緩沖曲線屬性添加,此時我們只專注于使轉(zhuǎn)換動畫。

接下來,我們需要添加 x 值的轉(zhuǎn)換。 x 值的轉(zhuǎn)換應(yīng)該與 y 值的轉(zhuǎn)換同時運行,所以我們需要將執(zhí)行 y 值的轉(zhuǎn)換的順序分組動畫與 x 值的轉(zhuǎn)換動畫一起封裝到一個平行分組動畫中去。

ParallelAnimation {
    id: anim
    SequentialAnimation {
        // ... our Y1, Y2 animation
    }
    NumberAnimation { // X1 animation
        target: ball
        properties: "x"
        to: 400
        duration: root.duration
    }
}
soccer_stage4

最后,我們希望球旋轉(zhuǎn)起來。為此,我們需要向并行動畫添加另一個動畫。我們選擇旋轉(zhuǎn)動畫(RotationAnimation),因為它是專門用于處理元素旋轉(zhuǎn)的。

ParallelAnimation {
    id: anim
    SequentialAnimation {
        // ... our Y1, Y2 animation
    }
    NumberAnimation { // X1 animation
        // X1 animation
    }
    RotationAnimation {
        target: ball
        properties: "rotation"
        to: 720
        duration: root.duration
    }
}

這就是整個動畫序列。剩下的一件事就是為球的運動提供正確的緩沖曲線。對于 Y1 動畫我們使用 Easing.OutCirc 曲線,這看起來更像一個圓形運動。Y2 的動畫是一個增強效果,我們使用 Easing.OutBounce 曲線,使球可以在結(jié)束時發(fā)生反彈(使用 Easing.InBounce 曲線的話你會看到反彈效果在開始時就會發(fā)生)。剩下的 X1 和 ROT1 動畫繼續(xù)使用線性曲線即可。

    ParallelAnimation {
        id: anim
        SequentialAnimation {
            NumberAnimation {
                target: ball
                properties: "y"
                to: 20
                duration: root.duration * 0.4
                easing.type: Easing.OutCirc
            }
            NumberAnimation {
                target: ball
                properties: "y"
                to: root.height-ball.height
                duration: root.duration * 0.6
                easing.type: Easing.OutBounce
            }
        }
        NumberAnimation {
            target: ball
            properties: "x"
            to: root.width-ball.width
            duration: root.duration
        }
        RotationAnimation {
            target: ball
            properties: "rotation"
            to: 720
            duration: root.duration
        }
    }

整個示例的完整代碼如下所示:

import QtQuick 2.5

Item {
    id: root
    width: 640
    height: 380
    property int duration: 3000

    Rectangle {
        id: sky
        width: parent.width
        height: 200
        gradient: Gradient {
            GradientStop { position: 0.0; color: "#0080FF" }
            GradientStop { position: 1.0; color: "#66CCFF" }
        }
    }
    Rectangle {
        id: ground
        anchors.top: sky.bottom
        anchors.bottom: root.bottom
        width: parent.width
        gradient: Gradient {
            GradientStop { position: 0.0; color: "#00FF00" }
            GradientStop { position: 1.0; color: "#00803F" }
        }
    }

    Image {
        id: ball
        x: 0; y: root.height-height
        source: "assets/soccer_ball.png"

        MouseArea {
            anchors.fill: parent
            onClicked: {
                ball.x = 0;
                ball.y = root.height-ball.height;
                ball.rotation = 0;
                anim.restart()
            }
        }
    }

    ParallelAnimation {
        id: anim
        SequentialAnimation {
            NumberAnimation {
                target: ball
                properties: "y"
                to: 20
                duration: root.duration * 0.4
                easing.type: Easing.OutCirc
            }
            NumberAnimation {
                target: ball
                properties: "y"
                to: root.height-ball.height
                duration: root.duration * 0.6
                easing.type: Easing.OutBounce
            }
        }
        NumberAnimation {
            target: ball
            properties: "x"
            to: root.width-ball.width
            duration: root.duration
        }
        RotationAnimation {
            target: ball
            properties: "rotation"
            to: 720
            duration: root.duration
        }
    }

}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 注意:最新的構(gòu)建時間:2016/03/21這章的源代碼能夠在 Assets[http://qmlbook.gith...
    趙者也閱讀 1,530評論 0 1
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,046評論 4 61
  • 我聽過最智慧的一句話,“一切都會過去的!” 并堅信這個教導(dǎo)來面對這個世界。 你也有自己聽過特別喜歡,特別智慧的一句...
    尚靈心閱讀 561評論 0 1
  • 天地有真眸,風(fēng)云清淡染。 回首一笑間,萬物盡騷然。
    平天下之文世界閱讀 368評論 3 11
  • 不是所有人單身都代表是可撩狀態(tài) 有些人對戀愛已沒有指望 只想安安靜靜讀幾年書 然后發(fā)財
    魔力小雞仔閱讀 118評論 0 0

友情鏈接更多精彩內(nèi)容