Как поворачивать представления при изменении ориентации без повторной компоновки?
Этот вопрос задан до здесь, но его ответ неверен. Я хотел бы повернуть некоторые взгляды на изменение ориентации экрана, но я хочу сохранить макет без изменений. Они должны вращаться на 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 или что-то похожее на это, чтобы достичь того, что я хочу, поэтому, пожалуйста, помогите мне.
Ответы
Ответ 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 здесь или используете собственный макет управления просмотром для разных экранов, зависит от вас и зависит от вашей реализации.
Анимация будет немного сложнее, если это даже возможно. Быстрый поиск говорит это не.
Обновить для комментариев "Я просто хочу повернуть некоторые виды, а не вращать макет"
В теории можно создать свой собственный макет и обработать чертеж ваших дочерних представлений. Я просто попробовал, но не смог произвести никаких результатов в соответствующее время, но что вам нужно сделать:
- сохранить последние измеренные значения использовать теги в представлении или аналогичных подходах, чтобы сохранить последние измерения и макеты, чтобы после изменения ориентации вы могли различать
- ожидание изменения ориентации: триггер поворотного рисунка - поворот холста, расположение представлений с параметрами предыдущий и рисование дочерних представлений, где они были раньше, и
- начать анимацию интерполировать от последнего к новым значениям, поворачивая холст от последнего к новому макету
Вот как я это сделаю.