【问题标题】:ListView position is always retained when changing orientation in a Fragment在 Fragment 中更改方向时,始终保留 ListView 位置
【发布时间】:2014-10-09 22:40:55
【问题描述】:

现在,我确信这对许多人来说听起来很奇怪,但是我的 ListView 在旋转我的设备时始终保持其位置存在问题。这并不是一个特别糟糕的行为(这是我的最终目标,当用户旋转他们的设备时让它记住 ListView 的位置),更多的是似乎没有理由 why 它保留了位置。我从来没有告诉它这样做!即使我尝试强制更改 ListView 上的自定义适配器,它也会更新内部信息(列表项),但仍保留元素的位置。

经过进一步测试,如果我尝试做一个延迟的Runnable(大约300ms延迟),我可以成功改变ArrayAdapter并且位置如预期重置到顶部。

为什么在Fragment创建期间(onCreateView、onActivityCreated等)强制ListView改变位置?

这里有一些代码:

public class MainFragment extends Fragment {
ListView list;
ArrayList<String> skinslist;
ArrayList<File> files;
ArrayList<Integer> heights;
File directory;
String[] listitems;
LinearLayout skin_list_error;
SkinListAdapter adapter;
SwipeRefreshLayout swipeLayout;
View view;

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    setHasOptionsMenu(true);
    listitems = getResources().getStringArray(R.array.TestStrings);
    list = (ListView) view.findViewById(R.id.skin_list);
    skin_list_error = (LinearLayout) view.findViewById(R.id.skin_list_error);

    //Initialize list items
    if (isExternalStorageWritable() && isExternalStorageReadable()) {
        directory = new File(Environment.getExternalStorageDirectory());
        //File directory = new File(getActivity().getFilesDir(), "Mine");
        directory.mkdir();
        CreateNoMediaFile.CreateNoMedia(directory);
        File[] filedirectory = directory.listFiles();

        Arrays.sort(filedirectory, new Comparator<File>(){
            public int compare(File f1, File f2)
            {
                return Long.valueOf(f2.lastModified()).compareTo(f1.lastModified());
            } });

        skinslist = new ArrayList<String>();
        files = new ArrayList<File>();
        heights = new ArrayList<Integer>();
        for (File f : filedirectory) {
            String filename = f.getName();
            if (filename.endsWith(".png")) {
            skinslist.add(f.getName().substring(0, filename.length() - 4));
            files.add(f);
            }
        }
        listitems = skinslist.toArray(new String[skinslist.size()]);
            adapter = new SkinListAdapter(this.getActivity(), listitems, files, heights);
            list.setAdapter(adapter);
    } else {
        Toast.makeText(getActivity(), "Error: Couldn't access phone storage", Toast.LENGTH_LONG).show();
        list.setVisibility(ListView.GONE);
        skin_list_error.setVisibility(LinearLayout.VISIBLE);
    }
    //Finish initializing list items

    swipeLayout = (SwipeRefreshLayout) view.findViewById(R.id.swipe_container);
    swipeLayout.setOnRefreshListener(new OnRefreshListener() {

        @Override
        public void onRefresh() {
            refreshSkins(false);
        }

    });
    swipeLayout.setColorScheme(R.color.refresh_initial_color, 
            R.color.refresh_initial_color, 
            R.color.refresh_initial_color, 
            R.color.refresh_initial_color);

}

这里是视图膨胀的地方:

    @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    view = inflater.inflate(R.layout.skinlist, container, false);
    return view;
}

【问题讨论】:

  • 你在哪里给view赋值?我想在onCreateView(),你能把它的代码贴出来吗?
  • 当然!我刚刚将它添加到主帖中。
  • 你为什么从onCreateView()打电话给super.onCreate()
  • 嗯...我认为这是必要的。我将其删除并再次尝试(仅作为测试)。遗憾的是,结果相同。
  • @Phascinate 我认为问题是由于调用了错误的超类(super.onCreate() vs super.onCreateView()

标签: android


【解决方案1】:

FragmentManager 在其moveToState() 方法中保存和加载片段的视图状态。 (搜索saveFragmentViewState(f)f.restoreViewState())。

saveFragmentViewState() 最终为层次结构中的所有视图调用View.onSaveInstanceState(),因此它保存了ListView 滚动位置、EditText 内容等等。

更新:corresponding documentation(关于Activity,但Fragment 生命周期由Activity 生命周期指导):

然而,即使你什么都不做也没有实现onSaveInstanceState(),一些Activity的状态会被Activity类默认的onSaveInstanceState()实现恢复。具体来说,默认实现为布局中的每个视图调用相应的 onSaveInstanceState() 方法,这允许每个视图提供有关其自身的信息,这些信息应该被保存。几乎 Android 框架中的每个小部件都适当地实现了此方法,以便在重新创建活动时自动保存和恢复对 UI 的任何可见更改。例如,EditText 小部件保存用户输入的任何文本,而 CheckBox 小部件保存它是否被选中。您需要做的唯一工作是为每个要保存其状态的小部件提供唯一 ID(带有 android:id 属性)。如果小部件没有 ID,则系统无法保存其状态。

【讨论】:

  • 非常感谢!令人惊讶的是,我从未了解过这一点,更不用说活动也是如此。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-30
  • 1970-01-01
相关资源
最近更新 更多