PDA

View Full Version : Getting Carousel to Redraw on Orientation Change



dankhan
7 Oct 2010, 12:20 AM
Hi,

I'm trying to get the iphone simulator (thru phonegap) to show a simple carousel with a few cards. I've setup to monitor the orientation change using the windowresize functionas suggested in other threads since phonegap doesn't seem to fire the native orientationchanged event.

Anyway, display rotates fine, but the carousel and cards are not relaid out. I've set this carousel to fullscreen so would thought it would automatically pick up changes in orientation and redraw.

Also then tried to specifically trap the window size changing and fire off a setOrientation event - this seems be getting warmer now as I can see the carousel orientationchanged function being fired. But nothing is rendered to screen. I tried putting liveral sprinkings of carousel.doLayout() calls a various places, but can't figure out what I need to do to get the carousel to redraw (I thought this would be taken care of with the setOrientation function). Anyway, here's my code:




// Setup some globals so we can access from callbacks
var carousel;

function onBodyLoad()
{
document.addEventListener("deviceready",onDeviceReady,false);
}

/* When this function is called, PhoneGap has been initialized and is ready to roll */
function onDeviceReady()
{
Ext.setup({
tabletStartupScreen: 'tablet_startup.png',
phoneStartupScreen: 'phone_startup.png',
icon: 'icon.png',
glossOnIcon: false,
onReady: function() {

// cut down to simplify the post...
var cardContents = [
'<h1>card1</h1>',
'<h1>card2</h1>'
];

// Create an empty carousel - we programatically add each item next
carousel = new Ext.Carousel({
fullscreen: true
});

// Setup the card containers
var cardCntS = '<div class="card"><div class="cardbg">';
var cardCntE = '</div></div>';

// Create all of the cards with nested subpanels to allow proper styling - we embed each card in a subpanel since theres a margin bug on carousel items not sizing cards correctly if they have a margin
for (var i=0; i<cardContents.length; i++)
{
var card = new Ext.Panel({
id: 'card'+i,
cls: 'cardcnt',
html: cardCntS + cardContents[i] + cardCntE
});

// We now add this card to the carousel
carousel.add(card);
}
carousel.doLayout();

// Setup a callback to monitor changes in orientation
Ext.EventManager.onWindowResize(updateOrientation);

carousel.on('orientationchange', function(e, o, w, h) {
debug.log('Callback: '+o+' '+w+' '+h);
//carousel.doLayout();
});
}
});
}

function updateOrientation() {
debug.log("Orientation changed to: " + Ext.getOrientation());

debug.log(Ext.getOrientation()+' '+window.innerWidth+' '+window.innerHeight);
carousel.setOrientation(Ext.getOrientation(),window.innerWidth,window.innerHeight);
//carousel.doLayout();
}


and here's my debug log:



2010-10-07 21:16:06.566 App[7298:207] [INFO] Orientation changed to: landscape
2010-10-07 21:16:06.576 App[7298:207] [INFO] landscape 480 300
2010-10-07 21:16:06.587 App[7298:207] [INFO] Orientation changed to: landscape
2010-10-07 21:16:06.618 App[7298:207] [INFO] landscape 480 300
2010-10-07 21:16:06.628 App[7298:207] [INFO] Callback: landscape 480 300
2010-10-07 21:16:06.685 App[7298:207] [INFO] Callback: landscape 480 300


Any ideas why my carousel isn't being rendered on rotate? It gets rendered (just not resized) if I omit the setOrientation call.

Also, wonder why is windowResize() getting called twice? Once for x and once for y?

Thanks for any help.

Cheers,
-Dan

evant
7 Oct 2010, 12:32 AM
Any full screen component monitors the orientation and will re-lay out when the orientation changes, you don't need to do it manually.

