Different layout for "Landscape" and "Landscape-reverse" orientation
Asked Answered
S

2

6

My problem:

For some requirements i need two different xml layouts for my activity:

  • One for Landscape mode.
  • And another one for Landscape-reverse mode (upside-down of Landscape).

Unfortunately Android doesn't allow creating a separate layout for landscape-reverse (like we can do for portrait and landscape with layout-land and layout-port).

AFAIK, the only way is to change the activity-xml from java code.

What i've tried:

1) Override onConfigurationChanged() method to detect orientation changes, but i can't figure out if it's Landscape or Landscape-reverse:

@Override
public void onConfigurationChanged(Configuration newConfig) {
     super.onConfigurationChanged(newConfig);

     if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
         Log.d("TEST","Landscape");
     }

}

( Whith android:configChanges="keyboardHidden|orientation|screenSize|layoutDirection" in my activity tag in manifest)

2) Use an OrientationEventListener with SENSOR_DELAY_NORMAL as suggested in this answer but the device orientation changes before entering my if blocks, so i get a delayed update of the view:

mOrientationEventListener = new OrientationEventListener(this, SensorManager.SENSOR_DELAY_NORMAL){

            @Override
            public void onOrientationChanged(int orientation) {

                if (orientation==0){
                    Log.e("TEST", "orientation-Portrait  = "+orientation);
                } else if (orientation==90){
                    Log.e("TEST", "orientation-Landscape = "+orientation);
                } else if(orientation==180){
                    Log.e("TEST", "orientation-Portrait-rev = "+orientation);
                }else if (orientation==270){
                    Log.e("TEST", "orientation-Landscape-rev = "+orientation);
                } else if (orientation==360){
                    Log.e("TEST", "orientation-Portrait= "+orientation);
                }

            }};

My question:

Is there a better solution to change activity-layout between "Landscape" and "Landscape-reverse" orientation?

Any suggestions are highly appreciated.

Sarah answered 11/1, 2016 at 19:36 Comment(0)
G
5

Are you trying as suggested here?. You may handle an event with a different types of configuration reverse and standart by using activity attribute sensorLandscape

EDITED: Try to use Display.getOrientation as described here http://android-developers.blogspot.in/2010/09/one-screen-turn-deserves-another.html

And do not forget to set configChanges flag on activity in manifest to handle changes manualy in onConfigurationChanges().

So it seems like only way to do this is to listen SensorManager as frequently as possible.

SensorManager sensorMan = (SensorManager)getSystemService(SENSOR_SERVICE);
Sensor sensor = sensorMan.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
sensorMan.registerListener(...)
Guenzi answered 11/1, 2016 at 20:18 Comment(10)
Thank you for your answer. I've just tried your suggestion and didn't work. Pete's answer is completely wrong. --1) With android:screenOrientation attribute you can't use |. --2) Configuration.orientation has nothing to do with ActivityInfo.SCREEN_ORIENTATION_PORTRAIT or the other constants.Sarah
Because Configuration.orientation has value = 1 or = 2 (ORIENTATION_PORTRAIT or ORIENTATION_LANDSCAPE) while ActivityInfo's constants have 0,1,8 and 9 as values.Sarah
Ok, have you meet with this topic by Dan Morrill - android-developers.blogspot.in/2010/09/… >The question is, how does the device tell you that it’s been reoriented? And the answer is: android.view.Display.getRotation(). That method will return one of four values, indicating that either the device has not been reoriented (ROTATION_0), or that it has been reoriented by 90 degrees, 180 degrees, or 270 degrees (which respectively are ROTATION_90, ROTATION_180, and ROTATION_270.)Guenzi
Using getRotation() will return the right value. But the problem is where to used it? I've added a switch case of getRotation() in onConfigurationChanged() method, it works fine when you do 90° rotations but for 180° rotation onConfigurationChanged() won't be called, because the screen size wasn't changed from land to land-rev (or port to port-rev).Sarah
Activity recreates it's self every time when configuration changed, since its have to reinflate an appropriate layout. So, theoreticaly you can call getOrientation anywhere, for example in onStart or onCreate.Guenzi
To use onConfigurationChanged() you should set configChanged flag on activity in app manifest. Otherwise configurationChanged() will not be called and activity will be recreated. See the attribute javadoc > Specify one or more configuration changes that the activity will handle itself. If not specified, the activity will be restarted if any of these configuration changes happen in the system. Otherwise, the activity will remain running and its Activity.onConfigurationChanged() method called with the new configuration.Guenzi
I know that, but practically this is not what happened (at least in my Samsung S3, Nexus 7, Nexus 10 and Acer iconia). Btw try to create a simple project with an Activity, then add a break point ( or some log) in onCreate method, then do a quick 180° rotation (exp from portrait to portrait-rev or land to land-rev) you'll see that onCreate() method is not always being called. I think android considered that switching from mode to reverse-mod doesnt affect the size so there is no need to recreate the activity or calling onConfigurationChanged(). Or maybe its just an Android bug.Sarah
PS: I've also tried with android:configChanges="keyboardHidden|orientation|screenSize|layoutDirection" in activity tag in manifest and its the same.Sarah
This topic groups.google.com/forum/#!topic/android-developers/IgBNQNgFUmk contains an answer from Android framework engineer Dianne Hackborn. She confirms that there is no gracefuly way to handle reversing orientation event. So, one of possible solutions must be to listen SensorManager with appropriate density, and hope it will not affect the battery too much.Guenzi
Thank you for the link, at least it confirm my results. An upvote for that :)Sarah
G
0

