Rotate View Hierarchy 90 degrees
I had the same problem and managed to solve it. Instead of rotating each view or the layout by hand, I used a LayoutAnimationController.
First, place a file in /res/anim/ called rotation.xml
<?xml version="1.0" encoding="utf-8"?>
<rotate
xmlns:android="http://schemas.android.com/apk/res/android"
android:fromDegrees="0"
android:toDegrees="-90"
android:pivotX="50%"
android:pivotY="50%"
android:duration="0" android:fillAfter="true">
</rotate>
Then, in your Activity's onCreate, do
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.myscreen);
Animation rotateAnim = AnimationUtils.loadAnimation(this, R.anim.rotation);
LayoutAnimationController animController = new LayoutAnimationController(rotateAnim, 0);
FrameLayout layout = (FrameLayout)findViewById(R.id.MyScreen_ContentLayout);
layout.setLayoutAnimation(animController);
}
If you want to rotate elements that lie above your camera preview view (SurfaceHolder), simply place a FrameLayout above the SurfaceHolder, place all your elements in that FrameLayout and call the Layout "MyScreen_ContentLayout". Done.
Hope that helped someone out, took me quite a while to get everything together.
Using API level 11 and later you can use the method setRotation(degreesFloat);
to change the rotation of a view programmatically, or you can use the XML attribute android:rotation=""
to change it in your XML. There are also methods/attributes for changing only the X or Y values of a view's rotation: Android Docs - View (setRotation).
So nowadays as long as you're using API level 11 or above, you should be able to apply the rotation to a wrapper layout node. However, you probably will also have to change the dimensions of the top-level layout to match the dimensions you desire after the rotation. I.e. if you have a portrait view w/ dimensions 800x1280, you'll have to change them to 1280x800 in order for it to line up after rotating to landscape.
Using this library you can rotate whole view hierarchy https://github.com/rongi/rotate-layout
Like this
This is what has worked for me in general.
private void init() {
setRotation(90f);
}
public YourViewOrViewGroup(final Context context) {
super(context);
init();
}
... (all the View/ViewGroup constructors) ...
@Override
protected void onLayout(final boolean changed, final int l, final int t, final int r, final int b) {
super.onLayout(changed, l, t, r, b);
final int width = getWidth();
final int height = getHeight();
final int offset = Math.abs(width - height) / 2;
setTranslationX(-offset);
setTranslationY(offset);
}
@Override
protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
super.onMeasure(heightMeasureSpec, widthMeasureSpec);
}
What you want to do is swap the width with height and then put the X & Y offsets so that the view becomes full screen after the rotation.
The above is a 'landscape'-rotated version. To achieve a landscape inverted just apply 270-deg rotation. You can either modify code within the snippet or apply the rotation outside in a more generic way, i.e
final YourViewOrViewGroup layout = inflater.inflate(...);
if (currentOrientation.isInverted()) {
layout.setRotation(layout.getRotation + 180f);
}
this way you are able to embed the rotated View/ViewGroup within the xml definition and inflate 'port' and 'land' versions while the screen orientation changes, but this seems out of this topic.
Edit: actually it is much better to defer the offset setting until at least one layout pass is over. This is due the fact that in my case after first onMeasure() the view would be drawn (before the offsets were set). Eventually it could be experienced as glitching because the view/layout would not get drawn within the final bounds at first. (updated the snippet)