Android:ListView在标签和背面之间切换时恼人地滚动到顶部

时间:2013-12-19 23:40:57

标签: android listview android-cursoradapter android-cursorloader

我在附加到CursorAdapter的Fragment中有一个ListView。片段有setRetainInstance(true)。在Fragment的onCreate()方法下,我实例化了CursorAdapter(将其存储在变量adapter中)。然后我在Fragment的listView.setAdapter(adapter)方法下调用onCreateView。 CursorAdapter中的Cursor由CursorLoader加载。在我的LoaderCallbacks'onLoadFinished()中,我致电adapter.swapCursor(cursor)

总之:似乎所有内容都已到位,以便在标签和背面之间切换时,ListView不应滚动到顶部。但它仍然存在!我可以错过什么吗?

这是一些代码。

片段

public class Home extends Fragment{
    ...
    private HomeFeedAdapter adapter; // HomeFeedAdapter extends CursorAdapter
    private AutoQuery autoQuery;     // AutoQuery extends LoaderCallbacks<Cursor>
    ...                              // (See inner class, at the end)

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRetainInstance(true);

        if(adapter == null)
            adapter = new HomeFeedAdapter(getActivity(), null);
        if(autoQuery == null)
            autoQuery = new AutoQuery();
        getLoaderManager().initLoader(LOADER_INITIAL, null, autoQuery);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        // Layout
        View v = inflater.inflate(R.layout.home, container, false); 
        l = (ListView) v.findViewById(R.id.listview);
        l.setAdapter(adapter);

        return v;
    }

    private class AutoQuery implements LoaderCallbacks<Cursor>{

        @Override
        public Loader<Cursor> onCreateLoader(int id, Bundle args) {

            ...    
            return new CursorLoader(getActivity(), uri,
                    null, null, null, null);
        }

        @Override
        public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
            adapter.swapCursor(cursor);
        }

        @Override
        public void onLoaderReset(Loader<Cursor> loader) {
            adapter.swapCursor(null);
        }

    }

}

活动

public class MainActivity extends SherlockFragmentActivity {

    ...

    private class TabsListener implements ActionBar.TabListener {
        private Fragment fragment;
        private String tag;

        public TabsListener(Fragment fragment, String tag) {
            this.fragment = fragment;
            this.tag = tag; 
        }

        @Override
        public void onTabReselected(Tab tab, FragmentTransaction ft) {
            // Do nothing
        }

        @Override
        public void onTabSelected(Tab tab, FragmentTransaction ft) {
            ft.replace(R.id.fragment_container, fragment, tag);
        }

        @Override
        public void onTabUnselected(Tab tab, FragmentTransaction ft) {
            ft.remove(fragment);
        }

    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {    
        super.onCreate(savedInstanceState);

        // Layout
        getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
        getSupportActionBar().setDisplayHomeAsUpEnabled(false);
        getSupportActionBar().setHomeButtonEnabled(false);
        getSupportActionBar().setDisplayShowTitleEnabled(false);
        setContentView(R.layout.activity_main);

        // Loads fragment
        Fragment fHome, fActivity, fProfile;
        if((fHome = getSupportFragmentManager().findFragmentByTag(HOME)) == null) fHome = new Home();
        if((fActivity = getSupportFragmentManager().findFragmentByTag(ACTIVITY)) == null) fActivity = new FriendsList();
        if((fProfile = getSupportFragmentManager().findFragmentByTag(PROFILE)) == null) fProfile = new Profile();       

        ActionBar.Tab tab;
        tab = getSupportActionBar().newTab();
        tab.setTabListener(new TabsListener(
            fHome,
            HOME
            ));
        getSupportActionBar().addTab(tab, false);

        tab = getSupportActionBar().newTab();
        tab.setTabListener(new TabsListener(
            fActivity,
            ACTIVITY
            ));
        getSupportActionBar().addTab(tab, false);

        tab = getSupportActionBar().newTab();
        tab.setTabListener(new TabsListener(
            fProfile,
            PROFILE
            ));
        getSupportActionBar().addTab(tab, false);

        ...

    }

}

1 个答案:

答案 0 :(得分:0)

Greg Giacovelli的帮助引导我朝着正确的方向前进,我找到了解决问题的方法。

我将从一个免责声明开始,我不太清楚如何保存ListView的位置。每次调用Fragment的onCreateView()时,都会重新创建我的ListView实例。例如,当屏幕旋转时会发生这种情况。然而,在屏幕旋转的特定情况下,即使调用onCreateView()并因此重新实例化ListView,仍然会恢复ListView的状态。因此,如果正在重新创建ListView,那么其他东西必须告诉它之前的位置是什么......我不知道那是什么。我认为这可归因于setRetainInstance(true)的机制。

但是让我们看看我的主要问题:为什么ListView会在标签更改之间滚动到顶部?正如格雷格所说,这是因为我正在重新添加片段replace(),因此每次用户翻转到另一个标签并返回时,都会销毁我的片段并重新创建。

我的解决方案是检查选项卡是否已添加;若然,则不加;否则,添加它。然后,当用户单击选项卡时,我只是分离片段(不删除它),并附加一个新片段。这样,未选中的选项卡的片段仍然存在,但是已经分离。

// Tabs listener
private class TabsListener implements ActionBar.TabListener {
    private Fragment fragment;
    private String tag;

    public TabsListener(Fragment fragment, String tag) {
        this.fragment = fragment;
        this.tag = tag; 
    }

    @Override
    public void onTabReselected(Tab tab, FragmentTransaction ft) {
        if(fragment instanceof ScrollableToTop) ((ScrollableToTop) fragment).scrollToTop();
    }

    @Override
    public void onTabSelected(Tab tab, FragmentTransaction ft) {
        if(!fragment.isAdded()){
            ft.add(R.id.fragment_container, fragment, tag);
        }
        ft.attach(fragment);
    }

    @Override
    public void onTabUnselected(Tab tab, FragmentTransaction ft) {
        ft.detach(fragment);
    }

}