web-dev-qa-db-ja.com

ビュー階層を90度回転

私はすべての子を90度回転させることになっているFrameLayoutのサブクラスに取り組んでいます。これは、アクティビティを横向きにすることで、Android 2.1以前の横向きのみのカメラの制限を克服するために行っていますが、カメラオーバーレイをこのframelayoutオーバーレイに配置して表示しますまるで肖像画のように( これがLayarのやり方です )これを達成するために、私は Jeff Sharkeyのコード をビューの回転に適応させています。私の問題は、フレームレイアウトですが、新しいサイズに合わせてサイズを変更することはできません。したがって、g1では、横向きの480x320カメラビューを介した320x480ポートレートビューの代わりに、中央に320x320ボックスが表示されます。

ここに私のコードがあります:

public class RotateLayout extends FrameLayout {
    private Matrix mForward = new Matrix();
    private Matrix mReverse = new Matrix();
    private float[] mTemp = new float[2];

    public RotateLayout(Context context) {
        super(context);
    }

    public RotateLayout(Context context, AttributeSet attrs) {
        super(context, attrs);

    }


    /* (non-Javadoc)
     * @see Android.widget.FrameLayout#onMeasure(int, int)
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //This didn't work:
        //super.onMeasure(heightMeasureSpec, widthMeasureSpec);
    }

    /* (non-Javadoc)
     * @see Android.widget.FrameLayout#onSizeChanged(int, int, int, int)
     */
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        canvas.rotate(270, getWidth()/2, getHeight()/2);
        //This code will stretch the canvas to accommodate the new screen size. This is not what I want.
        //float scaleX=(float)getHeight()/getWidth();
        //float scaleY=(float)getWidth()/getHeight();
        //canvas.scale(scaleX, scaleY,  getWidth()/2, getHeight()/2);
        mForward = canvas.getMatrix();
        mForward.invert(mReverse);
        canvas.save();
        canvas.setMatrix(mForward); //This is the matrix we need to use for proper positioning of touch events
        super.dispatchDraw(canvas);
        canvas.restore();
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        final float[] temp = mTemp;
        temp[0] = event.getX();
        temp[1] = event.getY();

        mReverse.mapPoints(temp);

        event.setLocation(temp[0], temp[1]);
        return super.dispatchTouchEvent(event);
    }
}

ビューのX次元とY次元を切り替えるためにOnMeasureをオーバーライドしようとしましたが、それを機能させることができませんでした。あなたが提供できる助けは大歓迎です。

35
QRohlf

私は同じ問題を抱えていて、それをなんとか解決しました。各ビューまたはレイアウトを手動で回転する代わりに、LayoutAnimationControllerを使用しました。

最初に、/ res/anim /に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>

次に、アクティビティのonCreateで、

  @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);
 }

カメラプレビュービュー(SurfaceHolder)の上にある要素を回転させる場合は、SurfaceHolderの上にFrameLayoutを配置し、すべての要素をそのFrameLayoutに配置して、レイアウトを「MyScreen_ContentLayout」と呼びます。できた.

誰かを助けてくれて、すべてをまとめるのにかなり時間がかかったと思います。

39
Georg

APIレベル11以降を使用すると、メソッドsetRotation(degreesFloat);を使用してプログラムでビューの回転を変更したり、XML属性Android:rotation=""でXMLを変更します。ビューの回転のXまたはY値のみを変更するためのメソッド/属性もあります: Android Docs-View(setRotation)

したがって、今日では、APIレベル11以上を使用している限り、ラッパーレイアウトノードに回転を適用できるはずです。ただし、おそらく、トップレベルレイアウトのサイズを変更して、回転後に必要なサイズに一致させる必要があります。つまり縦800x1280のポートレートビューがある場合、横に回転した後に整列させるためにそれらを1280x800に変更する必要があります。

7
Alex Ross

このライブラリを使用すると、ビュー階層全体を回転できます https://github.com/rongi/rotate-layout

このような

enter image description here

3

これは私にとって一般的に働いていることです。

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);
}

あなたがしたいのは、幅を高さと入れ替えてから、回転後にビューがフルスクリーンになるようにXとYのオフセットを配置することです。

上記は「風景」を回転させたバージョンです。横向きに反転させるには、270度の回転を適用します。スニペット内のコードを変更するか、より一般的な方法で外部に回転を適用できます。

final YourViewOrViewGroup layout = inflater.inflate(...);
if (currentOrientation.isInverted()) {
    layout.setRotation(layout.getRotation + 180f);
}

このようにして、回転したView/ViewGroupをxml定義内に埋め込み、画面の向きが変わっている間に「ポート」バージョンと「ランド」バージョンを膨らませることができますが、これはこのトピックから外れているようです。

編集:実際には、少なくとも1つのレイアウトパスが終了するまでオフセット設定を延期することをお勧めします。これは、私の場合、最初のonMeasure()の後(オフセットが設定される前)にビューが描画されるためです。最終的には、ビュー/レイアウトが最初に最終的な境界内に描画されないため、グリッチとして発生する可能性があります。 (スニペットを更新)

1
foo

OnMeasureの1行を忘れたと思います。

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

ここでの垂直シークバーのコードから取得: Androidで動作する垂直シークバーを取得するにはどうすればよいですか?

画面の正しいサイズにするには、getMeasuredHeight()をいじる必要があるかもしれません。

0
Li_W

ビュールートの子クリッピングをオフにしてみてください。RotateLayoutの親でsetClipChildren(false)を呼び出し、RotateLayoutのonMeasureメソッドで次の行を追加します。

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

私はあなたと基本的に同じ問題を抱えていますが、まだソリューションをテストしていません-明日それを行い、それが正しく機能するかどうかを確認します。

0
DoDo