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

Reply via email to