Titanium JIRA Archive
Titanium SDK/CLI (TIMOB)

[TIMOB-15951] Android: Animating a child view in vertical layout no longer works correctly

GitHub Issuen/a
TypeBug
PriorityCritical
StatusClosed
ResolutionFixed
Resolution Date2014-01-22T00:19:53.000+0000
Affected Version/sn/a
Fix Version/s2013 Sprint 26, 2013 Sprint 26 API, 2014 Sprint 01, 2014 Sprint 01 API, Release 3.2.3, Release 3.3.0
ComponentsAndroid
Labels3.2.0, Alloy, android, animation, module_animation, qe-closed-3.2.3, qe-testadded, regression, triage
ReporterJohn Liddell
AssigneePing Wang
Created2013-12-05T22:34:50.000+0000
Updated2014-03-21T03:44:21.000+0000

Description

Animating a child view contained in a view with a vertical layout no longer adjusts the other children as it used to. Now the views just stay stationary while the animation happens. the following snippet shows the issue, the second square should be moving up and down to compensate for the animation but it doesn't now.

Sample Code:

*index.xml*
<Alloy>
	<Window class="container">
	</Window>
</Alloy>
*index.js*
var bBig = false;

var btn = Ti.UI.createButton( {
	width : '90%',
	height : '40dp',
	title : 'Start Test',
	top: 0
} );

var parent = Ti.UI.createView({
	height: 100,
	width: 100,
	layout: 'vertical'
});

var v1 = Ti.UI.createView({
	height: 50,
	width: 50,
	top: 5,
	backgroundColor: 'red'
});

var v2 = Ti.UI.createView({
	height: 50,
	width: 50,
	top: 20,
	backgroundColor: 'blue'
});

btn.addEventListener( 'click', function( e ) {
	if( !bBig ){
		bBig = true;
		v1.animate( Ti.UI.createAnimation({
			height:100,
			duration: 300
		}));
	} else {
		bBig = false;
		v1.animate( Ti.UI.createAnimation({
			height:50,
			duration: 300
		}));
	}
} );
$.index.add( btn );
$.index.add( parent );

parent.add( v1 );
parent.add( v2 );

$.index.open();

Steps to reproduce:

1. Create a new alloy project with the above code 2. Run the app on an Android device, building with TiSDK 3.2.0 3. Click the "Start Test" button 4. Notice that the red box moves down and overlaps the blue box

