如何在旋转后正确恢复视图状态

6

我正在试图手动处理复杂视图的旋转,包括恢复适当的位置和大小。目前,我正在尝试在onLayout中完成它(欢迎更好的想法)。有时它表现良好,但经常第一次旋转就错位或视图没有绘制子项。

private int oldOrientation = -1;

  /**
   * Override method to configure the dragged view and secondView layout properly.
   */
  @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    Log.e("mylayout", "onLayout " + df.format(new Date(Calendar.getInstance().getTimeInMillis())));
    if (isInEditMode()) {
      super.onLayout(changed, left, top, right, bottom);
    } else {
      dragView.setVisibility(INVISIBLE);
      if (isDragViewAtTop() && (oldOrientation != getResources().getConfiguration().orientation || oldOrientation == -1)) {
        dragView.layout(left, top, right, transformer.getOriginalHeight());
        secondView.layout(left, transformer.getOriginalHeight(), right, bottom);
        ViewHelper.setY(dragView, top);
        ViewHelper.setY(secondView, transformer.getOriginalHeight());
        ViewHelper.setX(dragView, left);
        ViewHelper.setX(secondView, left);
        oldOrientation = getResources().getConfiguration().orientation;
      } else if (isClosedAtLeft() && (
          oldOrientation != getResources().getConfiguration().orientation
              || oldOrientation == -1)) {
        dragView.layout(left, top, right, transformer.getOriginalHeight());
        secondView.layout(left, transformer.getOriginalHeight(), right, bottom);
        ViewHelper.setY(dragView, top);
        ViewHelper.setY(secondView, transformer.getOriginalHeight());
        ViewHelper.setX(dragView, left);
        ViewHelper.setX(secondView, left);
        closeToLeft();
        oldOrientation = getResources().getConfiguration().orientation;
      } else if (isClosedAtRight() && (
          oldOrientation != getResources().getConfiguration().orientation
              || oldOrientation == -1)) {
        dragView.layout(left, top, right, transformer.getOriginalHeight());
        secondView.layout(left, transformer.getOriginalHeight(), right, bottom);
        ViewHelper.setY(dragView, top);
        ViewHelper.setY(secondView, transformer.getOriginalHeight());
        ViewHelper.setX(dragView, left);
        ViewHelper.setX(secondView, left);
        closeToRight();
        oldOrientation = getResources().getConfiguration().orientation;
      } else if ((oldOrientation != getResources().getConfiguration().orientation
          || oldOrientation == -1)) {
        dragView.layout(left, top, right, transformer.getOriginalHeight());
        secondView.layout(left, transformer.getOriginalHeight(), right, bottom);
        ViewHelper.setY(dragView, top);
        ViewHelper.setY(secondView, transformer.getOriginalHeight());
        ViewHelper.setX(dragView, left);
        ViewHelper.setX(secondView, left);
        smoothSlideTo(SLIDE_BOTTOM);
        oldOrientation = getResources().getConfiguration().orientation;
      }
      dragView.setVisibility(VISIBLE);
    }
  }

在这段代码中,我试图在旋转后恢复初始状态,当 onLayout 被调用时将其移回到旋转前的位置(有 4 种状态:左侧屏幕外,右侧屏幕外,屏幕顶部或右下角)。
编辑:
<?xml version="1.0" encoding="utf-8"?>
<manifest
    package="com.github.pedrovgs.sample"
    xmlns:android="http://schemas.android.com/apk/res/android">

    <uses-sdk android:minSdkVersion="8" />

    <!-- Permissions -->

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

    <uses-feature
        android:glEsVersion="0x00020000"
        android:required="true" />

    <!-- Application configuration -->

    <application
        android:name=".DraggablePanelApplication"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme">

        <!-- Maps API KEY -->

        <meta-data
            android:name="com.google.android.maps.v2.API_KEY"
            android:value="AIzaSyC1rMU-mkhoyTvBIdTnYU0dss0tU9vtK48" />

        <!-- Main Activity -->

        <activity
            android:name=".activity.MainActivity"
            android:configChanges="keyboardHidden|orientation|screenSize"
            android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <!-- Places sample -->

        <activity
            android:name=".activity.PlacesSampleActivity"
            android:configChanges="keyboardHidden|orientation|screenSize"

            android:label="@string/places_sample_activity_title" />

        <!-- TV Shows sample -->

        <activity
            android:name=".activity.TvShowsActivity"
            android:label="@string/tv_shows_sample_activity_title" />


        <!-- Youtube Sample -->

        <activity
            android:name=".activity.YoutubeSampleActivity"
            android:configChanges="keyboardHidden|orientation|screenSize"

            android:label="@string/youtube_sample_activity_title" />


        <!-- Video Sample -->

        <activity
            android:name=".activity.VideoSampleActivity"
            android:configChanges="keyboardHidden|orientation|screenSize"

            android:label="@string/video_sample_activity_title" />

        <meta-data
            android:name="com.google.android.gms.version"
            android:value="@integer/google_play_services_version" />

    </application>