dankhan
7 Oct 2010, 12:45 AM
That's what I thought, but I get very intermittent results and mostly no redraw when using the above code and changing orientation. If I don't listen explicitly listen for the event as above, then no re-layout occurs - e.g. page width is still at portrait width, and carousel navigation is off bottom of device screen. I've have seen posts on the forum that says phonegap doesn't pick up this event correctly which is why I was manually firing windowresize as suggested in those threads. Is this refire likely to be causing the carousel to just show the blank screen?

Thanks for your help and quick reply to my question!

dankhan
7 Oct 2010, 12:48 PM
Well done some more testing, and i don't know if this is a problem with the carousel component specifically, or just under phonegap maybe.

I added a listener in Ext.Setup to check for orientationChanged and callback to my function, which did 2 simple things:



carousel.getActiveItem().update("Orientation changed to: " + e.orientation + '<br />Ext orient: ' + Ext.getOrientation() + '<br />My orient: ' + orient);
carousel.setOrientation(orient,w,h);


The results of this are interesting on the iphone sim - effectively the results are backwards, almost as if the orientationChanged function is getting called with the current height/width and orientation *before* the rotation. Thus rotating to landscape, Ext.getOrientation() returns 'portrait', and calls to window.innerHeight and innerWidth return the portrait sizes.

A quick fix (although obviously not cross-phone/ipad supported yet) is to do the following which works perfectly:



function updateOrientation(e) {

var orient = 'portrait', w = 320, h = 460;
switch(e.orientation)
{
case 90:
case -90:
{
orient = 'landscape';
w = 480;
h = 300;
}
}

carousel.getActiveItem().update("Orientation changed to: " + e.orientation + '<br />Ext orient: ' + Ext.getOrientation() + '<br />My orient: ' + orient);
carousel.setOrientation(orient,w,h);
}


Odd one, anyone seen this behaviour, and is it just specific to carousel component through phonegap?

evant
7 Oct 2010, 2:57 PM
I can't say I've seen this. On my iPad changing the orientation on any fullscreen component forces a layout. If you have a look inside the code you can verify it.

m7o
18 Oct 2010, 11:34 PM
I have the same problem, and only with Phonegap. As a web app all redraws fine, as native with Phonegap it does as described: change orientation, but stays aligned left, not stretching over the whole width, and the lower disappears because the height stays the same as in portrait mode.

evant
18 Oct 2010, 11:36 PM
Right, but does it happen on a native device? If so, it might indicate the problem lies with PhoneGap.

m7o
18 Oct 2010, 11:44 PM
Yes, it happens on the iPhone as well as the simulator. Thanks a lot for the quick reply!
I will have a look in the Phonegap forums.

dankhan
18 Oct 2010, 11:48 PM
Yeh, I notice as well that when coming back to reactivate the app after leaving without closing, sometimes the orientation is wrong if you've changed the orientation since you were in the app. I suspect you could modify the ObjC code in Phonegap to fire off an extra orientation check when the app is reactivated to fix this one, but yes, likely a question for the phonegap forums.

