Rotate View Hierarchy 90 degrees

后端 未结 6 946
予麋鹿
予麋鹿 2020-11-28 03:33

I am working on a subclass of FrameLayout that is supposed to rotate all of its children by 90 degrees. I am doing this to overcome the landscape-only camera limitation pres

相关标签:
6条回答
  • 2020-11-28 04:13

    I think you forgot one line in your onMeasure.

    @Override
    protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         super.onMeasure(heightMeasureSpec, widthMeasureSpec);
         setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth());
    }
    

    Taken from the code for a vertical seekbar here: How can I get a working vertical SeekBar in Android?

    You might need to fiddle with the getMeasuredHeight() to make it the correct size of your screen.

    0 讨论(0)
  • 2020-11-28 04:13

    Try turning off children clipping of your view root: call setClipChildren(false) on parent of your RotateLayout and in onMeasure method of your RotateLayout put these lines:

    super.onMeasure(heightMeasureSpec, widthMeasureSpec);
    setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth());
    

    I'm having basically the same problem as you and I still haven't tested my solution - I'll do it tomorrow and tell if it is working correctly.

    0 讨论(0)
  • 2020-11-28 04:14

    Using this library you can rotate whole view hierarchy https://github.com/rongi/rotate-layout

    Like this

    enter image description here

    0 讨论(0)
  • 2020-11-28 04:16

    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)

    0 讨论(0)
  • 2020-11-28 04:21

    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.

    0 讨论(0)
  • 2020-11-28 04:26

    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.

    0 讨论(0)
提交回复
热议问题