My app tries to support both portrait and landscape modes.
In portrait mode it has to show the status bar, but not in landscape mode (on iOS).
This is achieved by using 1) theme constant landscapeTitleUiidBool=true and 2) overriding StatusBarLandscape, as suggested here:
Codename One iOS Statusbar on landscape orientation.
I have created a test project with two forms and the following logic:
public void start() {
if (current != null) {
current.show();
return;
}
Form home = new Form("Home", BoxLayout.y());
Button ok = new Button("OK");
ok.addActionListener(e -> {
showOKForm(home);
});
home.add(ok);
home.show();
}
// precondition: Toolbar.setGlobalToolbar(true) set in init(Object)
private void showOKForm(Form home) {
Form f = new Form("OK", BoxLayout.y());
f.add(new Label("Thanks"));
f.getToolbar().setBackCommand("", e -> home.showBack());
f.show();
}
This works as expected - but not always!
Testing the app on an iPhone X device things quickly go wrong if we play around a little with form navigation and rotating the device.
All situations occur: both forms in portrait mode showing the status bar correctly and incorrectly (i.e. the title and back command on top of the status bar) and both forms in landscape mode not showing the status bar correctly (i.e. no status bar) and incorrectly (i.e. status bar space above the title and back command).
See the attached picture with partial screenshots (only the relevant top (left) parts are shown).
Scenarios to achieve this are not reproducible: it depends.
The problems also occur in the simulator.
It appears that sometimes the wrong UIID is used: StatusBar vs StatusBarLandscape. (Edit: in the simulator it shows the correct UIIDs but the dimensions are wrong, i.e. "reversed".)
In my real app (i.e. not the test project) I have reproducible situations where things go wrong, especially in this scenario: 1) open a form, 2) rotate the device, 3) go back to the previous form. I tried overriding showBack() to redo the layout or to revalidate, but nothing helps.
Question: is the above implementation correct and how can this problem be solved?
Related
I'm developing a temporary web app for the iPad. It's really just a stop-gap until a proper mobile solution can be devised for this particular product.
One issue is this app works and looks perfect in Landscape, but in Portrait mode, the dimensions just don't fit.
I'm sure this is a horrible usability crime to even ask such a question, but is there any sort of convention for prohibiting a web app from rotating to Portrait mode?
I'm not looking for an examples of code, I'm just wondering if anything like this exists.
No, there isn't an option. After all html is all about dynamic display of information. Just define the elements of your webapp proper and it will look fine.
You can use the orientation change function to check for the orientation and then show a image or div stating the user that webapp can be opened only in Landscape mode.
window.addEventListener('orientationchange', function(event) {
if (window.orientation == 90 || window.orientation == -90)
{
/* Hiding the Message div */
}
else
{
/* Show a div in Portrait Asking users to switch orientation to Landscape */
}
});
So I have created an App that has a different menu when it is held portrait, but changes when held landscape.
I can get the navigation to work, However I am unsure how to design landscape pages inside Flash?
My stage is set to the standard 640x960 air for iOS, which gives me perfect portrait pages, But when I tilt my phone to landscape the screen obviously changes, and it looks weird. Im hoping someone can tell me how i can get this view inside Flash, while still having the portrait screens too?
I want to have both Portrait and Landscape in the same app, and am currently so confused how I can design this inside flash?
I hope this makes sense, and that someone could throw some help my way!
It's not easy, but you can do it. First, you have to wait until stage is initialized and set it's scaling property to no scale (this will stop resizing page to fill screen). Then you have to listen to stage's resizing (it trigger's every time you rotate iPhone) and to move/scale your display objects in proper way in the listener handler.
addEventListener(Event.ADDED_TO_STAGE, init); //Wait for stage initialization
private function init(e:Event):void { //init handler
removeEventListener(Event.ADDED_TO_STAGE, init); //remove listener, which won't be used more
stage.scaleMode = StageScaleMode.NO_SCALE; //set null scaling and top-left align
stage.align = StageAlign.TOP_LEFT;
stage.addEventListener(Event.RESIZE, resize); //add handler for resizing
}
private function resize(e:Event):void { //triggers every time iPhone being rotated
//Move/scale your objects here
}
Im developing an application using Titanium which is compatible for iPhone. I'm navigating between 4 views.
1st View (Portrait) ---> 2nd View (Landscape) --> 3rd View (Portrait) ---> 4th View (Portrait)
SO I have 3 Portrait views in my application and I used Tiapp.xml and add
<orientations device="iphone">
<orientation>Ti.UI.PORTRAIT</orientation>
</orientations>
For 2nd View I used following code ;
var winCheckInLogin = Ti.UI.createWindow({
backgroundColor : "black",
orientationModes : [Titanium.UI.LANDSCAPE_LEFT, Titanium.UI.LANDSCAPE_RIGHT],
navBarHidden : true, // Hides the native title bar
});
winCheckInLogin.addEventListener("open", function() {
Titanium.UI.orientation = Titanium.UI.LANDSCAPE_LEFT;
});
But for the loading time 2nd View appear on Portrait mode after I rotate my device it keep it as Landscape. I need to load it as Landscape mode and lock that screen as it is.
Please help me to solve this.
Thanks a lot
Gayan,
Using different orientation modes for a single app in iPhone is not recommended. Please read Orientation design principles
Apple's Developer documentation says: "People expect to use your
app in different orientations, and it’s best when you can fulfill that
expectation." In other words, don't look at handling orientation as a
bother but an opportunity.
Apple further recommends that when choosing to lock or support
orientation, you should consider following these principles:
On iPhone/iPod Touch – Don't mix orientation of windows within a single app; so, either lock orientation for the whole app, or react to orientation changes.
On iPhone – don't support the portrait-upside-down orientation because that could leave the user with their phone upside-down when receiving a phone call.
However, if you want to use different orientations, just add the following to your tiApp.xml under <orientations device="iphone"> tag
<orientations device="iphone">
<orientation>Ti.UI.LANDSCAPE_LEFT</orientation>
<orientation>Ti.UI.LANDSCAPE_RIGHT</orientation>
</orientations>
This will do the trick for you!!
http://docs.appcelerator.com/titanium/latest/#!/api/Titanium.UI.Window-property-orientationModes
In your tiapp.xml
<orientations device="iphone">
<orientation>Ti.UI.PORTRAIT</orientation>
<orientation>Ti.UI.LANDSCAPE_LEFT</orientation>
<orientation>Ti.UI.LANDSCAPE_RIGHT</orientation>
</orientations>
For all Windows (and not views), be sure to add the property of that window as:
orientationModes: [Ti.UI.PORTRAIT]
for Portrait-only Windows,
and for lanscape-only:
orientationModes: [Ti.UI.LANDSCAPE_LEFT, Ti.UI.LANDSCAPE_RIGHT]
That should do the trick you're looking for.
I'm having trouble getting my app to rotate since switching to Xcode 4 and iOS 5. After tearing my hair out, I created a brand-new test project to see if I could get a bare-bones app to rotate.
I created the test project using the 'Empty Application' template. All I added to this template was a UINavigationController, with a UIViewController pushed onto it. There is a nib file for the UIViewController, with one label that says 'Hello'.
On the target Summary screen, I clicked in all the buttons for 'Supported Device Orientations'.
In the .m files for the Navigation and View controller code I changed shouldAutoRotate... to:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (YES);
}
The test project builds with no issues and runs perfectly. There's a navigation bar and friendly 'Hello' message, but the darn thing won't rotate!
Obviously, I am missing something pretty simple, but I can't figure out what it is. My suspicion has fallen on the .nib. Under 'Simulated Metrics', there is an attribute called Orientation. This is set to Portrait. The only other choice is 'Landscape'. If I change this setting to 'Landscape' the view in the .nib editor changes to landscape, but when I run the app, it runs in Portrait mode, and still refuses to rotate.
Hopefully, someone will get a big laugh out of my blunder and point out the goofy mistake I'm making. Please do!
in your RootViewController.m find the line
return (UIInterfaceOrientationIsPortrait( interface Orientation ) );
and you can replace this with whatever... like
return (UIInterfaceOrientationIsLandscape( interface Orientation ) );
I have a application with a screen manager class that is causing me some problems.
The application makes requests to the server to perform searches and allows the user to view results.
The application has worked fine on all OS versions up to 4.5 where we are sudden having
problems viewing a screen under certain circumstances.
It occurs when the user has performed a search and they wait for the results.
While waiting for results, they press the trackball which displays a menu.
This is not needed to display the results, it just happened that the user decided to press it.
When the results come back from the server, the results screen should automatically be displayed. On OS 4.5, the code displays the results screen runs but then the application completely falls over. If the user doesn't press the trackball while waiting, the application works fine.
Looking at the logs, they show no exception being thrown and the only suspect line being
System data:VM:DPNAv=78,p
By adding in some more log lines I have discovered that the code is reaching the
UiApplication.getUiApplication().popScreen(screen);
line in the method hideScreen(Screen screen) but when called from hideCurrentScreen(). By adding in some more debugging I find that the active screen at this point is DefaultMenuScreen (as the menu button has been pressed)
So it seems the problem is that I am trying to pop one of my own screens from the display
stack when the DefaultMenuScreen one is the active one. I repeat that this code did work on OS previous to 4.5. By running the same code on the 8300 with OS 4.2.2 with the debugging statements, I can see that the same thing happens, the active screen is the DefaultScreen but removing my own screen does not cause the whole application to crash.
The one way round this I could see, was to change the hideCurrentScreen() to just remove the active screen but this does not seem like the correct way to do it.
Has anyone else had experience of this? Can anyone tell me why this is happening? What are we meant to do if we cannot remove our screens when a DefaultMenuScreen is the active one?
This occurs in both device and simulator for 8310 and 9700.
The screen manager code is as follows.
public class ScreenManager
{
private Hashtable screens;
private String currentScreenName;
public ScreenManager()
{
screens=new Hashtable();
}
/**
* Description of the Method
*
*#param sCardName Description of Parameter
*/
public boolean showScreen( String sScreenName )
{
boolean bSuccess=false;
if (sScreenName != null && sScreenName.length() > 0 )
{
MainScreen screen=(MainScreen)screens.get(sScreenName);
if (screen!=null)
{
// We have a new screen to display so pop the current screen off the stack
hideCurrentScreen();
// If the screen is on the stack then pop the screens until we get our target screen
// otherwise just push the screen onto the stack.
if (screen.isDisplayed())
{
Screen activeScreen=null;
synchronized(UiApplication.getEventLock())
{
activeScreen=UiApplication.getUiApplication().getActiveScreen();
}
while (screen!=activeScreen && activeScreen!=null)
{
activeScreen=hideScreen(activeScreen);
}
bSuccess=(screen==activeScreen);
}
else
{
synchronized(UiApplication.getEventLock())
{
UiApplication.getUiApplication().pushScreen(screen);
bSuccess=true;
}
}
}
}
if (bSuccess)
{
this.currentScreenName=sScreenName;
}
else
{
Logger.warning("ScreenManager: Failed to display screen ["+ sScreenName +"]");
}
return bSuccess;
}
private Screen hideCurrentScreen()
{
Screen activeScreen=null;
if(currentScreenName!=null)
{
MainScreen screen=(MainScreen)screens.get(currentScreenName);
activeScreen=hideScreen(screen);
}
return activeScreen;
}
private Screen hideScreen(Screen screen)
{
Screen activeScreen=null;
if (screen!=null && screen.isDisplayed())
{
Logger.finest("Hiding Screen ["+currentScreenName+"]");
synchronized(UiApplication.getEventLock())
{
UiApplication.getUiApplication().popScreen(screen);
activeScreen=UiApplication.getUiApplication().getActiveScreen();
}
Logger.finest("Hid Screen ["+currentScreenName+"]");
}
return activeScreen;
}
//Rest of code omitted
}
The only way round this I managed to find was what I mentioned in the question. When I want to remove the current screen. I need to check it is the same as the active screen. If it is not the same then I just remove the active screen until I reach the screen I am looking for. This would only happen if a menu or pop up was displayed. Also, I need to add checks to my custom pop-up code to make sure it does not try and remove a screen that has already been removed.
It seems a bit messy but could not find any other alternatives.
The way we pop screens in our app is to explicitly pop the screen you want off the stack, as opposed to just the top-most screen. This either requires keeping track of which screens you have on the stack, or some code to iterate through the screens on the stack and search for the particular screen you want to pop off.