</manifest>

示例活动XML

<?xml version="1.0" encoding="utf-8"?>

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:draggable_panel="http://schemas.android.com/apk/res-auto"
    android:id="@+id/fl_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

  <!-- Movie Thumbnail -->

  <ImageView
      android:id="@+id/iv_thumbnail"
      android:layout_width="fill_parent"
      android:layout_height="fill_parent"
      style="@style/image_view"/>

  <!-- DraggablePanel -->

  <com.github.pedrovgs.DraggablePanel
      android:id="@+id/draggable_panel"
      android:layout_width="fill_parent"
      android:layout_height="fill_parent"
      draggable_panel:x_scale_factor="@dimen/x_scale_factor"
      draggable_panel:y_scale_factor="@dimen/y_scale_factor"
      draggable_panel:top_fragment_height="@dimen/top_fragment_height"
      draggable_panel:top_fragment_margin_right="@dimen/top_fragment_margin"
      draggable_panel:top_fragment_margin_bottom="@dimen/top_fragment_margin"
      draggable_panel:enable_horizontal_alpha_effect="false"/>

</FrameLayout>

为什么你不使用清单文件呢?如果你在旋转时没有做特殊处理,那么可以忽略旋转。 - SRB Bans
好的,抱歉我误会了。 - SRB Bans
你读过 https://dev59.com/GnA65IYBdhLWcg3w9DqF#3542895 吗? - Hugo Gresse
@HugoGresse 是的,但就像我在悬赏中所说的那样,saveInstanceState在手动旋转处理程序上不会被调用。 - Yarh
你能把你的清单添加到问题中吗? - Hugo Gresse
显示剩余10条评论
5个回答

2
如果您想深入布局您的View,则不需要在您的ViewActivity中使用此内容。
 android:configChanges="keyboardHidden|orientation|screenSize"

如果在旋转之后设置了这个属性,Android 就不会过多地关注是否重新创建你的 Activity 以便重新绘制、重新测量、重新定位等等。

因此,如果你在一个 [10 100] 的位置放置一个 ImageView,在旋转后,你的 ImageView 将被认为是位于 [10 100] 的位置,有时甚至可能给你一些奇怪的屏幕外坐标。


没有它,视频流会出现暂停。 - Yarh

1
你扩展了一个ViewGroup而不是View,但是在xml或代码中没有添加任何child到DraggableView。我没有看到任何addChild或任何与child相关的代码在DraggableView中。你使用了topFragment、bottomFragment等,并使用addFragmentToView()在ViewGroup内进行fragment事务。这是个坏主意!
我知道这很难且耗时。但你需要退后一步,考虑这个视图的设计。我强烈建议你将这些topFragment等视为DraggableView的子项,而不是在此View中具有FragmentManager并执行addTransaction。
一旦您将片段添加为子项到您的ViewGroup中,许多复杂性就会消失。我从过去的经验中这样说。onLayout()用于排列ViewGroup内的Child Views。一旦您旋转设备,onLayout()将再次被调用,并按您想要的方式排列子视图。这将非常简单。一旦您开始像这样进行概念化,拖动操作将变得更加简单。
如果您认为在ViewGroup中将Framgents作为子项是荒谬的,请看看ViewPager代码here。这使用片段作为输入,但仍将它们视为布局的子项。
  1. 尝试在onLayout()中处理所有与位置相关的事情。
  2. 不要在onSaveInstanceState()中保存位置数据。只保存textdrawable数据。
  3. 最好不要覆盖onCofigurationChanged()

你现在可能做不到,但从长远来看,你可能想要重构并按照这种方式进行。

记住onLayout()的真正目的:

当此视图需要为每个子视图分配大小和位置时,从布局中调用。具有子项的派生类应重写此方法,并在其每个子项上调用布局。


0
尝试使用onConfigrationChange()重写方法,该方法将处理旋转。

0

我想这是一个不错的方式

@Override
    protected Parcelable onSaveInstanceState() {
        Parcelable superState = super.onSaveInstanceState();
        return new YourParcelableObject(superState, yourValues);
    }

    @Override
    protected void onRestoreInstanceState(Parcelable state) {
        YourParcelableObject savedState = (SavedState) state;
        super.onRestoreInstanceState(savedState.getSuperState());

        //restote other values from YourParcelableObject
    }

0

假设您正在创建自己的自定义视图。如果是这样,您应该使用View类提供的标准机制。

@Override
protected void onRestoreInstanceState(Parcelable state) {
    // Restore state
}

@Override
protected Parcelable onSaveInstanceState() {
    // Save state
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接