Recently at work, I’ve been working on making an Android version of the company’s iOS application. The application itself runs entirely in portrait mode, except for the image of the benefits card that is included in the application. In iOS, that was easy enough to accomplish. In Android, the most common way to limit orientation changes is on a per-activity basis in the manifest, like this:
<activity
android:screenOrientation="portrait"
android:configChanges="orientation|keyboardHidden">
</activity>
Unfortunately, we can’t do that. Our application makes use of the “slide out” menu that was made popular in the Facebook application, but that you can now find as a very common pattern in many applications. The way that you accomplish this pattern in Android is by using the DrawerLayout and by using Fragments. Fragments are much like User Controls in Asp.Net WebForms or Partial Views in Asp.Net MVC or Rails. You have a container and you can load different layouts into that container, while maintaining the rest of the page’s layout as-is. The code that drives the fragment layouts has its own lifecycle (making it much more like WebForms User Controls than a Partial View).
The problem that this causes us is that we have one activity that sometimes we want to be able to rotate and other times, we want to keep it locked into place depending on which fragment is loaded at any given time. I searched and searched and could not find a solution that worked for us 100% of the time and was simple enough to implement. Eventually, I came up with my own solution to this problem.
The code for this entire project can be found on GitHub. For demonstration purposes, the project is based on a Sliding Menu project created by Ravi Tamada. Most of the code is his, with just the modifications I’m going to discuss here.
The menu looks like this:
When you click an item, it loads a fragment into the main window section. Here are the landscape modes of the Home Screen, followed by the Communities Screen:
What we want, however, is for the Communities screen to remain in portrait mode no matter how we turn the phone, but the other pages can rotate. To accomplish this, I modified the method that is called whenever someone selects one of the menu items out of the menu.
/**
* Diplaying fragment view for selected nav drawer list item
* */
private void displayView(int position) {
// update the main content by replacing fragments
Fragment fragment = null;
// We allow the Sensor to be used in all instances by default
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
switch (position) {
case 0:
fragment = new HomeFragment();
break;
case 1:
fragment = new FindPeopleFragment();
break;
case 2:
fragment = new PhotosFragment();
break;
case 3:
// In just this one instance, we turn the sensor off
// Until a different menu item is selected, which re-enables it
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
fragment = new CommunityFragment();
break;
case 4:
fragment = new PagesFragment();
break;
case 5:
fragment = new WhatsHotFragment();
break;
default:
break;
}
if (fragment != null) {
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.frame_container, fragment).commit();
// update selected item and title, then close the drawer
mDrawerList.setItemChecked(position, true);
mDrawerList.setSelection(position);
setTitle(navMenuTitles[position]);
mDrawerLayout.closeDrawer(mDrawerList);
} else {
// error in creating fragment
Log.e("MainActivity", "Error in creating fragment");
}
}
Notice that the first thing we do is allow the orientation sensor to work.
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
However, as we are setting to load the fragment for communities (if that is selected), we turn the orientation sensor off.
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
That causes the device to not rotate and to return to the original orientation, no matter how you are holding the phone when it loads.
After this change, we see the following. The home screen looks right in portrait mode:
Rotating it, does make it move to landscape:
But, when I choose Communities and we are in landscape, the app will only display portrait mode:
That’s all there is to it. If you have a better solution, please feel free to leave it in the comments. If you want to check out the code and play around with it, here is the link to the repo again.