m7o
19 Oct 2010, 12:27 AM
Thanks to oxynel (http://www.sencha.com/forum/newreply.php?do=postreply&t=111798) I got closer to my solution. The following will make the change correctly once ;-) The next orientation changes don't seem to fire the function.
What I did:
- put the Ext.Panel into a the variable panel.
- added the function that fires on Ext.EventManager.onWindowResize.

I used the sencha carousel example, obviously.

I keep on looking to make this work everytime, not just once. Maybe you have a suggestion, too.



Ext.setup({
tabletStartupScreen: 'tablet_startup.png',
phoneStartupScreen: 'phone_startup.png',
icon: 'icon.png',
glossOnIcon: false,
onReady: function() {
// Create a Carousel of Items
var carousel1 = new Ext.Carousel({
defaults: {
cls: 'card'
},
items: [{
html: '<h1>Carousel</h1><p>Navigate the two carousels on this page by swiping left/right or clicking on one side of the circle indicators below.</p>'
},
{
title: 'Tab 2',
html: '2'
},
{
title: 'Tab 3',
html: '3'
}]
});

panel = new Ext.Panel({
fullscreen: true,
layout: {
type: 'fit'
},
defaults: {
flex: 1
},
items: [carousel1]
});

Ext.EventManager.onWindowResize(
function(){
panel.setOrientation( Ext.getOrientation() , window.innerWidth , window.innerHeight )
}
);


}
});

m7o
19 Oct 2010, 12:29 AM
I wanted to link to oxynel, but the forum made something different out of the link... here is the URL
http://bit.ly/9kcuS9

sandor
19 Oct 2010, 4:09 AM
A possible intermediate solution for this problem COULD be to use the @media in the HTML-page (since this seems to working well) and pass this back to the index.js (if that is possible). Maybe one of you guys with solid JS knowledge could give that a try (i am just the marketing guy here - LOL...)

Cheers,

Sandor

ed.canas
1 Nov 2010, 4:03 PM
It seems like the orientation event stops firing after setting to landscape and using the following size
this.ui.setSize(480 , 300) or the command this.ui.setOrientation( Ext.getOrientation() , window.innerWidth , window.innerHeight );

But if you replace 480 or Ext.getOrientation() by 479 the orientation event will keep firing and changing, but of course there is a bit left space on the side. Does anybody have any ideas as to why the event will stop firing after setting the size to 480?
Again this only happens when using phonegap or when the application is deployed locally with any other tool.

I modify the code to the following to test if I comment and change it back to 480 it will stop working.



Ext.EventManager.onWindowResize(
function(){
if(Ext.getOrientation()=="landscape") {
//this.ui.setSize(480 , 300);
this.ui.setSize(479 , 300);
this.ui.doLayout();
//this.ui.setOrientation( 'landscape' , 480 , 300 );
}
else {
this.ui.setSize(320 , 460);
this.ui.doLayout();
//this.ui.setOrientation( 'portrait' , 300 , 480 );
}
}
);




Thanks to oxynel (http://www.sencha.com/forum/newreply.php?do=postreply&t=111798) I got closer to my solution. The following will make the change correctly once ;-) The next orientation changes don't seem to fire the function.
What I did:
- put the Ext.Panel into a the variable panel.
- added the function that fires on Ext.EventManager.onWindowResize.

I used the sencha carousel example, obviously.

I keep on looking to make this work everytime, not just once. Maybe you have a suggestion, too.



Ext.setup({
tabletStartupScreen: 'tablet_startup.png',
phoneStartupScreen: 'phone_startup.png',
icon: 'icon.png',
glossOnIcon: false,
onReady: function() {
// Create a Carousel of Items
var carousel1 = new Ext.Carousel({
defaults: {
cls: 'card'
},
items: [{
html: '<h1>Carousel</h1><p>Navigate the two carousels on this page by swiping left/right or clicking on one side of the circle indicators below.</p>'
},
{
title: 'Tab 2',
html: '2'
},
{
title: 'Tab 3',
html: '3'
}]
});

panel = new Ext.Panel({
fullscreen: true,
layout: {
type: 'fit'
},
defaults: {
flex: 1
},
items: [carousel1]
});

Ext.EventManager.onWindowResize(
function(){
panel.setOrientation( Ext.getOrientation() , window.innerWidth , window.innerHeight )
}
);


}
});

m7o
2 Nov 2010, 12:43 AM
It seems to me that the event 'orientationchange' does not fire in Phonegap, have you had the same experience?
I tried many things with test callback functions, f.e.


Ext.EventManager.on(window, 'orientationchange', testfunction);

function testfunction(e, t){
alert(1);
}

with no result.

And the onWindowResize does only seem to fire once (without the hack from ed.canas).

Could someone at Sencha please look into this as well, please? After all, Sencha is supposed to work with Phonegap, and you are the experts... I am sure you will see something that we don't.

oonox
2 Nov 2010, 5:07 AM
Hi M7O,

orientationchange event are not fire when you use phonegap via the uiwebcomponent of xcode. onWindowResize catch event. out the function of your setup and place the resize on the right place.

Best regard and thank for your sharing link to Oxynel.



Ext.setup({
tabletStartupScreen: 'tablet_startup.png',
phoneStartupScreen: 'phone_startup.png',
icon: 'icon.png',
glossOnIcon: false,
onReady: function() {
// Create a Carousel of Items
var carousel1 = new Ext.Carousel({
defaults: {
cls: 'card'
},
items: [{
html: '<h1>Carousel</h1><p>Navigate the two carousels on this page by swiping left/right or clicking on one side of the circle indicators below.</p>'
},
{
title: 'Tab 2',
html: '2'
},
{
title: 'Tab 3',
html: '3'
}]
});

panel = new Ext.Panel({
fullscreen: true,
layout: {
type: 'fit'
},
defaults: {
flex: 1
},
items: [carousel1]
});
}
Ext.EventManager.onWindowResize(setActivePanel);
});

function setActivePanel(){
panel.setOrientation( Ext.getOrientation() , window.innerWidth , window.innerHeight );
};

m7o
2 Nov 2010, 5:42 AM
Hi oonox,
thank you for sharing this, but in your code
Ext.EventManager.onWindowResize(setActivePanel); is located in the wrong place (in the Ext.setup function) and secondly, even if I put it in the correct spot, it will only fire once (see posts above).

But still, thanks to your idea we will be finally getting there someday ;-)

m7o
2 Nov 2010, 7:01 AM
Just to let everybody know: the onWindowResize event fires just fine, and everytime. I wrote a little feedback function giving me width and height of both my panel I want redrawn and the window after each onWindowResize. The numbers area always correct, and it fires everytime.
Only the panel is redrawn just the first time.

This is driving me nuts.


'feedback' in this case is just the ID of an html element in the window.


var dh = Ext.DomHelper;
Ext.EventManager.onWindowResize(setActivePanel);
function setActivePanel(){


panel.setOrientation(Ext.getOrientation(), window.innerWidth, window.innerHeight);
dh.overwrite(
'feedback',
{html:panel.getWidth()+' '+panel.getHeight()+' '+Ext.getOrientation()+' '+window.innerWidth+' '+window.innerHeight}
);


};

m7o
2 Nov 2010, 7:09 AM
I was not quite correct: the onWindowResize stops firing if panel.setOrientation... was called!
comment out the line with 'panel.setOrientation' and the event fires everytime, keep it active and it will not fire after the first time.
weird.

m7o
2 Nov 2010, 7:46 AM
As far as I can see, only a modified version of ed.canas (http://www.sencha.com/forum/member.php?194092-ed.canas) hack is working:



Ext.EventManager.onWindowResize(setActivePanel);
function setActivePanel(){
panel.setOrientation(Ext.getOrientation(), (window.innerWidth-1), window.innerHeight);
};


of course that is no real solution, as there really is that 1px margin on the right.

I tested some more, f.e. also with panel.setWidth(window.innerWidth), and that also breaks the onWindowResize listener, while panel.setWidth((window.innerWidth-1)) does not break it.

So please, please, please Sencha Touch support: This must give you something to work with?
I know you mainly promote Sencha for web apps, but I'm sure you want it to work in Phonegap etc. as well.

Please have a look into this, thank you.

m7o
3 Nov 2010, 8:17 AM
Finally found the solution: use 'overflow:hidden' on html AND body in your css and you can use window.innerWidth instead of (window.innerWidth-1) In the above solution. Voila, no more 1px space!

ed.canas
3 Nov 2010, 9:43 AM
Thanks it's now working as expected.

hitman01
9 Dec 2010, 7:55 AM
How can I use this method globally for all my components at the same time so that it does not fire in normal browser?