Подтвердить что ты не робот

Как поворачивать представления при изменении ориентации без повторной компоновки?

Этот вопрос задан до здесь, но его ответ неверен. Я хотел бы повернуть некоторые взгляды на изменение ориентации экрана, но я хочу сохранить макет без изменений. Они должны вращаться на 90, 180, 270 или 360 градусов в соответствии с текущей ориентацией (SCREEN_ORIENTATION_LANDSCAPE, SCREEN_ORIENTATION_PORTRAIT, SCREEN_ORIENTATION_REVERSE_LANDSCAPE, SCREEN_ORIENTATION_REVERSE_PORTRAIT).

Этого я хочу достичь:

LayoutExample

В ответной ссылке я упомянул, что я должен создать новый разный макет в layout-land. Ясно, что это не то, что я хочу. Я не хочу воссоздавать активность или менять ориентацию макета. Я просто хочу повернуть некоторые виды и не менять другие представления при изменении ориентации.

Существует огромное различие между вращением определенных видов и изменением или воссозданием всей компоновки (как при изменении ориентации).

Используя ответ в этой ссылке, я смогу получить текущую ориентацию экрана с помощью этого метода:

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 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 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() без изменения макета?". Проблема в том, что он не сможет обнаружить изменения ориентации, если я уже отключу изменение ориентации макета.

Кто-нибудь знает, как это делается? Я мог бы полностью пройти через неправильные шаги, и я думаю, что мне нужно будет использовать Accelerometer Sensor или что-то похожее на это, чтобы достичь того, что я хочу, поэтому, пожалуйста, помогите мне.

4b9b3361

Ответ 1

Попробуйте использовать OrientationEventListener. Вам не нужно использовать onConfigurationChanged и android:configChanges="orientation|keyboardHidden|screenSize".

Вам нужно установить android:screenOrientation="portrait" для активности в AndroidManifest.xml. Вот мое решение с 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... и т.д. Надеюсь, что это поможет.

Ответ 2

Основы на самом деле намного проще. Посмотрите Обработка изменений времени выполнения.

Прежде всего, установив

android:configChanges="orientation|keyboardHidden|screenSize"

в вашем манифесте вашего тега активности вы можете самостоятельно изменить ориентацию. (orientation должно быть достаточно, но иногда возникают проблемы, когда событие не срабатывает только с этим.)

Затем пропустите onCreate и вместо этого вызывается onConfigurationChanged. Перезапишите этот метод и примените изменения в макете. Независимо от того, измените ли вы свою ориентацию linearLayouts здесь или используете собственный макет управления просмотром для разных экранов, зависит от вас и зависит от вашей реализации.

Анимация будет немного сложнее, если это даже возможно. Быстрый поиск говорит это не.


Обновить для комментариев "Я просто хочу повернуть некоторые виды, а не вращать макет"

В теории можно создать свой собственный макет и обработать чертеж ваших дочерних представлений. Я просто попробовал, но не смог произвести никаких результатов в соответствующее время, но что вам нужно сделать:

  • сохранить последние измеренные значения использовать теги в представлении или аналогичных подходах, чтобы сохранить последние измерения и макеты, чтобы после изменения ориентации вы могли различать
  • ожидание изменения ориентации: триггер поворотного рисунка - поворот холста, расположение представлений с параметрами предыдущий и рисование дочерних представлений, где они были раньше, и
  • начать анимацию интерполировать от последнего к новым значениям, поворачивая холст от последнего к новому макету

Вот как я это сделаю.