This question has been asked before here but its answer is incorrect. I would like to rotate some views on screen orientation change, but I want to keep the layout unchanged. They should be rotated 90, 180, 270 or 360 degrees according to the current orientation (SCREEN_ORIENTATION_LANDSCAPE
, SCREEN_ORIENTATION_PORTRAIT
, SCREEN_ORIENTATION_REVERSE_LANDSCAPE
, SCREEN_ORIENTATION_REVERSE_PORTRAIT
).
This is what I want to achieve:
The answer in the link I mentioned stated that I should create a new different layout in layout-land
. Clearly, this is not what I want. I don't want to recreate the activity or change layout orientation. I only want to rotate some views, and keep other views unchanged on orientation change.
There is a huge difference between rotating specific views and changing or recreating the whole layout (both on orientation change).
Using the answer in this link, I will be able to get the current screen orientation with this method:
public static int getScreenOrientation(Context context) {
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
int rotation = windowManager.getDefaultDisplay().getRotation();
DisplayMetrics dm = new DisplayMetrics();
windowManager.getDefaultDisplay().getMetrics(dm);
int width = dm.widthPixels;
int height = dm.heightPixels;
int orientation;
// if the device's natural orientation is portrait:
if ((rotation == Surface.ROTATION_0
|| rotation == Surface.ROTATION_180) && height > width ||
(rotation == Surface.ROTATION_90
|| rotation == Surface.ROTATION_270) && width > height) {
switch (rotation) {
case Surface.ROTATION_0:
orientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
break;
case Surface.ROTATION_90:
orientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
break;
case Surface.ROTATION_180:
orientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
break;
case Surface.ROTATION_270:
orientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
break;
default:
Log.e("ScreenOrientation", "Unknown screen orientation. Defaulting to " + "portrait.");
orientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
break;
}
}
// if the device's natural orientation is landscape or if the device
// is square:
else {
switch (rotation) {
case Surface.ROTATION_0:
orientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
break;
case Surface.ROTATION_90:
orientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
break;
case Surface.ROTATION_180:
orientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
break;
case Surface.ROTATION_270:
orientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
break;
default:
Log.e("ScreenOrientation", "Unknown screen orientation. Defaulting to " + "landscape.");
orientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
break;
}
}
return orientation;
}
On orientation change, I would like to do something simple like this:
RotateAnimation rotateAnimation = new RotateAnimation(0, getScreenOrientation(getContext()));
rotateAnimation.setDuration(2000);
for (int i = 0; i < 63; i++) {
Button button = (Button) rootView.findViewById(i);
button.startAnimation(rotateAnimation);
}
Another way to rephrase my question would be "Is there any way to detect orientation change in onConfigurationChanged()
method without changing the layout?". The problem is that it will not be able to detect any orientation change if I already disable layout orientation change.
Anyone knows how it is done? I might have totally gone through wrong steps, and I think I will have to use Accelerometer Sensor or something similar to that to achieve what I want, so please guide me through.
Try to use OrientationEventListener
. You don't need to use onConfigurationChanged
and android:configChanges="orientation|keyboardHidden|screenSize"
.
You need set android:screenOrientation="portrait"
for the activity in AndroidManifest.xml. Here is my solution with OrientationEventListener
:
public class MyActivity extends Activity{
private ImageButton menuButton;
private Animation toLandAnim, toPortAnim;
private OrientationListener orientationListener;
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_image_ruler);
menuButton=(ImageButton)findViewById(R.id.menu_button);
toLandAnim= AnimationUtils.loadAnimation(this, R.anim.menubutton_to_landscape);
toPortAnim= AnimationUtils.loadAnimation(this, R.anim.menubutton_to_portrait);
orientationListener = new OrientationListener(this);
}
@Override protected void onStart() {
orientationListener.enable();
super.onStart();
}
@Override protected void onStop() {
orientationListener.disable();
super.onStop();
}
private class OrientationListener extends OrientationEventListener{
final int ROTATION_O = 1;
final int ROTATION_90 = 2;
final int ROTATION_180 = 3;
final int ROTATION_270 = 4;
private int rotation = 0;
public OrientationListener(Context context) { super(context); }
@Override public void onOrientationChanged(int orientation) {
if( (orientation < 35 || orientation > 325) && rotation!= ROTATION_O){ // PORTRAIT
rotation = ROTATION_O;
menuButton.startAnimation(toPortAnim);
}
else if( orientation > 145 && orientation < 215 && rotation!=ROTATION_180){ // REVERSE PORTRAIT
rotation = ROTATION_180;
menuButton.startAnimation(toPortAnim);
}
else if(orientation > 55 && orientation < 125 && rotation!=ROTATION_270){ // REVERSE LANDSCAPE
rotation = ROTATION_270;
menuButton.startAnimation(toLandAnim);
}
else if(orientation > 235 && orientation < 305 && rotation!=ROTATION_90){ //LANDSCAPE
rotation = ROTATION_90;
menuButton.startAnimation(toLandAnim);
}
}
}
}
This also prevents from too frequent rotations when orientation
is about 45, 135... etc.
Hope it helps.