Label/image resize on rotation behavior in iOS

230 views
Skip to first unread message

Chris Ostmo

unread,
Mar 24, 2014, 10:06:37 PM3/24/14
to codenameone...@googlegroups.com
I didn't want to tag on to the old thread because this is its own issue, but this is one step past where I was here:
https://groups.google.com/forum/#!topic/codenameone-discussions/PgT-q1RmiIo

I changed to a BorderLayout and subclassed Label so that I could override setPreferredSize so that the Label (and the image used as its icon) that lives in the NORTH component area will always be full width (with height proportional to the image size) regardless of device orientation and to resize on device rotation.

The problem that I have remaining is that, on iOS devices, when the device rotates, the image squeezes or stretches to fit the width of the screen as the rest of the interface rotates, but the proportions are off for a fraction of a second, then the image snaps into place with the proper proportions. On Android devices and in the simulator, the interface rotates and the image is properly sized. I only have the problem on actual iOS devices. I have tried several combinations of animate(Fade)Layout(AndWait) both before and after rotation without any positive result.

I am going to include a bunch of the related code in hopes that it will help. Names have been changed to protect the innocent.

Sorry this is so long. I didn't know a better way to get all the pertinent information out there to avoid a lengthy back-and-forth conversation.

In the app's start method:
    Display.getInstance().getCurrent().addOrientationListener(
       
new ActionListener()
       
{
           
public void actionPerformed( ActionEvent evt )
           
{
               
String viewTag = MyAppData.sectionTagByLocationAndIndex( ICON_LOCATION_TABBAR, appCaller.tabComponent.getSelectedIndex() );
               
if( !viewTag.equals( "" ) )
               
{
                   
if( appCaller.childInstances.get( viewTag ) != null )
                   
{
                       
TabViews thisView = (TabViews)appCaller.childInstances.get( viewTag );
                        thisView
.rotate();
                   
}
               
}
               
Display.getInstance().getCurrent().animateLayout( 100 );
           
}
       
} // new ActionListener()


A child instance's rotate method:
    public void rotate()
   
{
       
this.imageLabel.resizeToFullWidth();
   
}



The same child instance's content provider (where the label/image is added to the interface):
        Container returnContainer = new Container( new BorderLayout() );
       
       
this.imageLabel = new CustomImageLabel();
       
try
       
{
           
Image bannerImage = Image.createImage( "/a_banner_image.png" );
           
this.imageLabel.setFullWidthImage( bannerImage );
       
}
       
catch( IOException e )
       
{
            e
.printStackTrace();
       
}

       
BrowserComponent bc = new BrowserComponent();
        bc
.setPage( this.getContent(), "/" );
       
       
Style bcStyle = new Style();
        bcStyle
.setBorder( Border.createEmpty() );
        bcStyle
.setMargin( 3, 3, 3, 3 );
        bcStyle
.setFgColor( 0xffffff );
       
        bc
.setSelectedStyle( bcStyle );
        bc
.setUnselectedStyle( bcStyle );
       
        returnContainer
.addComponent( BorderLayout.NORTH, this.imageLabel );
        returnContainer
.addComponent( BorderLayout.CENTER, bc );
       
       
return returnContainer;


And the custom image label class:
public class CustomImageLabel extends Label
{
   
public Image labelImage;

   
public void setImage( Image inputImage )
   
{
       
this.labelImage = inputImage;
   
}

   
@Override
   
public Dimension calcPreferredSize()
   
{
       
if( this.labelImage == null )
       
{
           
return this.calcPreferredSize();
       
}
       
       
int deviceWidth = Integer.valueOf( MyApp.deviceInfo().get( "width" ) ).intValue();

       
int imgWidth = this.labelImage.getWidth();
       
int imgHeight = this.labelImage.getHeight();
       
double ratio = ((double)imgHeight/(double)imgWidth);
       
       
return new Dimension( deviceWidth, (int)Math.floor( (deviceWidth * ratio) ) );
   
}

   
public void setFullWidthImage( Image inputImage  )
   
{
       
this.setImage( inputImage );
       
       
Style imgStyle = new Style();
        imgStyle
.setPadding( 0, 0, 0, 0 );
        imgStyle
.setMargin( 0, 0, 0, 0 );
        imgStyle
.setAlignment( Component.CENTER );
       
       
this.setSelectedStyle( imgStyle );
       
this.setUnselectedStyle( imgStyle );
       
       
Dimension dim = this.calcPreferredSize();
       
this.setIcon( this.labelImage.scaled( dim.getWidth(), dim.getHeight() ) );
   
}

   
/**
     * A convenience wrapper to setFullWidthImage( Image )
     */

   
public void resizeToFullWidth()
   
{
       
this.setFullWidthImage( this.labelImage );
   
}
}

I have an additional problem in this particular code in that, again, only on iOS devices (not on Android or in the simulator), what looks like a 1 pixel border gets added to the bottom of the BrowserComponent every time the device rotates. 2 rotations = 2 pixel border, 3 rotations = 3 pixel border... But I'd be happy to address that in another thread if I can prevent the image from visibly popping into size/shape from the result of this thread.

Thanks!


Chris Ostmo

unread,
Mar 24, 2014, 10:08:51 PM3/24/14
to codenameone...@googlegroups.com
I meant "calcPreferredSize" Sorry.

On Monday, March 24, 2014 7:06:37 PM UTC-7, Chris Ostmo wrote:

I changed to a BorderLayout and subclassed Label so that I could override setPreferredSize so that the Label...

Chris Ostmo

unread,
Mar 24, 2014, 10:22:56 PM3/24/14
to codenameone...@googlegroups.com
And one other bit of information that I should have included in the original post:
The title bar and its text and tab bar and its text and icons squeeze or stretch (depending on which orientation it's changing from/to) on rotation then snap into place a fraction of a second after rotation has completed also... The same thing is happening to the pre-baked interface components, not just the custom label/image that I created.

Chris Ostmo

unread,
Mar 25, 2014, 12:41:54 AM3/25/14
to codenameone...@googlegroups.com
Since this was happening to the pre-baked interface elements, I decided to create a simple test that took all of my code out of the equation.

I created a new app in Eclipse and chose "Tab Application" as the template. I setup my certificate and provisioning profile, created a build and installed it on the device.

With no changes to any code, this app has the same behavior on iOS devices. That is, on device rotation, the interface elements squeeze or stretch during rotation and then snap into place once the rotation has completed.

So... This is a bug in Codename One? I literally changed nothing, and this is the result.

If this is the behavior that is produced for iOS applications, I'm afraid I can't use Codename One for iOS apps, which would be a real bummer.

Should I send the code that Codename One produced to the support email address, or is this a known issue?

Chris Ostmo

unread,
Mar 25, 2014, 12:52:56 AM3/25/14
to codenameone...@googlegroups.com
OK. This is my last message until I here from someone at Codename One.

The same behavior happen to the title bar in the default "Hi World" application that's built when you accept all of the default options for a new project in Eclipse.

So I think it's reasonably safe to assume that this is a bug in Codename One (possibly only affecting iOS 7).

Is there a workaround? If not, I have to abandon Codename One as far as iOS is concerned because minute details of the interface are of extreme importance to this app.

Thanks.

Shai Almog

unread,
Mar 25, 2014, 2:18:59 AM3/25/14
to codenameone...@googlegroups.com
That's the rotation behavior we currently have on iOS. Since Codename One draws its own components the animation works in the same way as it would for a phonegap app or a game by scaling the UI during rotation.

Chris Ostmo

unread,
Mar 25, 2014, 2:26:05 AM3/25/14
to codenameone...@googlegroups.com
OK. Thanks for the info.

Unfortunately, we won't be able to use CN1 for iOS output with that visual behavior. I think it's still going to be OK for other platforms, but we were really hoping to be able to break away from 4 separate code bases. 2 will be better than 4, but it's not as good as 1.

Is there any hope of seeing that behavior fixed in the next few months?

Shai Almog

unread,
Mar 25, 2014, 2:59:21 PM3/25/14
to codenameone...@googlegroups.com
You can lock the orientation of the device but I'm guessing that's not what you want.

If you are serious about Codename One this is one of those things we might be able to improve but its a pretty difficult task. We would need to effectively recreate that exact effect in Codename One and resolve all the edge cases/component types. So this is theoretically doable, however we probably won't do it unless we get pressure from Enterprise customers to do it.

Steve Hannah

unread,
Mar 25, 2014, 3:23:49 PM3/25/14
to codenameone...@googlegroups.com
Just to chime in on this.  All the code is open source so if it is really that important to you, you can always just do it yourself.  That's one of the things I like most about CN1.  Every problem can be solved if you're willing to put in the time.


On Tue, Mar 25, 2014 at 11:59 AM, Shai Almog <shai....@gmail.com> wrote:
You can lock the orientation of the device but I'm guessing that's not what you want.

If you are serious about Codename One this is one of those things we might be able to improve but its a pretty difficult task. We would need to effectively recreate that exact effect in Codename One and resolve all the edge cases/component types. So this is theoretically doable, however we probably won't do it unless we get pressure from Enterprise customers to do it.

--
You received this message because you are subscribed to the Google Groups "CodenameOne Discussions" group.
To unsubscribe from this group and stop receiving emails from it, send an email to codenameone-discu...@googlegroups.com.
Visit this group at http://groups.google.com/group/codenameone-discussions.
To view this discussion on the web visit https://groups.google.com/d/msgid/codenameone-discussions/67bc4677-30be-486e-a90a-4ea67675a7ad%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
Steve Hannah
Web Lite Solutions Corp.
Reply all
Reply to author
Forward
0 new messages