web-dev-qa-db-ja.com

レイアウトを再作成せずに方向変更時にビューを回転させる方法は?

この質問は以前に尋ねられた here ですが、その答えは正しくありません。画面の向きを変更したときに一部のビューを回転させたいのですが、レイアウトは変更しないでください。現在の向きに応じて、90、180、270、または360度回転する必要があります(_SCREEN_ORIENTATION_LANDSCAPE_、_SCREEN_ORIENTATION_PORTRAIT_、_SCREEN_ORIENTATION_REVERSE_LANDSCAPE_、_SCREEN_ORIENTATION_REVERSE_PORTRAIT_)。

これは私が達成したいことです:

LayoutExample

私が言及したリンクの答えは、_layout-land_で新しい異なるレイアウトを作成する必要があることを述べています。明らかに、これは私が望むものではありません。アクティビティを再作成したり、レイアウトの向きを変更したりしたくありません。一部のビューのみを回転させ、向きが変わっても他のビューは変更しないようにします。

特定のビューの回転とレイアウト全体の変更または再作成(方向変更時の両方)

この link の答えを使用すると、このメソッドで現在の画面の向きを取得できます。

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

向きを変えるとき、私はこのような簡単なことをしたいと思います:

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

私の質問を言い換える別の方法は、「レイアウトを変更せずにonConfigurationChanged()メソッドの向きの変更を検出する方法はありますか?」です。問題は、レイアウトの向きの変更を既に無効にしている場合、向きの変更を検出できないことです。

誰もがそれがどのように行われるか知っていますか?私は完全に間違った手順を実行した可能性があり、私が望むものを達成するには加速度計センサーまたはそれに類似したものを使用する必要があると思います。

15
Hussein El Feky

OrientationEventListenerを使用してみてください。 onConfigurationChangedおよびAndroid:configChanges="orientation|keyboardHidden|screenSize"を使用する必要はありません。

AndroidManifest.xmlのアクティビティにAndroid:screenOrientation="portrait"を設定する必要があります。これが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);
        }
    }
}
}

これにより、orientationが約45、135などの場合にローテーションが頻繁に行われるのを防ぐこともできます。

15
mirekkomis

基本は実際にははるかに簡単です。 ランタイム変更の処理 をご覧ください。

まず最初に、設定によって

Android:configChanges="orientation|keyboardHidden|screenSize"

アクティビティタグのマニフェストで、向きの変更を自分で処理できます。 (orientationで十分なはずですが、それだけではイベントが発生しない場合があります。)

次にonCreateをスキップし、代わりにonConfigurationChangedが呼び出されます。このメソッドを上書きし、ここでレイアウトの変更を適用します。ここでlinearLayoutsの方向を変更するか、または異なる画面自体のカスタムビュー処理レイアウトを使用するかは、ユーザー次第であり、実装によって異なります。

それがpossilbeでさえあるなら、アニメーションは少しトリッキーになります。クイック検索では そうではない と表示されます。


コメントの更新「レイアウトを回転させるのではなく、一部のビューのみを回転させたい」

理論的には独自のレイアウトを作成し、子ビューの描画を処理することが可能です。私はそれを試しましたが、適切な時間で結果を出すことができませんでしたが、あなたがする必要があるでしょう:

  • 最後の測定値を保持しますビューまたは同様のアプローチでタグを使用して、最後の測定値とレイアウトを保持します。これにより、向きが変わった後に、差分をとることができます。
  • 方向の変更を待つ:トリガー回転した描画-キャンバスを回転し、previousディメンション、およびbefore以前の子ビューを描画し、
  • アニメーションを開始lastからnew値、キャンバスを最後から新しいレイアウトに回転

これが私のやり方です。

1
David Medenjak