web-dev-qa-db-fra.com

Fragment de mise à jour de ViewPager par glissement

j'ai un problème avec lequel je me bats depuis 2 jours.

Je crée une application qui utilise ActionBar, ViewPager & FragmentPagerAdapter. Le code de Activity, Fragments & FragmentPagerAdapter est exactement celui indiqué dans l'exemple Android sur http://developer.Android.com/reference/Android/support/v4 /view/ViewPager.html

Le problème auquel je suis confronté est - en supposant que je n'ai que 2 fragments dans le viewPager. lors du basculement/passage entre les deux, les fragments ne sont pas mis à jour. onResume n'est pas appelé car le viewPager met en cache au moins 1 fragment de chaque côté du fragment affiché.

J'ai essayé d'utiliser onTabSelected pour détecter quand un fragment est sélectionné, puis démarrer une méthode à partir de ce fragment à l'aide d'une interface (code ci-dessous).

public void onTabSelected(Tab tab, FragmentTransaction ft) {
    TabInfo tag = (TabInfo)tab.getTag();
    for (int i=0; i<mTabs.size(); i++) {
        if (mTabs.get(i) == tag) {
            mViewPager.setCurrentItem(i);
        }
    }
    ((IStartStop)getItem(tab.getPosition())).Start();
}

Cependant, lorsque la méthode Start est utilisée, une exception NullPointerException est déclenchée lors de la tentative de mise à jour d'une vue de texte. Le code de la méthode de démarrage est:

public void Start() {
    TextView tv = _view.findViewById(R.id.text);
    tv.setText("test");
}

L'exception est levée à la ligne:

TextView tv = _view.findViewById(R.id.text);

L'interface IStartStop est assez simple:

public interface IStartStop {
    public void Start();
    public void Stop();
}

Je ne veux pas utiliser notifyDataSetChanged (); avec POSITION_NONE car chaque fois que je glisse vers un nouveau fragment, il faut quelques secondes pour charger les fragments

Pour le moment, les fragments incluent uniquement une vue texte, à l'avenir ils auront une animation et il est donc important de:

1- Exécuter une animation uniquement lorsque le fragment est sélectionné et non pas lorsque le fragment à côté de lui est sélectionné (la façon dont ViewPager met en cache et reprend les fragments).

2- Arrêtez l'animation lorsque le fragment n'est plus sélectionné pour éviter de gaspiller les ressources de l'appareil.

Oui, j'ai déjà vérifié tout ce qui est disponible sur Internet mais rien ne semble fonctionner avec moi.

Merci beaucoup pour votre aide!

27
Steve

Étonnamment, le ViewPager ne fait pas cela "nativement" (entre autres). Mais tout n'est pas perdu.

Vous devez d'abord modifier vos fragments afin qu'ils n'exécutent l'animation que lorsque vous leur dites que tout va bien et non lorsqu'ils sont instanciés. De cette façon, vous pouvez jouer avec le décalage du viseur (par défaut = 3) et avoir 2-3 fragments préchargés mais pas animés.

La deuxième étape consiste à créer une interface ou similaire qui définit quand le "fragment est devenu visible".

La troisième étape serait d'attacher un nouveau OnPageScrollListener à votre viewpager.

Le code suit (en code semi-non testé):

1) Fixez l'auditeur:

mViewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(final int i, final float v, final int i2) {
            }
            @Override
            public void onPageSelected(final int i) {
                YourFragmentInterface fragment = (YourFragmentInterface) mPagerAdapter.instantiateItem(mViewPager, i);
                if (fragment != null) {
                    fragment.fragmentBecameVisible();
                } 
            }
            @Override
            public void onPageScrollStateChanged(final int i) {
            }
        });

2) Voici votre interface:

public interface YourFragmentInterface {
    void fragmentBecameVisible();
}

3) Modifiez vos fragments pour qu'ils implémentent ceci:

public class YourLovelyFragment extends Fragment implements YourFragmentInterface {

4) Implémentez l'interface dans le fragment

@Override
public void fragmentBecameVisible() {
    // You can do your animation here because we are visible! (make sure onViewCreated has been called too and the Layout has been laid. Source for another question but you get the idea.
}

Où aller d'ici?

Vous voudrez peut-être implémenter une méthode/écouteur pour notifier les "autres" fragments qu'ils ne sont plus visibles (c'est-à-dire que lorsque l'un est visible, les autres ne le sont pas). Mais cela n'est peut-être pas nécessaire.

55
Martin Marconcini

Cela affectera les changements d'une page à une autre dans le téléavertisseur de vue.

OnPageChangeListener  pagechangelistener =new OnPageChangeListener() {

                @Override
                public void onPageSelected(int arg0) {
                    Logger.logMessage("Called first");

                    pageAdapter.notifyDataSetChanged();
                    indicator.setCurrentItem(arg0);
                }

                @Override
                public void onPageScrolled(int arg0, float arg1, int arg2) {

                    Logger.logMessage("Called second");

                }

                @Override
                public void onPageScrollStateChanged(int arg0) {

                    Logger.logMessage("Called third");

                }
            };
            myViewPager.setOnPageChangeListener(pagechangelistener);

Utilisez-le dans votre adaptateur de page.

@Override
    public int getItemPosition(Object object) {

        return POSITION_NONE;
    }
4
Dinesh IT

setOnPageChangeListener est obsolète. À la place, vous devez utiliser addOnPageChangeListener.

mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
        @Override
        public void onPageScrolled(final int i, final float v, final int i2) {
        }
        @Override
        public void onPageSelected(final int i) {
            YourFragmentInterface fragment = (YourFragmentInterface) mPagerAdapter.instantiateItem(mViewPager, i);
            if (fragment != null) {
                fragment.fragmentBecameVisible();
            } 
        }
        @Override
        public void onPageScrollStateChanged(final int i) {
        }
    });
2
A. Vin