Hi,
here's a summary from an irc discussion on the topic of Behavior vs. Follow.
Thesis: Follow is not needed, Behavior does all we need and more.
Consequence: Now that we have SmoothAnimation, all we need is SpringAnimation
and then we can depricate and remove all follows (SpringFollow and
SmoothFollow).
A Behavior is a QDeclarativePropertyValueInterceptor and thus a very nice
abstraction to what a follow does.
In the dial example Dial.qml, instead of doing
angle: -130
SpringFollow on angle {
spring: 1.4
damping: .15
to: Math.min(Math.max(-130, root.value*2.6 - 130), 133)
}
we would simply do
angle: Math.min(Math.max(-130, root.value*2.6 - 130), 133)
Behavior {
SpringAnimation{ spring: 1.4; damping: .15 }
}
There are several advantages of the behaviour approach:
1. the property value is written as declarative binding, the behavior comes
simply in addition to that. The logic of the code does not change.
2. when you disable the behaviour object, the animation goes away, but the
property still changes value. When you disable a follow object, the value does
not change anymore. This is where people hack with duration:0 or by setting
both the to-property of the follow object *and* the property (see same game)
I looked at the example which used follows and found they could all be written
nicer with behaviours. Attached is a patch for the clocks toy and for the same
game (which still lacks SpringAnimation).
There's one small corner case where the follow-approach had an advantage,
although we haven't found a true use case yet which didn't have a different
solution: follow makes it possible to apply a different initial value to the
property and to the follow's to-property, thus it can give you an initial
startup animation.
This has been used in the clocks example, where my patch shows, that you can
solve it differently. The behaviour version initially animates from the
initial values of the hours/minutes/seconds properties to the current time.
In the general case, where you do not have a timer, you can solve this the
following way:
1. declare the property value where the animation should start
2. change it to whatever you like in a Component.onCompleted-handler.
Example:
Item {
property int prop: <pre_initial_value>
Behaviour on prop{ <funky animation> }
Component.onCompleted: prop = <initial_value>
}
Alternatively, and probably nicer, you can declare the initial value in a
different state "Initial" and simply do
Component.onCompleted: state = "Initial"
To me the onCompleted-approach is appropriate, given that the usecase seems
rather esoteric.
Main advantage for the follow-removal: no more asymetric API, simpler API,
more exposure to the great and flexible Behavior.
Matthias
diff --git a/examples/declarative/toys/clocks/content/Clock.qml b/examples/declarative/toys/clocks/content/Clock.qml
index 136573b..24a07ec 100644
--- a/examples/declarative/toys/clocks/content/Clock.qml
+++ b/examples/declarative/toys/clocks/content/Clock.qml
@@ -45,10 +45,10 @@ Item {
width: 200; height: 230
property alias city: cityLabel.text
- property variant hours
- property variant minutes
- property variant seconds
- property variant shift : 0
+ property int hours
+ property int minutes
+ property int seconds
+ property real shift
property bool night: false
function timeChanged() {
@@ -60,23 +60,24 @@ Item {
}
Timer {
- interval: 100; running: true; repeat: true; triggeredOnStart: true
+ interval: 100; running: true; repeat: true;
onTriggered: clock.timeChanged()
}
Image { id: background; source: "clock.png"; visible: clock.night == false }
Image { source: "clock-night.png"; visible: clock.night == true }
+
Image {
x: 92.5; y: 27
source: "hour.png"
smooth: true
transform: Rotation {
id: hourRotation
- origin.x: 7.5; origin.y: 73; angle: 0
- SpringFollow on angle {
- spring: 2; damping: 0.2; modulus: 360
- to: (clock.hours * 30) + (clock.minutes * 0.5)
+ origin.x: 7.5; origin.y: 73;
+ angle: (clock.hours * 30) + (clock.minutes * 0.5)
+ Behavior on angle {
+ NumberAnimation{}
}
}
}
@@ -87,10 +88,10 @@ Item {
smooth: true
transform: Rotation {
id: minuteRotation
- origin.x: 6.5; origin.y: 83; angle: 0
- SpringFollow on angle {
- spring: 2; damping: 0.2; modulus: 360
- to: clock.minutes * 6
+ origin.x: 6.5; origin.y: 83;
+ angle: clock.minutes * 6
+ Behavior on angle {
+ NumberAnimation{}
}
}
}
@@ -101,10 +102,10 @@ Item {
smooth: true
transform: Rotation {
id: secondRotation
- origin.x: 2.5; origin.y: 80; angle: 0
- SpringFollow on angle {
- spring: 5; damping: 0.25; modulus: 360
- to: clock.seconds * 6
+ origin.x: 2.5; origin.y: 80;
+ angle: clock.seconds * 6
+ Behavior on angle {
+ NumberAnimation{}
}
}
}
diff --git a/demos/declarative/samegame/SamegameCore/BoomBlock.qml b/demos/declarative/samegame/SamegameCore/BoomBlock.qml
index 3f43579..ab872f5 100644
--- a/demos/declarative/samegame/SamegameCore/BoomBlock.qml
+++ b/demos/declarative/samegame/SamegameCore/BoomBlock.qml
@@ -47,11 +47,20 @@ Item {
property bool dying: false
property bool spawned: false
property int type: 0
- property int targetX: 0
- property int targetY: 0
+ property int row: 0
+ property int column: 0
- SpringFollow on x { enabled: spawned; to: targetX; spring: 2; damping: 0.2 }
- SpringFollow on y { to: targetY; spring: 2; damping: 0.2 }
+ x: column * gameCanvas.blockSize
+
+ Behavior on x {
+ enabled: spawned;
+ NumberAnimation{}
+ }
+
+ y: row * gameCanvas.blockSize
+ Behavior on y {
+ NumberAnimation{}
+ }
Image {
id: img
diff --git a/demos/declarative/samegame/SamegameCore/samegame.js b/demos/declarative/samegame/SamegameCore/samegame.js
index 5c008a2..44eb3ac 100755
--- a/demos/declarative/samegame/SamegameCore/samegame.js
+++ b/demos/declarative/samegame/SamegameCore/samegame.js
@@ -110,7 +110,7 @@ function shuffleDown()
}else{
if(fallDist > 0){
var obj = board[index(column,row)];
- obj.targetY += fallDist * gameCanvas.blockSize;
+ obj.row += fallDist;
board[index(column,row+fallDist)] = obj;
board[index(column,row)] = null;
}
@@ -128,7 +128,7 @@ function shuffleDown()
obj = board[index(column,row)];
if(obj == null)
continue;
- obj.targetX -= fallDist * gameCanvas.blockSize;
+ obj.column -= fallDist;
board[index(column-fallDist,row)] = obj;
board[index(column,row)] = null;
}
@@ -183,9 +183,8 @@ function createBlock(column,row){
return false;
}
dynamicObject.type = Math.floor(Math.random() * 3);
- dynamicObject.x = column*gameCanvas.blockSize;
- dynamicObject.targetX = column*gameCanvas.blockSize;
- dynamicObject.targetY = row*gameCanvas.blockSize;
+ dynamicObject.column = column;
+ dynamicObject.row = row;
dynamicObject.width = gameCanvas.blockSize;
dynamicObject.height = gameCanvas.blockSize;
dynamicObject.spawned = true;
_______________________________________________
Qt-qml mailing list
[email protected]
http://lists.trolltech.com/mailman/listinfo/qt-qml