【问题标题】:Problems when switching ListView ChoiceMode on screen rotation屏幕旋转时切换 ListView ChoiceMode 的问题
【发布时间】:2011-11-03 14:10:25
【问题描述】:

我正在尝试基于 Android 文档末尾提供的关于 Fragments 的example code 构建一个拆分窗格,基本上是一个包含两个片段的 LinearLayout(所有详细信息都可以在上面的链接中找到):

  • TitlesFragment 显示标题列表
  • DetailsFragment 显示当前选中标题的详细信息

我的问题是发生了以下意外行为:

  1. 我以横向方向启动应用程序:左侧显示标题列表,右侧显示当前所选标题的详细信息(开头的第一个)。李>
  2. 我从标题列表中选择item X:由于 ListView 设置为 CHOICE_MODE_SINGLE 并且其项目实现了 Checkable 接口,因此标题变得突出显示。
  3. 我切换到 纵向 方向(通过旋转设备或模拟器):正如预期的那样,仅显示标题列表并且在此配置中未选择任何项目,因为重新创建了 ListView 并且通过默认设置为CHOICE_MODE_NONE
  4. 我从标题列表中选择item Y:正如预期的那样,一个活动只显示了与所做选择相对应的DetailsFragment
  5. 我切换回横向方向(这是发生意外行为的地方):右侧的DetailsFragment正确显示了item Y的详细信息(已选中纵向),但TitlesFragment 仍将item X显示为选中状态(即在第一次屏幕旋转之前选中的那个)。

当然,我希望在纵向方向上所做的最后一个选择也正确显示在 TitlesFragment 中,否则我最终会出现不一致的突出显示,在显示项目 Y 的详细信息时显示项目 X 已被选中。

我发布了更改ListView模式的相关代码(在'onActivityCreated'内)并设置了所选项目(在'showDetails'方法内):

public static class TitlesFragment extends ListFragment {
boolean mDualPane;
int mCurCheckPosition = 0;

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);

    // Populate list with our static array of titles.
    setListAdapter(new ArrayAdapter<String>(getActivity(),
            android.R.layout.simple_list_item_activated_1, Shakespeare.TITLES));

    // Check to see if we have a frame in which to embed the details
    // fragment directly in the containing UI.
    View detailsFrame = getActivity().findViewById(R.id.details);
    mDualPane = detailsFrame != null && detailsFrame.getVisibility() == View.VISIBLE;

    if (savedInstanceState != null) {
        // Restore last state for checked position.
        mCurCheckPosition = savedInstanceState.getInt("curChoice", 0);
    }

    if (mDualPane) {
        // In dual-pane mode, the list view highlights the selected item.
        getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
        // Make sure our UI is in the correct state.
        showDetails(mCurCheckPosition);
    }
}

@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putInt("curChoice", mCurCheckPosition);
}

@Override
public void onListItemClick(ListView l, View v, int position, long id) {
    showDetails(position);
}

/**
 * Helper function to show the details of a selected item, either by
 * displaying a fragment in-place in the current UI, or starting a
 * whole new activity in which it is displayed.
 */
void showDetails(int index) {
    mCurCheckPosition = index;

    if (mDualPane) {
        // We can display everything in-place with fragments, so update
        // the list to highlight the selected item and show the data.
        getListView().setItemChecked(index, true);

        // Check what fragment is currently shown, replace if needed.
        DetailsFragment details = (DetailsFragment)
                getFragmentManager().findFragmentById(R.id.details);
        if (details == null || details.getShownIndex() != index) {
            // Make new fragment to show this selection.
            details = DetailsFragment.newInstance(index);

            // Execute a transaction, replacing any existing fragment
            // with this one inside the frame.
            FragmentTransaction ft = getFragmentManager().beginTransaction();
            ft.replace(R.id.details, details);
            ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
            ft.commit();
        }

    } else {
        // Otherwise we need to launch a new activity to display
        // the dialog fragment with selected text.
        Intent intent = new Intent();
        intent.setClass(getActivity(), DetailsActivity.class);
        intent.putExtra("index", index);
        startActivity(intent);
    }
}

