I already have a good understanding of the OrientationEventListener, and detecting screen orientation. But, how do I rotate or adjust the actual content (buttons, images, tabs, any objects)? Right now, when the user rotates the phone, the content doesn't move or rotate, and it appears sideways to the user.
NOTE: I am using the Droid 2 for testing, and I have noticed that if i I slide out the keyboard, the screen DOES rotate, which is kind of strange in my opinion.
Any help is greatly appreciated!
EDIT: Here is my code:
OrientationEventListener ole = new OrientationEventListener(this) {
#Override
public void onOrientationChanged(int arg0) {
TabHost ll = (TabHost) findViewById(android.R.id.tabhost);
try {
ll.forceLayout();
} catch (NullPointerException e) {
System.exit(0);
e.printStackTrace();
}
}
};
ole.enable();
Unfortunately, when the program reaches ll.forceLayout(), it throws a NullPointerException and causes the system to shut down.
SOLVED: I had to edit the manifest such that android:screenOrientation="sensor". Thanks for all your help!
but I have no idea of how to tell android to switch to the second view
when the screen rotates
You don't have to tell it to. If you just create a layout-land folder in your project the system will know to pull layout files from that folder if the device goes in to landscape mode.
Try to call forceLayout () for your root view in the onOrientationChanged.
Just leave that android:screenOrientation="sensor" out of your manifest. It's the default.
Related
I have a requirement to rotate the screen to Landscape from Portrait. Then I should stay in Landscape even though I have not tilted my phone. Portrait and Landscape have different views with buttons for orientation change and is in same content page which I have handled with content template. So, now I wanted to rotate automatically if I tilt the phone or if I tap on the button in either view to change orientation.
Portrait -> Landscape change using button then I should stay in landscape view until one rotation happen.
ex:- Now, I came to Landscape using a sensor, and I am in Landscape mode if I tap the button for rotation then I should change in portrait and should stay there.
I want to satisfy both cases. How to achieve that in Android and iOS (Xamarin.Forms)?
Anyone faces this kind of usecase and if you got a solution. Help me out.
When using Xamarin.Forms, the supported method of controlling device orientation is to use the settings for each individual project.
You could call the following method in dependency service.
Create a interface:
public interface IOrientationService
{
void Landscape();
void Portrait();
}
Android:
public class OrientationService : IOrientationService
{
public void Landscape()
{
((Activity)Forms.Context).RequestedOrientation = ScreenOrientation.Landscape;
}
public void Portrait()
{
((Activity)Forms.Context).RequestedOrientation = ScreenOrientation.Portrait;
}
}
iOS:
public class OrientationService : IOrientationService
{
public void Landscape()
{
AppDelegate appDelegate = (AppDelegate)UIApplication.SharedApplication.Delegate;
appDelegate.allowRotation = true;
UIDevice.CurrentDevice.SetValueForKey(new NSNumber((int)UIInterfaceOrientation.LandscapeLeft), new NSString("orientation"));
}
public void Portrait()
{
AppDelegate appDelegate = (AppDelegate)UIApplication.SharedApplication.Delegate;
appDelegate.allowRotation = true;
UIDevice.CurrentDevice.SetValueForKey(new NSNumber((int)UIInterfaceOrientation.Portrait), new NSString("orientation"));
}
}
For the usage of dependency service, you could refer to the link below. How can I block rotation to only allow portrait mode in xamarin forms?
I want to rotate only one page in my app automatically and as well as manually.
When you do the navigation, you could do the Orientation before loading the page in OnAppearing event.
protected override void OnAppearing()
{
base.OnAppearing();
DependencyService.Get<IOrientationService>().Landscape();
}
Both portrait and landscape views are different.
Liek 1., you could set the Orientation you want to in each page with OnAppearing() event.
I should not lock the particular page at any cause but I also when I want to change orientation manually I should able to do that. Even though I am not rotating/tilt the phone.
If you want to do it manually, invoke the Landscape or Portrait in a click event or tap or something else.
how to reload a page (with a new template) when the orientation of the device changes?
I want a different layout in landscape mode. This is in NativeScript, not Java.
the correct xml file is selected if i arrive at the page in landscape, but if i change orientation, nothing gets reloaded.
Note that this is not a question of refreshing the CSS, it is a different XML file needed.
NativeScript solution:
First you need to tie into the orientation event. You have a couple ways you can tie into that event.
The first and easiest method is to install the nativescript-orientation plugin, it ties into the event globally and then it will just automatically run your exported function on each of the current page called orientation, each time the orientation changes.
To Install:
tns plugin install nativescript-orientation
Open your app.js file and add at the top of the file;
require('nativescript-orientation');
Then by creating:
exports.orientation = function(args) {
if (args.landscaped) { /* do landscape stuff */ }
else { /* do port */
};
on any page you want to be notified that the orientation changed, it will be called on those pages that have that function and you can handle the event how you need to.
However, if you prefer to not use a plugin, you can directly tie into the orientation event yourself by doing:
var application = require('application');
exports.onNavigateTo = function() {
application.on(application.orientationChangedEvent,myOrientationFunction);
}
exports.onNavigateFrom = function() {
application.off(application.orientationChangedEvent, myOrientationFunction);
function myOrientationFunction(args) {
// We have an orientation event
}
However you must ask to be notified of the event when your page first open and you must remove your self from the notification when your page closes. This is a lot of extra code per page that the plugin above just handles for you. Please note when you are doing this yourself you also need to to add the NavigateTo/NavigatedFrom to the <Page> tag in your Declarative UI XML file, otherwise those functions won't be called.
Ok, now that you have the event which ever way you prefer; lets look at how we can make your idea work.
Now, you are asking to switch layouts each time the page changes; this is typically the worst thing to do; but I will answer it first and then give you the alternative method that I use to do complex layouts that work in both Portrait and Landscape modes pretty much automatically.
MyPage-Landscape.xml
<Page><StackLayout><Label text="Landscape"/></StackLayout></Page>
MyPage-Portrait.xml
<Page><StackLayout><Label text="Portrait"/></StackLayout></Page>
MyPage-Landscape.js
var commonPage = require("./MyPage.js");
var frame = require('ui/frame');
exports.orientation = function(args) {
if (args.landscape === false) {
frame.topmost().navigate('MyPage-Portrait');
}
};
// Tie all the common page code into this pages exports
for (var key in commonPage) {
if (commonPage.hasOwnProperty(key)) {
exports[key] = commonPage[key];
}
}
MyPage-Portrait.js
var commonPage = require("./MyPage.js");
var frame = require('ui/frame');
exports.orientation = function(args) {
if (args.landscape === true) {
frame.topmost().navigate('MyPage-Landscape');
}
};
// Tie all the common page code into this pages exports
for (var key in commonPage) {
if (commonPage.hasOwnProperty(key)) {
exports[key] = commonPage[key];
}
}
MyPage.js
exports.TapHandler = function() { /* Someone Tapped */ }
exports.someOtherLogic = function() { /* More logic */ }
exports.etc = function() { /* etc */ }
You put all your common page logic in the MyPage file; but you specifically navigate to the specific landscape or portrait page; and each of them are responsible to navigate to the other version if the page orientation changes.
Notes about the above solution:
You need to navigate to the proper version of the page from any other page; ie. if you are in Landscape mode; when you navigate to another page; you need to make sure you navigate to the Landscaped version of the page.
the NS-Orientation plugin does give you a handle helper function to find out the current orientation to make this easier.
Remember to make the MyPage.js have all the common code; you want to try and eliminate any custom code on a specific page version.
Their is a frame reload command you can use; however it totally clears the history; meaning you can't navigate backwards. i.e. Page1 -> Page2, frame.reloadPage() means that the back button will NOT go back to Page1. If this is acceptable; you can make the above system a lot simpler; rather than create separate xml & js files you just need a myPage.landscape.xml and myPage.portrait.xml and you need to on every orientation change just call the frame.reloadPage();
Now to me the above is some serious overkill for what is probably a simple change that you need done between pages. So I'm going to describe how I do it in my apps; which has some pretty complex screens but they look very nice and completely change functionality on a orientation change.
This is part of the reason the NativeScript-orientation plugin was written. On a page orientation change will automatically add / remove a "landscape" class name to the <Page> element in your XML. What this allows you to do in your CSS is:
.myLabel {
font-size: 12;
background-color: blue;
height: 20;
}
.landscape .myLabel {
font-size: 16;
background-color: green;
height: 40;
}
If you haven't figured out where I am going with this; this allows you to have custom CSS for the page while in landscape mode vs it being in portrait mode. In addition when you use the exports.orientation function in union with it also you can then run custom code depending on the orientation.
So in my case; On a phone my scroll list is a single scroll list of items going up down and is sized perfectly to the screen, and looks very sharp. When you switch to landscape mode; it hides the actionbar, adds a fab button, resizes the entire grid item to fit with the same proportions and switches scrolling modes to right-left. The majority of the entire look change is done in pure css; and the rest is done in the exports.orientation function which handles things like switching scroll direction.
Disclaimer: I am the author of the NativeScript-orientation plugin
In your activity:
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
setContentView(R.layout.my_layout);
}
Make sure you have layout XML with same name for both orientations
res/layout/my_layout.xml
res/layout-land/my_layout.xml
With correct resource file names Android system automatically reloads your Activities/Fragments with proper resources.
You can catch and handle events manually by setting android:configChanges (but it is a rare case).
Check some documentation:
Handling Runtime Changes
Providing Resources
First of all say that I don't have much experience programming and that these are my first steps in Android.
I've developed an app for android, with minSdkVersion 8 and targetSdkVersion 16.
The application is like a photographic gallery that when you touch one of the pictures, shows a screen with a picture, a text, and play two sounds. You can view the previous or next screen sliding with your finger, or make it automatically sliding with some intervals.
I've tested the app in the emulator with android 2.2, and in some devices with android 2.3.5 and android 4.0.x.
With android 2.2 and 2.3.5 the app works correctly, but with android 4.0.x I've detected that the "manual" way works correctly, but the "automatic image sliding" doesn't work.
The problem is that you select one of the pictures and the first activity runs correctly, but after the first one, the sounds of the next activity are heard before the layout of this activity is on the screen. If you exit to the main menu and choose other picture, the problem is the same. You see correctly the first activity and after that, the sounds advance the image of the activity.
I haven't found nothing similar to my problem searching here. Can anyone help me?
EDITED to show some code.
The onCompletion code:
public void onCompletion(MediaPlayer mp) {
if(mp.equals(mpNom)){
try {
Thread.sleep (mpNom.getDuration()+500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else if(mp.equals(mpSo)){
try {
Thread.sleep (mpSo.getDuration());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
The application does't show any error and neither crash, but the UI is shown when the sounds are already reproducing.
Any idea? Thanks in advance.
Finally I've solved the problem.
It seems that the problem was in the OnCompletion method or in the code inside this method.
I rewrite the code making the app do the same but in a different way (programmaticaly talking), avoiding the OnCompletion method and now the app works perfect in android 4.0.x
I've written an android app with a view within an activity that relies on a callback to the view's wrapper's getHeight() function using an OnGlobalLayoutListener attached to the view's wrapper's viewTreeObserver to determine the amount of space it has to work with, during onCreate. Usually this is less than the 400px requested by chordDisplay in the xml below. This works perfectly in the android emulator, for a variety of screen sizes using android 2.1 and 4.03. However, on my kindle fire, the callback does not initially return the correct height when I launch the app in landscape (less than 400px are available) until I switch the orientation to portrait and back to landscape either manually or by code. This means the contents of my view aren't sized correctly initially.
sample logcat output when I initially launch the app in landscape:
04-22 17:31:28.249: D/onGlobalLayout(12979): chordDisplay.getHeight(): 400
then I switch to portrait and back to landscape:
04-22 17:32:44.546: D/onGlobalLayout(12979): chordDisplay.getHeight(): 350
I don't understand how this could be happening considering that all that happens during an orientation change is another call to onCreate() in the app, right? Which is the same thing that happens when I start the app.
Does anyone have any experience with similar orientation switching / layout bugs in their apps?/Have any ideas why this could be happening? Any help would be appreciated... Thanks.
code:
OnGlobalLayoutListener thelistener;
RelativeLayout chordDisplayWrapper;
TableRow.LayoutParams lp;
private ChordAdapter chordAdapter;
private HorizontalListView chordDisplay
thelistener = new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
chordDisplayWrapper.getViewTreeObserver().removeGlobalOnLayoutListener(this);
Log.d("onGlobalLayout", "chordDisplay.getHeight(): " + chordDisplay.getHeight());
lp = new TableRow.LayoutParams(chordDisplay.getHeight()/6 -2,chordDisplay.getHeight()/6 -2); //6 just works. I shrink it a tiny bit to compensate for some weird bug.
chordAdapter = (new ChordAdapter(mcontext, R.layout.row, magicbundle, lp));
chordDisplay.setAdapter(chordAdapter);
}
};
chordDisplayWrapper.getViewTreeObserver().addOnGlobalLayoutListener(thelistener);
xml layout for views involved:
<RelativeLayout
android:id="#+id/chordDisplayWrapper"
android:layout_width="wrap_content"
android:layout_height="0dip"
android:layout_weight="1"
android:gravity="center" >
<berry.chordsfree.HorizontalListView
android:id="#+id/testerList"
android:layout_width="wrap_content"
android:layout_height="400px"
android:layout_centerInParent="true"
android:gravity="center" />
</RelativeLayout>
You may have solved this by now, but posting for posterity for those that may come across this after -
I'm having the same problem on my Nexus One, running a custom 2.3.7 ROM, but the code works on my Nexus Galaxy on stock 4.1.1.
Similar to you, I'm trying to resize certain views during onCreate using ViewTreeObserver. I've tried manually calling dispatchGlobalLayout and have ascertained it isn't an issue with onGlobalLayout not firing. And I played around with moving elements into the activity's onWindowFocusChanged without success (but I want to avoid having much resizing done there). This has cost me more than a day of work so I'm just using a quick/dirty fix for now. It appears normally if I just tweak the layout/view in question, after onCreate finishes:
#Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (!reset) {
LinearLayout frameItem = (LinearLayout) findViewById(R.id.frameItem);
frameItem.setVisibility(LinearLayout.GONE);
frameItem.setVisibility(LinearLayout.VISIBLE);
reset = true;
}
}
I am making an app that has a scrolling screen like the homescreen style. I have implemented this solution:
Android Homescreen
It works great but I also want there to be buttons on each page that you can click to go to the next page but I just can't figure out how to do it! can someone help? I've been staring at this code for days now!
Thanks
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
UPDATE - HELP
I really don't understand how to get around the problem of calling the SetToScreen from the other activity, Can anyone help as if I try I do keep getting Static call errors.
Look at
public void setToScreen(int whichScreen) {}
Use this function to set to a screen on a click.
you should extend Draggablespace by adding a function to get the current space like:
public int getCurrentScreen() {
return this.mCurrentScreen;
}
then you can write your own functions in your activity like
public void nextScreen() {
draggableSpace.setToScreen(draggableSpace.getCurrentScreen() + 1));
}
The same for previous screen.
Now you only need to check if there is an additional screen waiting if you are going forward or backward.
(Of course draggableSpace is your object of the class draggablespace...not a static call!)