在片段中更改方向时,始终会保留ListView位置

时间:2014-10-09 22:40:56

标签: android

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

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

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

以下是一些代码:

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;
}

1 个答案:

答案 0 :(得分:2)

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

saveFragmentViewState()最终会针对层次结构中的所有视图调用View.onSaveInstanceState(),因此会保存ListView滚动位置,EditText内容以及更多内容。

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

  

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