有人知道如何解决此类问题吗? 提前致谢。

【问题讨论】:

  • 我知道这有点晚了,但我的行为完全相同。我正在真实设备中测试代码,即安装了 API 16 的平板电脑。我放了踪迹,可以看到在showDetails(index) 中,索引是正确的,但setItemChecked(index, true) 没有突出显示正确的标题。

标签: android


【解决方案1】:

两年后,我正在使用 Android v4 支持库中的 Fragment Layout 示例,但我遇到了同样的问题!

这是我想出的唯一一个不需要一直使用CHOICE_MODE_SINGLE 的解决方法:

只需在 TitlesFragment 的 onResume() 方法中添加对 getListView().setItemChecked(mCurCheckPosition, true); 的调用。而且……就是这样!

【讨论】:

    【解决方案2】:

    也许您应该在调用 super.onSaveInstanceState 之前设置 outState 的值?

    @Override
    public void onSaveInstanceState(Bundle outState) {
        outState.putInt("curChoice", mCurCheckPosition);
        super.onSaveInstanceState(outState);
    }
    

    【讨论】:

    • 再次感谢您,但不幸的是,这并不能解决我的问题。似乎 ListView 的“mCheckStates”字段保留了上次设置“CHOICE_MODE_SINGLE”时设置的值,而在设置“CHOICE_MODE_NONE”时所做的任何选择都将被丢弃。此外,我注意到,如果我将 ListView 保留在 'CHOICE_MODE_SINGLE' 中(通过在 'onActivityCreated' 末尾注释掉 'if (mDualPane)'),最后的选择会在屏幕方向更改时正确保存和恢复。但我不想以纵向突出显示...还有其他想法吗?
    • 我的假设似乎是正确的,即在“CHOICE_MODE_NONE”中所做的选择对 ListView 的“mCheckStates”字段没有影响,这在某种程度上似乎是合理的。我发现以下(可怕的)解决方法支持了我的假设:如果我添加这些代码行: getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE); getListView().setItemChecked(index, true); getListView().setChoiceMode(ListView.CHOICE_MODE_NONE);在“showDetails”方法的“else”开头,一切正常。我确信必须有一个更清洁的解决方案......
    • 我在运行 3.1 的平板电脑上测试了 SDK 版本 13 的示例代码,它运行良好。我没有得到不正确的行为。也许您的模拟器需要更新?
    • 其实SDK版本13的代码也一直设置ListView的模式为CHOICE_MODE_SINGLE,不只是双屏。我认为您需要获取最新的示例代码。你的有点不同。
    • 你能更好地解释一下你到底做了什么吗?如果您在“android-compatibility/v13/samples”中引用“Support13Demos”,我没有在其中找到任何“TitlesFragment”类(顺便说一句,是否可以在 3.1 的平板电脑上运行针对 API 级别 13 的代码,哪个有 API 级别 12?)... 然而,在 3.2 模拟器上的 API Demos 中,App/Fragment/Layout 示例具有与我描述的相同的错误行为。几天前,我还将我的模拟器更新到了最新版本。我错过了什么吗?
    【解决方案3】:

    我在该代码上遇到了同样的问题,作为解决方法,我在 onStart 方法上调用 setItemChecked

    @Override
    public void onStart() {
        super.onStart();
        if (mDualPane) {
            getListView().setItemChecked(mCurCheckPosition, true);
        }
    }
    

    或者正如 LearningNerd 所说,在 onResume() 中进行操作

    【讨论】:

      【解决方案4】:

      如果您将android:configChanges="orientation" 放在清单文件的活动标记中,您的应用将忽略旋转但仍会呈现相关布局。

      【讨论】:

      • 感谢您的快速回复。我知道这样的功能,但这不是预期的行为。实际上,我希望 Activity 知道方向变化,因为只有标题必须以纵向显示,而标题和详细信息必须以横向显示。您对如何实现这一点有什么建议吗?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-22
      • 1970-01-01
      • 2021-08-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多