Tab中的ViewPager无法正确显示项目

时间:2012-09-11 12:33:26

标签: android android-fragments android-viewpager android-tabs android-nested-fragment

我有一个设置tabhost的FragmentActivity。每个选项卡都是一个名为TabFragment的简单片段。 TabFragment有一个ViewPager,在这种情况下它是antonyt的InfiniteViewPager(在此讨论:ViewPager as a circular queue / wrapping)。

(主要)问题如下:

  1. 我启动了应用程序。我点击第二个标签。当我看到与第一个标签中相同的内容时,只有一个空白屏幕。 向右滚动几次后,我会看到我的TextViews。

  2. 在ViewPagers中滚动片段并更改标签最终会导致停止和FC,并且不会抛出任何明显的异常。

  3. 这是我对碎片的第一次采取,我必须承认,我不理解观察到的行为。

    任何提示都将不胜感激。

    整个项目是here

    代码:

    使用TabHost的FragmentActivity:

    
    
        package com.example.viewpagerintab;
    
        import java.util.HashMap;
    
        import android.content.Context;
        import android.os.Bundle;
        import android.support.v4.app.Fragment;
        import android.support.v4.app.FragmentActivity;
        import android.support.v4.app.FragmentTransaction;
        import android.view.View;
        import android.widget.TabHost;
        import android.widget.TabHost.TabContentFactory;
    
        public class TabsFragmentActivity extends FragmentActivity implements
                TabHost.OnTabChangeListener {
    
            private TabHost mTabHost;
            private HashMap mapTabInfo = new HashMap();
            private TabInfo mLastTab = null;
    
            public TabsFragmentActivity() {
    
            }
    
            private class TabInfo {
                private String tag;
                private Class clss;
                private Bundle args;
                private Fragment fragment;
    
                TabInfo(String tag, Class classObject, Bundle args) {
                    this.tag = tag;
                    this.clss = classObject;
                    this.args = args;
                }
    
            }
    
            class TabFactory implements TabContentFactory {
    
                private final Context mContext;
    
                /**
                 * @param context
                 */
                public TabFactory(Context context) {
                    mContext = context;
                }
    
                /**
                 * (non-Javadoc)
                 * 
                 * @see android.widget.TabHost.TabContentFactory#createTabContent(java.lang.String)
                 */
                public View createTabContent(String tag) {
                    View v = new View(mContext);
                    v.setMinimumWidth(0);
                    v.setMinimumHeight(0);
                    return v;
                }
    
            }
    
            /**
             * (non-Javadoc)
             * 
             * @see android.support.v4.app.FragmentActivity#onCreate(android.os.Bundle)
             */
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
    
                setContentView(R.layout.tabs);
    
                initialiseTabHost(savedInstanceState);
    
                if (savedInstanceState != null) {
                    mTabHost.setCurrentTabByTag(savedInstanceState.getString("tab"));
                }
            }
    
            /**
             * (non-Javadoc)
             * 
             * @see android.support.v4.app.FragmentActivity#onSaveInstanceState(android.os.Bundle)
             */
            protected void onSaveInstanceState(Bundle outState) {
                outState.putString("tab", mTabHost.getCurrentTabTag());
                super.onSaveInstanceState(outState);
            }
    
            private void initialiseTabHost(Bundle args) {
                mTabHost = (TabHost) findViewById(android.R.id.tabhost);
                mTabHost.setup();
                TabInfo tabInfo = null;
    
                tabInfo = new TabInfo("Discover", TabFragmentD.class, args);
                TabsFragmentActivity.addTab(this, mTabHost,
                        mTabHost.newTabSpec("Discover").setIndicator("Discover"),
                        tabInfo);
                mapTabInfo.put(tabInfo.tag, tabInfo);
    
                tabInfo = new TabInfo("Friends", TabFragmentF.class, args);
                TabsFragmentActivity
                        .addTab(this, mTabHost, mTabHost.newTabSpec("Friends")
                                .setIndicator("Friends"), tabInfo);
                mapTabInfo.put(tabInfo.tag, tabInfo);
    
                onTabChanged("Discover");
    
                mTabHost.setOnTabChangedListener(this);
            }
    
            /**
             * @param activity
             * @param tabHost
             * @param tabSpec
             * @param clss
             * @param args
             */
            private static void addTab(TabsFragmentActivity activity, TabHost tabHost,
                    TabHost.TabSpec tabSpec, TabInfo tabInfo) {
    
                // Attach a Tab view factory to the spec
                tabSpec.setContent(activity.new TabFactory(activity));
                String tag = tabSpec.getTag();
    
                // Check to see if we already have a fragment for this tab, probably
                // from a previously saved state. If so, deactivate it, because our
                // initial state is that a tab isn't shown.
                tabInfo.fragment = activity.getSupportFragmentManager()
                        .findFragmentByTag(tag);
                if (tabInfo.fragment != null && !tabInfo.fragment.isDetached()) {
                    FragmentTransaction ft = activity.getSupportFragmentManager()
                            .beginTransaction();
                    ft.detach(tabInfo.fragment);
                    ft.commit();
                    activity.getSupportFragmentManager().executePendingTransactions();
                }
    
                tabHost.addTab(tabSpec);
            }
    
            /**
             * (non-Javadoc)
             * 
             * @see android.widget.TabHost.OnTabChangeListener#onTabChanged(java.lang.String)
             */
            public void onTabChanged(String tag) {
                TabInfo newTab = mapTabInfo.get(tag);
                if (mLastTab != newTab) {
                    FragmentTransaction ft = getSupportFragmentManager()
                            .beginTransaction();
                    if (mLastTab != null) {
                        if (mLastTab.fragment != null) {
                            ft.detach(mLastTab.fragment);
                        }
                    }
                    if (newTab != null) {
                        if (newTab.fragment == null) {
                            newTab.fragment = Fragment.instantiate(this,
                                    newTab.clss.getName(), newTab.args);
                            ft.add(R.id.realtabcontent, newTab.fragment, newTab.tag);
                        } else {
                            ft.attach(newTab.fragment);
                        }
                    }
    
                    mLastTab = newTab;
                    ft.commit();
                    getSupportFragmentManager().executePendingTransactions();
                }
            }
    
        }
    
    

    包含InfiniteViewPager的TabFragment:

    
    
        package com.example.viewpagerintab;
    
        import java.util.List;
        import java.util.Vector;
    
        import android.os.AsyncTask;
        import android.os.Bundle;
        import android.support.v4.app.Fragment;
        import android.support.v4.app.FragmentPagerAdapter;
        import android.support.v4.view.ViewPager;
        import android.support.v4.view.ViewPager.OnPageChangeListener;
        import android.util.Log;
        import android.view.LayoutInflater;
        import android.view.View;
        import android.view.ViewGroup;
        import android.widget.LinearLayout;
    
        import com.antonyt.infiniteviewpager.InfinitePagerAdapter;
        import com.example.viewpagerintab.pager.SimpleAdapter;
    
        public class TabFragment extends Fragment {
    
            private static final String TAG = TabFragment.class.getSimpleName();
    
            protected View mView;
    
            ViewPager mViewPager;
    
            private InfinitePagerAdapter mPagerAdapter;
    
            PageListener pageListener;
    
            public TabFragment() {
    
            }
    
            /**
             * (non-Javadoc)
             * 
             * @see android.support.v4.app.Fragment#onCreateView(android.view.LayoutInflater,
             *      android.view.ViewGroup, android.os.Bundle)
             */
            public View onCreateView(LayoutInflater inflater, ViewGroup container,
                    Bundle savedInstanceState) {
    
                Log.d(TAG, "onCreateView - called");
    
                if (container == null) {
                    // We have different layouts, and in one of them this
                    // fragment's containing frame doesn't exist. The fragment
                    // may still be created from its saved state, but there is
                    // no reason to try to create its view hierarchy because it
                    // won't be displayed. Note this is not needed -- we could
                    // just run the code below, where we would create and return
                    // the view hierarchy; it would just never be used.
                    return null;
                }
    
                pageListener = new PageListener();
    
                mView = (LinearLayout) inflater.inflate(R.layout.tab, container, false);
    
                List fragments = new Vector();
                fragments.add(DayFragment.newInstance("one"));
                fragments.add(DayFragment.newInstance("two"));
                fragments.add(DayFragment.newInstance("three"));
                fragments.add(DayFragment.newInstance("four"));
    
                mPagerAdapter = new InfinitePagerAdapter(
                        new com.example.viewpagerintab.PagerAdapter(
                                getFragmentManager(), fragments));
    
                mViewPager = (ViewPager) mView.findViewById(R.id.viewpager);
    
                mViewPager.setOnPageChangeListener(pageListener);
    
                new setAdapterTask().execute();
    
                Log.d(TAG, "onCreateView - finished");
    
                return mView;
            }
    
            private class setAdapterTask extends AsyncTask {
                protected Void doInBackground(Void... params) {
                    return null;
                }
    
                @Override
                protected void onPostExecute(Void result) {
                    mViewPager.setAdapter(mPagerAdapter);
                }
            }
    
            class PageListener implements OnPageChangeListener {
                private final String TAG = PageListener.class.getSimpleName();
    
                @Override
                public void onPageScrollStateChanged(int arg0) {
                    Log.d(TAG, "onPageScrollStateChanged(..) to: " + arg0);
    
                }
    
                @Override
                public void onPageScrolled(int arg0, float arg1, int arg2) {
                    // Log.d(TAG, "onPageScrolled(..) - called");
    
                }
    
                @Override
                public void onPageSelected(int arg0) {
                    Log.d(TAG, "onPageSelected(..) selected: " + arg0);
    
                }
            }
        }
    
    

    TabFragmentD和TabFragmentF几乎相同:

    
    
        public class TabFragmentD extends TabFragment {
    
            public TabFragmentD() {
    
            }
    
        }
    
    

    仅包含一个TextView的DayFragment:

    
    
        package com.example.viewpagerintab;
    
        import android.os.Bundle;
        import android.support.v4.app.Fragment;
        import android.util.Log;
        import android.view.LayoutInflater;
        import android.view.View;
        import android.view.ViewGroup;
        import android.widget.LinearLayout;
        import android.widget.TextView;
    
        public class DayFragment extends Fragment {
    
            private static final String TAG = DayFragment.class.getSimpleName();
    
            protected View mView;
    
            protected TextView tvDay;
    
            public DayFragment() {
    
            }
    
            /**
             * (non-Javadoc)
             * 
             * @see android.support.v4.app.Fragment#onCreateView(android.view.LayoutInflater,
             *      android.view.ViewGroup, android.os.Bundle)
             */
            public View onCreateView(LayoutInflater inflater, ViewGroup container,
                    Bundle savedInstanceState) {
    
                if (container == null) {
                    // We have different layouts, and in one of them this
                    // fragment's containing frame doesn't exist. The fragment
                    // may still be created from its saved state, but there is
                    // no reason to try to create its view hierarchy because it
                    // won't be displayed. Note this is not needed -- we could
                    // just run the code below, where we would create and return
                    // the view hierarchy; it would just never be used.
                    return null;
                }
    
                mView = (LinearLayout) inflater.inflate(R.layout.day, container, false);
    
                tvDay = (TextView) mView.findViewById(R.id.tvText);
    
                String text = getArguments().getString("text");
                Log.d(TAG, "creating view with text: " + text);
    
                tvDay.setText(text);
    
                return mView;
            }
    
            public static DayFragment newInstance(String text) {
                Log.d(TAG, "newInstance with text: " + text);
                DayFragment f = new DayFragment();
    
                // Supply text input as an argument.
                Bundle args = new Bundle();
                args.putString("text", text);
                f.setArguments(args);
    
                return f;
            }
    
        }
    
    

    PagerAdapter:

    
    
        package com.example.viewpagerintab;
    
        import java.util.List;
    
        import android.support.v4.app.Fragment;
        import android.support.v4.app.FragmentManager;
        import android.support.v4.app.FragmentPagerAdapter;
    
        public class PagerAdapter extends FragmentPagerAdapter {
    
            private List fragments;
    
            public PagerAdapter(FragmentManager fm, List fragments) {
                super(fm);
                this.fragments = fragments;
            }
    
            /*
             * (non-Javadoc)
             * 
             * @see android.support.v4.app.FragmentPagerAdapter#getItem(int)
             */
            @Override
            public Fragment getItem(int position) {
                return fragments.get(position);
            }
    
            /*
             * (non-Javadoc)
             * 
             * @see android.support.v4.view.PagerAdapter#getCount()
             */
            @Override
            public int getCount() {
                return this.fragments.size();
            }
        }
    
    

    InfiniteViewPager和InfinitePageAdapter位于antonyt's github

    tabs.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
    
    <TabHost
        android:id="@android:id/tabhost"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" >
    
        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:orientation="vertical" >
    
            <TabWidget
                android:id="@android:id/tabs"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:layout_weight="0"
                android:orientation="horizontal" />
    
            <FrameLayout
                android:id="@android:id/tabcontent"
                android:layout_width="0dp"
                android:layout_height="0dp"
                android:layout_weight="0" />
    
            <FrameLayout
                android:id="@+android:id/realtabcontent"
                android:layout_width="fill_parent"
                android:layout_height="0dp"
                android:layout_weight="1" />
        </LinearLayout>
    </TabHost>
    </LinearLayout>
    

    tab.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@android:color/black" >
    
    <com.antonyt.infiniteviewpager.InfiniteViewPager
        android:id="@+android:id/viewpager"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" />
    
    </LinearLayout>
    

    day.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@android:color/black"
    android:gravity="center" >
    
    <TextView
        android:id="@+id/tvText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="@android:color/white" />
    
    </LinearLayout>
    

    更新

    正如CommonsWare所指出的,Android在片段中存在片段问题。

    我将tabs.xml修改为:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="vertical" >
    
        <TabHost
            android:id="@android:id/tabhost"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent" >
    
            <LinearLayout
                android:layout_width="fill_parent"
                android:layout_height="fill_parent"
                android:orientation="vertical" >
    
                <TabWidget
                    android:id="@android:id/tabs"
                    android:layout_width="fill_parent"
                    android:layout_height="wrap_content"
                    android:layout_weight="0"
                    android:orientation="horizontal" />
    
                <FrameLayout
                    android:id="@android:id/tabcontent"
                    android:layout_width="0dp"
                    android:layout_height="0dp"
                    android:layout_weight="0" />
    
                <FrameLayout
                    android:id="@+android:id/realtabcontent"
                    android:layout_width="fill_parent"
                    android:layout_height="0dp"
                    android:layout_weight="0" />
    
                <com.antonyt.infiniteviewpager.InfiniteViewPager
                    android:id="@+android:id/viewpager"
                    android:layout_width="fill_parent"
                    android:layout_height="0dp"
                    android:layout_weight="1" />
            </LinearLayout>
        </TabHost>
    
    </LinearLayout>
    

    并创建了空TabFragments(tab.xml):

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="0dp"
        android:layout_height="0dp" >
    
    </LinearLayout>
    

    所以现在切换标签几乎与刷卡无关。

    唯一的缺点是,在更改标签后,任何尝试将ViewPager的当前位置设置为0都会出现一个非常恼人的问题(应用程序刚刚崩溃,没有例外)。

2 个答案:

答案 0 :(得分:5)

不支持片段内的片段according to the author of the fragments framework

我可以告诉你,你的ViewPager还有一个片段,它会使用返回片段的PagerAdapter。这将无法可靠地运作。

ViewPager移出片段​​(因此它直接由活动保存)或切换到不使用片段的PagerAdapter实现。

答案 1 :(得分:3)

使用getChildFragmentManager()代替getFragmentManager() ..... 所以你的代码就像

mPagerAdapter = new InfinitePagerAdapter(
                new com.example.viewpagerintab.PagerAdapter(
                        getChildFragmentManager(), fragments));

干杯:)