Хобрук: Ваш путь к мастерству в программировании

ViewPager внутри вкладки не отображает элементы должным образом

У меня есть FragmentActivity, который устанавливает tabhost. Каждая вкладка представляет собой простой фрагмент, называемый TabFragment. TabFragment имеет ViewPager, в данном случае это InfiniteViewPager от antonyt (обсуждается здесь: ViewPager как циклическая очередь/обертка).

Основные (основные) проблемы заключаются в следующем:

  1. Я запускаю приложение. Кликаю на вторую вкладку. Есть только пустой экран, когда я должен видеть то же самое, что и на первой вкладке. После прокрутки вправо несколько раз я вижу свои TextViews.

  2. Прокрутка фрагментов в ViewPagers и изменение вкладок в конечном итоге приводит к остановке и FC без выдачи четкого исключения.

Это мой первый взгляд на Фрагменты, и, должен признаться, я не понимаю наблюдаемого поведения.

Любые подсказки будут очень признательны.

Весь проект находится здесь.

Код:

Фрагментактивность с TabHost:



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

    }

TabFragment, содержащий InfiniteViewPager:



    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() {

        }

    }

DayFragment, содержащий только один TextView:



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

    }

ПейджерАдаптер:



    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 находятся на github antonyt.

вкладки.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>

таб.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>

день.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 после смены вкладок (приложение просто вылетало без исключения).


Ответы:


1

Фрагменты внутри фрагментов не поддерживаются, по словам автора структуры фрагментов.

Насколько я могу судить, у вас есть фрагмент, удерживающий ваш ViewPager, который, в свою очередь, использует PagerAdapter, который возвращает фрагменты. Это не будет работать надежно.

Либо переместите ViewPager из фрагмента (чтобы он удерживался действием напрямую), либо переключитесь на реализацию PagerAdapter, которая не использует фрагменты.

11.09.2012
  • Спасибо за ваш вклад. Странно, что у программиста столько проблем, чтобы получить вкладки с просмотрщиками ;) 12.09.2012

  • 2

    используйте getChildFragmentManager() вместо getFragmentManager()..... Таким образом, ваш код становится чем-то вроде

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

    Ваше здоровье :)

    23.04.2014
    Новые материалы

    5 проектов на Python, которые нужно создать прямо сейчас!
    Добро пожаловать! Python — один из моих любимых языков программирования. Если вы новичок в этом языке, перейдите по ссылке ниже, чтобы узнать о нем больше:

    Dall-E 2: недавние исследования показывают недостатки в искусстве, созданном искусственным интеллектом
    DALL-E 2 — это всеобщее внимание в индустрии искусственного интеллекта. Люди в списке ожидания пытаются заполучить продукт. Что это означает для развития креативной индустрии? О применении ИИ в..

    «Очень простой» эволюционный подход к обучению с подкреплением
    В прошлом семестре я посетил лекцию по обучению с подкреплением (RL) в моем университете. Честно говоря, я присоединился к нему официально, но я редко ходил на лекции, потому что в целом я нахожу..

    Освоение информационного поиска: создание интеллектуальных поисковых систем (глава 1)
    Глава 1. Поиск по ключевым словам: основы информационного поиска Справочная глава: «Оценка моделей поиска информации: подробное руководство по показателям производительности » Глава 1: «Поиск..

    Фишинг — Упаковано и зашифровано
    Будучи старшим ИТ-специалистом в небольшой фирме, я могу делать много разных вещей. Одна из этих вещей: специалист по кибербезопасности. Мне нравится это делать, потому что в настоящее время я..

    ВЫ РЕГРЕСС ЭТО?
    Чтобы понять, когда использовать регрессионный анализ, мы должны сначала понять, что именно он делает. Вот простой ответ, который появляется, когда вы используете Google: Регрессионный..

    Не зря же это называют интеллектом
    Стек — C#, Oracle Опыт — 4 года Работа — Разведывательный корпус Мне пора служить Может быть, я немного приукрашиваю себя, но там, где я живу, есть обязательная военная служба на 3..