QML ListView
のスクロールアニメーションを実装したい。これがサンプル画像です:
これを実装するために誰かが私に助言できますか?
ありがとうございました。
何時間もの作業、調査、そして@BaCaRoZzoの多大な支援(@BaCaRoZzoに感謝)を経て、ようやく適切な解決策を見つけました。各デリゲートに関連付けられたアニメーションを実行するには、Component.onCompleted()
イベントハンドラーを使用するだけです。
ここに例があります、楽しんでください!
import QtQuick 2.3
ListView {
anchors.fill: parent
id: list
model: 100
cacheBuffer: 50
delegate: Rectangle {
id: itemDelegate
Component.onCompleted: showAnim.start();
transform: Rotation { id:rt; Origin.x: width; Origin.y: height; axis { x: 0.3; y: 1; z: 0 } angle: 0}// <--- I like this one more!
width: parent.width
height: 50
color: index % 2 === 0 ? "#EEE" : "#DDD"
SequentialAnimation {
id: showAnim
running: false
RotationAnimation { target: rt; from: 180; to: 0; duration: 800; easing.type: Easing.OutBack; property: "angle" }
}
}
}
ViewTransition は、ListView
(コンポーネント作成時の最初の項目の遷移)、populate
、add
(自明)などの操作のremove
をアニメーション化する方法に関する多くの興味深い例と他の操作を提供します。
ListView
を指定して、アニメーション化する操作ごとに要素Transition
を定義します。 アニメーションフレームワーク は、基本的なアニメーションを組み合わせて、興味のある(多かれ少なかれ)複雑な動作を作成するだけで、複合アニメーションを作成するために利用できます( here for実際の例)。
ここで、ListView
の定義(最初にリンクされたドキュメントは、いくつかの素晴らしい画像を提供します):
ListView {
// data model, delegate, other usual stuff here...
// transitions for insertion/deletation of elements
add: Transition {
NumberAnimation { property: "opacity"; from: 0; to: 1.0; duration: 500 }
NumberAnimation { property: "scale"; easing.type: Easing.OutBounce; from: 0; to: 1.0; duration: 750 }
}
addDisplaced: Transition {
NumberAnimation { properties: "y"; duration: 600; easing.type: Easing.InBack }
}
remove: Transition {
NumberAnimation { property: "scale"; from: 1.0; to: 0; duration: 200 }
NumberAnimation { property: "opacity"; from: 1.0; to: 0; duration: 200 }
}
removeDisplaced: Transition {
NumberAnimation { properties: "x,y"; duration: 500; easing.type: Easing.OutBack }
}
}
最後に、いくつかの動作は、シェーダーを使用し、要素のアニメーションとデリゲートの1つまたは複数のデリゲートの遷移を組み合わせることによって取得できることに注意してください。良い例は Tweet Search で、バーアイテムのシェーディング効果([ShaderEffect][5]
を参照)がTransition
ListView
の単純なadd
と組み合わされています。
例のようにカスタマイズされたスクロールを提供するには、Item
内のListView
sの位置を考慮する必要があります。実用的なソリューションの鍵は、ビューの可視部分内のItem
の現在の位置を計算し、その値を使用して計算する方法を見つけることです適切な変換。 ListView
は、この目的に役立ついくつかの有用なプロパティを持つFlickable
から派生しています。
ただし、y
のItem
プロパティは、ListView
内のコンテンツのoverall高さを参照します。その位置をw.r.tにするには可視領域の始まり contentY
プロパティを使用できます。この場合、画像は1000語に相当します。
y
とcontentY
の違いは、必要な変換係数を計算するために使用できる値を提供します(height
のListView
に関連している可能性があります)。実際、ListView
がフリックされると、2つの値とそれらの差が変化し、特定のItem
の変換係数が変化します。
そのような変換は、問題のpartのみをカバーします。フリック/移動が終了したら、Item
sアニメーションを「終了」して、表示されているすべてのitem
sを使用できるようにする必要があります。この目的のために、 Binding
とそのwhen
プロパティを利用して、必要な場合のみ、つまり flicking
または dragging
が終了したときにのみ、終了アニメーションをアクティブ化できます。
この(退屈な)導入をすべて踏まえて、2番目のアニメーション(より単純なもの)を考慮に入れましょう。ここでは scale
を使用して目的の効果を得ることができます。 delegate
内のListView
コードは次のようになります。
ListView {
id: list
model: 100
spacing: 10
delegate: Rectangle {
id: itemDelegate
property int listY: y - list.contentY // stores the difference between the two values
width: parent.width
height: 50
border.color: "lightgray"
color: "red"
Binding {
target: itemDelegate
property: "scale"
value: 1 - listY / list.height / 2 // the "scale" property accepts values in the range [0, 1]
when: list.moving || list.flicking || list.dragging // ...when moved around
}
Binding {
target: itemDelegate
property: "scale"
value: 1 // flick finished --> scale to full size!
when: !(list.moving || list.dragging) // not moving or dragging any more
}
Behavior on scale {
NumberAnimation { duration: 100; to: 1}
enabled: !(list.flicking || list.dragging) // active only when flick or dragging ends!
}
}
}
最初のBinding
は、listY
に基づいてスケーリング係数を定義しますが、2番目はListView
が移動していない場合にのみ、スケーリングを1
に設定します。最後のBehavior
は、完全にスケーリングされたItem
への移行をスムーズするために必要です。
3番目の効果は、同様の方法で Rotation
を使用して取得できます。
ListView {
anchors.fill: parent
id: list
spacing: 10
model: 100
delegate: Rectangle {
id: itemDelegate
property int listY: y - list.contentY
property real angleZ: (90 * listY) / list.height // 0 - 90 degrees
transform: Rotation { Origin.x: width / 2; Origin.y: 30; axis { x: 1; y: 0; z: 0 } angle: angleZ}
//transform: Rotation { Origin.x: 0; Origin.y: 30; axis { x: 1; y: 1; z: 0 } angle: angleZ} <--- I like this one more!
width: parent.width
height: 50
border.color: "lightgray"
color: "red"
Binding {
target: itemDelegate
property: "angleZ"
value: 0
when: !(list.moving || list.dragging)
}
Behavior on angleZ {
NumberAnimation {duration: 200; to: 0}
enabled: !(list.flicking || list.dragging)
}
}
}
今回は、(任意に)Binding
を1つだけ使用することを選択しました。 最初の例でも同じを作成できます。つまり、最初のデリゲートscale: 1 - listY / list.height / 2
に書き込むことができます。
同様のアプローチに従って、最初のアニメーションなどを作成することもできます。最初のアニメーションでは、Rotation
と Translate
を組み合わせれば十分だと思います。