Comments

  1. Eric Wieber 2013-12-11

    I was able to reproduce this issue. In 3.2.0, when the "Start Test" button is clicked the red box moves down and overlaps the blue box. In 3.1.2, when the "Start Test" button is clicked the red box moves down and the blue box shrinks out of the way. The blue box does not animate properly in SDK 3.2.0.
  2. Ping Wang 2013-12-11

    Test case
       var win = Ti.UI.createWindow({
       	backgroundColor: "white"
       });
       
       var bBig = false;
        
       var btn = Ti.UI.createButton( {
           width : '90%',
           height : '40dp',
           title : 'Start Test',
           top: 0
       } );
        
       var parent = Ti.UI.createView({
           height: 100,
           width: 100,
           layout: 'vertical'
       });
        
       var v1 = Ti.UI.createView({
           height: 30,
           width: 50,
           top: 5,
           backgroundColor: 'red'
       });
        
       var v2 = Ti.UI.createView({
           height: 50,
           width: 50,
           top: 20,
           backgroundColor: 'blue'
       });
        
       btn.addEventListener( 'click', function( e ) {
           if( !bBig ){
               bBig = true;
               v1.animate( Ti.UI.createAnimation({
                   height:70,
                   duration: 300
               }));
           } else {
               bBig = false;
               v1.animate( Ti.UI.createAnimation({
                   height:30,
                   duration: 300
               }));
           }
       } );
       win.add( btn );
       win.add( parent );
        
       parent.add( v1 );
       parent.add( v2 );
        
       win.open();
       
  3. Ping Wang 2013-12-11

    In 3.2.0 (TIMOB-11811), we start to use the new animation mechanism - [Property Animation](http://android-developers.blogspot.com/2011/02/animation-in-honeycomb.html). The size/location animation inside a vertical/horizontal layout is broken under the property animation mechanism right now. Here is a temporary workaround for the above test case:
       var win = Ti.UI.createWindow({
       	backgroundColor : "white"
       });
       
       var bBig = false;
       
       var btn = Ti.UI.createButton({
       	width : '90%',
       	height : '40dp',
       	title : 'Start Test',
       	top : 0
       });
       
       var parent = Ti.UI.createView({
       	height : 100,
       	width : 100,
       	layout : 'vertical'
       });
       
       var v1 = Ti.UI.createView({
       	height : 30,
       	width : 50,
       	top : 5,
       	backgroundColor : 'red'
       });
       
       var v2 = Ti.UI.createView({
       	height : 50,
       	width : 50,
       	top : 20, // This value is relative to the red view since it's in a vertical layout.
       	backgroundColor : 'blue'
       });
       
       btn.addEventListener('click', function(e) {
       	if (!bBig) {
       		bBig = true;
       		var animation1 = Ti.UI.createAnimation({
       			height : 70,
       			duration : 300
       		});
       		v1.animate(animation1);
       
       		// Since the vertical layout is not taken into account during the animation,
       		// we need to animate the blue view manually here. The view position "top"
       		// has to be relative to its parent.
       		var animation2 = Ti.UI.createAnimation({
       			top : 95,
       			duration : 300
       		});
       		v2.animate(animation2);
       
       		// For Android API level < 11, the final position "top" of the blue view
       		// should be relative to the red view.
       		if (Ti.Platform.Android.API_LEVEL < 11) {
       			animation2.addEventListener("complete", function() {
       				v2.top = 20;
       			});
       		}
       	} else {
       		bBig = false;
       		var animation1 = Ti.UI.createAnimation({
       			height : 30,
       			duration : 300
       		});
       		v1.animate(animation1);
       
       		var animation2 = Ti.UI.createAnimation({
       			top : 55,
       			duration : 300
       		});
       		v2.animate(animation2);
       
       		if (Ti.Platform.Android.API_LEVEL < 11) {
       			animation2.addEventListener("complete", function() {
       				v2.top = 20;
       			});
       		}
       	}
       });
       win.add(btn);
       win.add(parent);
       
       parent.add(v1);
       parent.add(v2);
       
       win.open();
       
  4. Hieu Pham 2013-12-13

    Extended test case:
       var tests = {};
       var win = Ti.UI.createWindow({
           backgroundColor : 'white'
       });
       var section = Ti.UI.createListSection({
           headerTitle : 'Animation Test'
       });
       section.setItems([{
           properties : {
               title : 'Vertical Layout',
               itemId : 'vertical',
               font : {
                   fontSize : 20
               }
           }
       }, {
           properties : {
               title : 'Horizontal Layout',
               itemId : 'horizontal',
               font : {
                   fontSize : 20
               }
           }
       }]);
       var listView = Ti.UI.createListView({
           backgroundColor : "white",
           sections : [section]
       });
        
       listView.addEventListener('itemclick', function(e) {
           var f = tests[e.itemId];
           if (f)
               f();
       });
        
       win.add(listView);
        
       tests.vertical = function() {
           var win = Ti.UI.createWindow({
               fullscreen : false,
               backgroundColor : 'white',
               title : 'Vertical Tests'
           });
           var bScale = false;
           var bTrans = false;
           var bST = false;
        
        
           var btn = Ti.UI.createButton({
               width : '90%',
               height : '40dp',
               title : 'Scale Test',
               top : 0
           });
            
           var btn2 = Ti.UI.createButton({
               width : '90%',
               height : '40dp',
               title : 'Translation Test',
               top : '50dp'
           });
            
           var btn3 = Ti.UI.createButton({
               width : '90%',
               height : '40dp',
               title : 'Scaling + Translation Test',
               top : '90dp'
           });
        
           var parent = Ti.UI.createView({
               height : 100,
               width : 100,
               backgroundColor: 'yellow',
               layout : 'vertical'
           });
        
           var v1 = Ti.UI.createView({
               height : 50,
               width : 50,
               top : 5,
               backgroundColor : 'red'
           });
        
           var v2 = Ti.UI.createView({
               height : 50,
               width : 50,
               top : 20,
               backgroundColor : 'blue'
           });
        
           btn.addEventListener('click', function(e) {
               if (!bScale) {
                   bScale = true;
                   v1.animate(Ti.UI.createAnimation({
                       height : 100,
                       duration : 300
                   }));
               } else {
                   bScale = false;
                   v1.animate(Ti.UI.createAnimation({
                       height : 50,
                       duration : 300
                   }));
               }
           });
            
           btn2.addEventListener('click', function(e) {
               if (!bTrans) {
                   bTrans = true;
                   v1.animate(Ti.UI.createAnimation({
                       top : 50,
                       duration : 300
                   }));
               } else {
                   bTrans = false;
                   v1.animate(Ti.UI.createAnimation({
                       top : 5,
                       duration : 300
                   }));
               }
           });
            
           btn3.addEventListener('click', function(e) {
               if (!bST) {
                   bST = true;
                   v1.animate(Ti.UI.createAnimation({
                       height : 100,
                       top: 50,
                       duration : 300
                   }));
               } else {
                   bST = false;
                   v1.animate(Ti.UI.createAnimation({
                       height : 50,
                       top: 5,
                       duration : 300
                   }));
               }
           });
           win.add(btn);
           win.add(btn2);
           win.add(btn3);
           win.add(parent);
        
           parent.add(v1);
           parent.add(v2);
        
           win.open();
       };
        
       tests.horizontal = function() {
           var win = Ti.UI.createWindow({
               fullscreen : false,
               backgroundColor : 'white',
               title : 'Horizontal Tests'
           });
           var bScale = false;
           var bTrans = false;
           var bST = false;
        
        
           var btn = Ti.UI.createButton({
               width : '90%',
               height : '40dp',
               title : 'Scale Test',
               top : 0
           });
            
           var btn2 = Ti.UI.createButton({
               width : '90%',
               height : '40dp',
               title : 'Translation Test',
               top : '50dp'
           });
            
           var btn3 = Ti.UI.createButton({
               width : '90%',
               height : '40dp',
               title : 'Scaling + Translation Test',
               top : '90dp'
           });
        
           var parent = Ti.UI.createView({
               height : 100,
               width : 140,
               backgroundColor: 'yellow',
               layout : 'horizontal'
           });
        
           var v1 = Ti.UI.createView({
               height : 50,
               width : 50,
               left : 5,
               backgroundColor : 'red'
           });
        
           var v2 = Ti.UI.createView({
               height : 50,
               width : 50,
               left : 20,
               backgroundColor : 'blue'
           });
        
           btn.addEventListener('click', function(e) {
               if (!bScale) {
                   bScale = true;
                   v1.animate(Ti.UI.createAnimation({
                       width : 100,
                       duration : 300
                   }));
               } else {
                   bScale = false;
                   v1.animate(Ti.UI.createAnimation({
                       width : 50,
                       duration : 300
                   }));
               }
           });
            
           btn2.addEventListener('click', function(e) {
               if (!bTrans) {
                   bTrans = true;
                   v1.animate(Ti.UI.createAnimation({
                       left : 30,
                       duration : 300
                   }));
               } else {
                   bTrans = false;
                   v1.animate(Ti.UI.createAnimation({
                       left : 5,
                       duration : 300
                   }));
               }
           });
            
           btn3.addEventListener('click', function(e) {
               if (!bST) {
                   bST = true;
                   v1.animate(Ti.UI.createAnimation({
                       width : 100,
                       left: 30,
                       duration : 300
                   }));
               } else {
                   bST = false;
                   v1.animate(Ti.UI.createAnimation({
                       width : 50,
                       left: 5,
                       duration : 300
                   }));
               }
           });
           win.add(btn);
           win.add(btn2);
           win.add(btn3);
           win.add(parent);
        
           parent.add(v1);
           parent.add(v2);
        
           win.open();
        
       };
        
       win.open(); 
       
  5. Ping Wang 2013-12-16

    PR: https://github.com/appcelerator/titanium_mobile/pull/5128 For FR: 1. Run the above test case in Hieu's comment and the test case below on 2.3, 3.x and 4.x devices.
       var win = Ti.UI.createWindow({
       	backgroundColor: "white"
       });
       
       var bBig = false;
        
       var btn1 = Ti.UI.createButton( {
           width : '90%',
           height : '40dp',
           title : 'Scaling Test - vertical layout',
           top: 0
       } );
       
       var btn1_2 = Ti.UI.createButton( {
           width : '90%',
           height : '40dp',
           title : 'Translation Test - vertical layout',
           top: '40dp'
       } );
        
       var parent1 = Ti.UI.createView({
       	top: '250dp',
       	left: 0,
           height: 100,
           width: 100,
           backgroundColor: 'yellow',
           layout: 'vertical'
       });
        
       var v1 = Ti.UI.createView({
           height: 30,
           width: 50,
           top: 5,
           backgroundColor: 'red'
       });
       
       var v1_1 = Ti.UI.createView({
           height: '50%',
           width: '50%',
           backgroundColor: 'green'
       });
       v1.add(v1_1);
        
       var v2 = Ti.UI.createView({
           height: 50,
           width: 50,
           top: 20,
           backgroundColor: 'blue'
       });
        
       btn1.addEventListener( 'click', function( e ) {
           if( !bBig ){
               bBig = true;
               var animation1 = Ti.UI.createAnimation({
                   height:70,
                   width: 80,
                   duration: 300
               });
               v1.animate(animation1);
           } else {
               bBig = false;
               var animation1 = Ti.UI.createAnimation({
                   height:30,
                   width: 50,
                   duration: 300
               });
               v1.animate(animation1);
           }
       } );
       
       var bBig_2 = false;
       btn1_2.addEventListener( 'click', function( e ) {
           if( !bBig_2 ){
               bBig_2 = true;
               var animation1 = Ti.UI.createAnimation({
                   top: 40,
                   duration: 300
               });
               v1.animate(animation1);
           } else {
               bBig_2 = false;
               var animation1 = Ti.UI.createAnimation({
                   top: 5,
                   duration: 300
               });
               v1.animate(animation1);
           }
       } );
       
       
       win.add( btn1 );
       win.add( btn1_2 );
       win.add( parent1 );
        
       parent1.add( v1 );
       parent1.add( v2 );
       
       //******************************************************
       var bBig1 = false;
       
       var btn2 = Ti.UI.createButton( {
           width : '90%',
           height : '40dp',
           title : 'Scaling Test - horizontal layout',
           top: '80dp',
       } );
       
       var btn2_2 = Ti.UI.createButton( {
           width : '90%',
           height : '40dp',
           title : 'Translation Test - horizontal layout',
           top: '120dp',
       } );
        
       var parent2 = Ti.UI.createView({
       	top: '250dp',
       	left: 105,
           height: 100,
           width: 120,
           backgroundColor: 'yellow',
           layout: 'horizontal'
       });
        
       var v3 = Ti.UI.createView({
           height: 50,
           width: 30,
           left: 5,
           backgroundColor: 'red'
       });
       
       var v3_1 = Ti.UI.createView({
           height: '50%',
           width: '50%',
           backgroundColor: 'green'
       });
       v3.add(v3_1);
        
       var v4 = Ti.UI.createView({
           height: 50,
           width: 50,
           left: 20,
           backgroundColor: 'blue'
       });
        
       btn2.addEventListener( 'click', function( e ) {
           if( !bBig1 ){
               bBig1 = true;
               var animation3 = Ti.UI.createAnimation({
                   width:70,
                   height: 70,
                   duration: 300
               });
               v3.animate(animation3);
           } else {
               bBig1 = false;
               var animation3 = Ti.UI.createAnimation({
                   width:30,
                   height: 50,
                   duration: 300
               });
               v3.animate(animation3);
           }
       } );
       
       var bBig1_2 = false;
       btn2_2.addEventListener( 'click', function( e ) {
           if( !bBig1_2 ){
               bBig1_2 = true;
               var animation3 = Ti.UI.createAnimation({
                   left: 40,
                   duration: 300
               });
               v3.animate(animation3);
           } else {
               bBig1_2 = false;
               var animation3 = Ti.UI.createAnimation({
                   left: 5,
                   duration: 300
               });
               v3.animate(animation3);
           }
       } );
       
       win.add( btn2 );
       win.add( btn2_2 );
       win.add( parent2 );
        
       parent2.add( v3 );
       parent2.add( v4 );
       
       //******************************************************
       var bBig2 = false;
       
       var btn3 = Ti.UI.createButton( {
           width : '90%',
           height : '40dp',
           title : 'Scaling Test - composite layout',
           top: '160dp',
       } );
       
       var btn3_2 = Ti.UI.createButton( {
           width : '90%',
           height : '40dp',
           title : 'Translation Test - composite layout',
           top: '200dp',
       } );
        
       var parent3 = Ti.UI.createView({
       	top: '250dp',
       	left: 230,
           height: 100,
           width: 120,
           backgroundColor: 'yellow'
       });
        
       var v5 = Ti.UI.createView({
           height: 50,
           width: 50,
           left: 5,
           backgroundColor: 'red'
       });
       
       var v5_1 = Ti.UI.createView({
           height: '50%',
           width: '50%',
           backgroundColor: 'green'
       });
       v5.add(v5_1);
        
       var v6 = Ti.UI.createView({
           height: 50,
           width: 50,
           left: 60,
           backgroundColor: 'blue'
       });
        
       btn3.addEventListener( 'click', function( e ) {
           if( !bBig2 ){
               bBig2 = true;
               var animation5 = Ti.UI.createAnimation({
                   width: 80,
                   height: 80,
                   duration: 300
               });
               v5.animate(animation5);
           } else {
               bBig2 = false;
               var animation5 = Ti.UI.createAnimation({
                   width: 50,
                   height: 50,
                   duration: 300
               });
               v5.animate(animation5);
           }
       } );
       
       var bBig2_2 = false;
       btn3_2.addEventListener( 'click', function( e ) {
           if( !bBig2_2 ){
               bBig2_2 = true;
               var animation5 = Ti.UI.createAnimation({
                   left: 50,
                   duration: 300
               });
               v5.animate(animation5);
           } else {
               bBig2_2 = false;
               var animation5 = Ti.UI.createAnimation({
                   left: 5,
                   duration: 300
               });
               v5.animate(animation5);
           }
       } );
       
       win.add( btn3 );
       win.add( btn3_2 );
       win.add( parent3 );
        
       parent3.add( v5 );
       parent3.add( v6 );
        
       win.open();
       
    2. Run KS for a sanity check. 3. Run Anvil. Should be 429 passed / 42 failed.
  6. Ping Wang 2014-01-13

    Re-open the ticket since found an issue regarding the 2DMatrix animation introduced by the above PR. To reproduce the issue, run the code below. The view is scaled but the anchor point is not the center of the view.
       var win = Ti.UI.createWindow({
           backgroundColor: "white"
       });
       
       var matrix1 = Ti.UI.create2DMatrix({
       	scale: 2
       });
       
       
       var matrix2 = Ti.UI.create2DMatrix({
       	scale: 0.5
       });
       
        
       var bBig = false;
         
       var btn1 = Ti.UI.createButton( {
           width : '90%',
           height : '40dp',
           title : 'Scaling Test - vertical layout',
           top: 0
       } );
       
       var parent1 = Ti.UI.createView({
           top: '250dp',
           left: 0,
           height: 100,
           width: 100,
           backgroundColor: 'yellow',
           layout: 'vertical'
       });
         
       var v1 = Ti.UI.createView({
           height: 30,
           width: 50,
           top: 5,
           backgroundColor: 'red'
       });
         
       var v2 = Ti.UI.createView({
           height: 50,
           width: 50,
           top: 20,
           backgroundColor: 'blue'
       });
         
       btn1.addEventListener( 'click', function( e ) {
           if( !bBig ){
               bBig = true;
               var animation1 = Ti.UI.createAnimation({
                   transform: matrix1,
                   duration: 300
               });
               v1.animate(animation1);
           } else {
               bBig = false;
               var animation1 = Ti.UI.createAnimation({
                   transform: matrix2,
                   duration: 300
               });
               v1.animate(animation1);
           }
       } );
        
        
       win.add( btn1 );
       win.add( parent1 );
         
       parent1.add( v1 );
       parent1.add( v2 );
       
       win.open();
       
  7. Ping Wang 2014-01-16

    PR: https://github.com/appcelerator/titanium_mobile/pull/5226 (in this PR I reverted the previous [PR#5128](https://github.com/appcelerator/titanium_mobile/pull/5128)). 3_2_X PR: https://github.com/appcelerator/titanium_mobile/pull/5245 For FR, please follow the testing steps in TIMOB-15951, TIMOB-16087, TIMOB-15719, TIMOB-2373, TIMOB-13536.
  8. Priya Agarwal 2014-03-20

    Verified with: Appc Studio:3.2.3.201403190645 Sdk:3.2.3.v20140319174101 alloy:1.3.1 titanium:3.2.1 titanium-code-processor:1.1.0 Osx: Maverick(10.9.2) Device:iPad(v6.1.3),LG-970(V4.0.4) xCode:5.1 Followed the last test Code. Verified animations works fine. Hence closing the issue.

JSON Source