#android
Вопрос:
Я хочу использовать разную компоновку для альбомного и портретного экрана. В портрете я хочу использовать HorizontalScrollView, который прокручивается горизонтально. В альбомной ориентации я хочу использовать ScrollView для вертикальной прокрутки.
Они хорошо работают, за исключением того, что, когда я переключаю направление своего устройства с портретной на альбомную, он падает, жалуясь, что HorizontalScrollView не может быть перенесен в ScrollView.
Должен ли он перезагрузить макет вместо приведения компонентов? Стек весь в коде для Android, а не в моем коде, поэтому я не знаю, что с ним делать. Пожалуйста, помогите, спасибо!
Это файл макета в файле res/layout:
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<HorizontalScrollView
android:id="@ id/hsv_tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#d0d0d0"
android:visibility="visible"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#b0b0b0"
android:orientation="horizontal"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@ id/tools_draw"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:layout_marginRight="3dp"
android:text="@string/tools_draw"
android:textSize="10sp"
app:drawableTopCompat="@drawable/tools_new" />
И это макет в res/макет-земля:
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ScrollView
android:id="@ id/hsv_tools"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="#d0d0d0"
android:visibility="visible"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#b0b0b0"
android:orientation="vertical"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent">
Сбой происходит, когда я поворачиваю мобильный телефон, трассировка стека:
java.lang.RuntimeException: Unable to start activity ComponentInfo: java.lang.ClassCastException: android.widget.HorizontalScrollView$SavedState cannot be cast to android.widget.ScrollView$SavedState
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2604)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2670)
at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:4370)
at android.app.ActivityThread.access$1200(ActivityThread.java:178)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1523)
at android.os.Handler.dispatchMessage(Handler.java:111)
at android.os.Looper.loop(Looper.java:207)
at android.app.ActivityThread.main(ActivityThread.java:5845)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:907)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:768)
Caused by: java.lang.ClassCastException: android.widget.HorizontalScrollView$SavedState cannot be cast to android.widget.ScrollView$SavedState
at android.widget.ScrollView.onRestoreInstanceState(ScrollView.java:1834)
at android.view.View.dispatchRestoreInstanceState(View.java:14953)
at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:3249)
at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:3255)
at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:3255)
at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:3255)
at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:3255)
at android.view.View.restoreHierarchyState(View.java:14931)
at com.android.internal.policy.PhoneWindow.restoreHierarchyState(PhoneWindow.java:2068)
at android.app.Activity.onRestoreInstanceState(Activity.java:1036)
at android.app.Activity.performRestoreInstanceState(Activity.java:991)
at android.app.Instrumentation.callActivityOnRestoreInstanceState(Instrumentation.java:1170)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2577)
Комментарии:
1. Пожалуйста, поделитесь своим кодом и трассировкой стека, чтобы мы могли помочь.
2. Я в замешательстве, почему вы пытаетесь использовать вид горизонтальной прокрутки для вертикальной прокрутки и почему вы не можете использовать только вид прокрутки для этой вертикальной прокрутки?
3. Извините за опечатку в описании. Я имею в виду, что на портретном экране я хочу, чтобы горизонтальный экран прокрутки прокручивался горизонтально, на альбомном экране я хочу, чтобы вид прокрутки прокручивался вертикально.
Ответ №1:
Вопреки тому, что вы можете подумать, HorizontalScrollView не наследуется от ScrollView.
У них обоих есть внутренние классы SavedState, но они разные.
Когда вы меняете ориентацию с портретной на альбомную или наоборот, это приводит к тому, что ваш вид прокрутки с идентификатором hsv_tools сохраняет состояние экземпляра, используя его сохраненное состояние.
Затем, когда Действие/Фрагмент будет воссоздан, ваш макет будет увеличен, а состояние восстановлено, и поскольку вы используете один и тот же идентификатор как для представления прокрутки, так и для представления горизонтальной прокрутки, сохраненное состояние, помещенное в пакет, будет для представления прокрутки, как это было до изменения ориентации.
Это то, что приводит к исключению ClassCastException.
Я бы предложил, поскольку у вас совершенно другой тип представления прокрутки в зависимости от портретного или ландшафтного режима, предоставить разные идентификаторы для каждого, а затем обработать это в коде, сначала проверив наличие представления в макете, и если оно есть, вы знаете, с каким из них вы имеете дело.
Ответ №2:
Я не думаю, что кто-нибудь сможет помочь вам с просмотром журнала выполнения и кода, не могли бы вы скопировать оба в свой вопрос?
Извините, что не хватило репутации, чтобы прокомментировать.
Ответ №3:
Просто некоторые дальнейшие выводы, основанные на ответе Майкла.
Поэтому, когда у меня разные макеты для портретной и альбомной ориентации, все именованные представления должны быть одного типа в портретной и альбомной ориентации, иначе произойдет сбой при повороте экрана пользователем. Это необязательно для безымянных представлений.
Для моей проблемы я создал как HorizontalScrollView, так и ScrollView и добавил суффикс _hsv и _sv в идентификатор. Для портрета _sv не используется, поэтому установите видимость в «Пропало», для ландшафта установите _hsv видимость в «Пропало».
В коде я проверяю, какой из них используется, проверяя видимость == Вид.Ушел или нет. Это решает все мои проблемы.
Спасибо Майклу и всем остальным!