in order to achive this goal, you need to implement a rotation listener, you need also to know that android destroy objects and recreate them to load your layouts, values... based on configuration qualifiers

STEP 01: create a Java interface [rotationCallbackFn]

    public interface rotationCallbackFn {
        void onRotationChanged(int lastRotation, int newRotation);
    }

STEP 02: create a Java class [rotationListenerHelper]

import android.content.Context;
import android.hardware.SensorManager;
import android.view.OrientationEventListener;
import android.view.WindowManager;

public class rotationListenerHelper {

private int lastRotation;

private WindowManager windowManager;
private OrientationEventListener orientationEventListener;

private rotationCallbackFn callback;

public rotationListenerHelper() {
}

public void listen(Context context, rotationCallbackFn callback) {
    // registering the listening only once.
    stop();
    context = context.getApplicationContext();
    this.callback = callback;
    this.windowManager = (WindowManager) context
            .getSystemService(Context.WINDOW_SERVICE);

    this.orientationEventListener = new OrientationEventListener(context, SensorManager.SENSOR_DELAY_NORMAL) {
        @Override
        public void onOrientationChanged(int orientation) {
            WindowManager localWindowManager = windowManager;
            rotationCallbackFn localCallback = rotationListenerHelper.this.callback;
            if(windowManager != null && localCallback != null) {
                int newRotation = localWindowManager.getDefaultDisplay().getRotation();
                if (newRotation != lastRotation) {
                    localCallback.onRotationChanged(lastRotation, newRotation);
                    lastRotation = newRotation;
                }
            }
        }
    };
    this.orientationEventListener.enable();

    lastRotation = windowManager.getDefaultDisplay().getRotation();
}

public void stop() {
    if(this.orientationEventListener != null) {
        this.orientationEventListener.disable();
    }
    this.orientationEventListener = null;
    this.windowManager = null;
    this.callback = null;
}

}

STEP 03: add these statements to your mainActivity

// declaration
private rotationListenerHelper rotationListener = null;
private Context mContext;
//...

/* constructor ----------------------------------------------------------------*/
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    mContext = this;

    final int curOrientation =  getWindowManager().getDefaultDisplay().getRotation();

    switch (curOrientation) {
        case 0:
            //. SCREEN_ORIENTATION_PORTRAIT
            setContentView(R.layout.your_layout_port);
            break;
            //----------------------------------------
        case 2:
            //. SCREEN_ORIENTATION_REVERSE_PORTRAIT
            setContentView(R.layout.your_layout_port_rev);
            break;
            //----------------------------------------
        case 1:
            //. SCREEN_ORIENTATION_LANDSCAPE
            setContentView(R.layout.your_layout_land);
            break;
            //----------------------------------------
        case 3:
            //. SCREEN_ORIENTATION_REVERSE_LANDSCAPE
            setContentView(R.layout.your_layout_land_rev);
            break;
            //----------------------------------------
    } /*endSwitch*/

    rotationListener = new rotationListenerHelper();
    rotationListener.listen(mContext, rotationCB);

    //...
}

private rotationCallbackFn rotationCB = new rotationCallbackFn() {
    @Override
    public void onRotationChanged(int lastRotation, int newRotation) {
        Log.d(TAG, "onRotationChanged: last " + (lastRotation) +"  new " + (newRotation));

        /**
        * no need to recreate activity if screen rotate from portrait to landscape
        * android do the job in order to reload resources
        */

        if (
                (lastRotation == 0 && newRotation == 2) ||
                (lastRotation == 2 && newRotation == 0) ||
                (lastRotation == 1 && newRotation == 3) ||
                (lastRotation == 3 && newRotation == 1)
                )
            ((Activity) mContext).recreate();
    }
};

/* destructor -----------------------------------------------------------------*/
@Override
protected void onDestroy() {
    rotationListener.stop();
    rotationListener = null;
    Log.i(TAG, "onDestroy: activity destroyed");
    super.onDestroy();
}

FINAL STEP : ENJOY

Grose answered 23/1, 2017 at 23:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.