Question Comment déterminer quand Fragment devient visible dans ViewPager


Problème: Fragment onResume() dans ViewPager est déclenché avant que le fragment ne soit réellement visible.

Par exemple, j'ai 2 fragments avec ViewPager et FragmentPagerAdapter. Le second fragment n'est disponible que pour les utilisateurs autorisés et je dois demander à l'utilisateur de se connecter lorsque le fragment devient visible (en utilisant une boîte de dialogue d'alerte).

Mais le ViewPager crée le deuxième fragment lorsque le premier est visible afin de mettre en cache le deuxième fragment et le rend visible lorsque l'utilisateur commence à glisser.

Alors le onResume() l'événement est déclenché dans le second fragment bien avant qu'il ne devienne visible. C'est pourquoi j'essaie de trouver un événement qui se déclenche quand le second fragment devient visible pour montrer un dialogue au moment approprié.

Comment cela peut-il être fait?


628
2018-04-05 07:58


origine


Réponses:


METTRE À JOUR: Bibliothèque de support Android (rev 11) enfin Correction du problème d'indice visible de l'utilisateur, maintenant si vous utilisez la bibliothèque de support pour les fragments, vous pouvez utiliser en toute sécurité getUserVisibleHint() ou remplacer setUserVisibleHint() pour capturer les changements comme décrit par la réponse de gorn.

MISE À JOUR 1 Voici un petit problème avec getUserVisibleHint(). Cette valeur est par défaut true.

// Hint provided by the app that this fragment is currently visible to the user.
boolean mUserVisibleHint = true;

Donc, il pourrait y avoir un problème lorsque vous essayez de l'utiliser avant setUserVisibleHint() a été invoqué. Comme une solution de contournement, vous pouvez définir la valeur dans onCreate méthode comme celle-ci.

public void onCreate(@Nullable Bundle savedInstanceState) {
    setUserVisibleHint(false);

La réponse dépassée:

Dans la plupart des cas d'utilisation, ViewPager seulement afficher une page à la fois, mais les fragments pré-mis en cache sont également mis à l'état "visible" (en fait invisible) si vous utilisez FragmentStatePagerAdapter dans Android Support Library pre-r11.

Je remplace:

public class MyFragment extends Fragment {
    @Override
    public void setMenuVisibility(final boolean visible) {
        super.setMenuVisibility(visible);
        if (visible) {
            // ...
        }
    }
   // ...
}

Pour capturer l'état de focalisation du fragment, ce que je pense être l'état le plus approprié de la "visibilité" que vous voulez dire, puisque seulement un fragment dans ViewPager peut réellement placer ses éléments de menu avec les éléments de l'activité parent.


472
2017-09-21 02:56



Comment déterminer quand Fragment devient visible dans ViewPager

Vous pouvez effectuer les opérations suivantes en remplaçant setUserVisibleHint dans ton Fragment:

public class MyFragment extends Fragment {
    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (isVisibleToUser) {
        }
        else {
        }
    }
}

519
2018-06-17 23:42



Cela semble restaurer la normale onResume() comportement que vous attendez. Il joue bien en appuyant sur la touche d'accueil pour quitter l'application, puis ré-entrer dans l'application. onResume() n'est pas appelé deux fois de suite.

@Override
public void setUserVisibleHint(boolean visible)
{
    super.setUserVisibleHint(visible);
    if (visible && isResumed())
    {
        //Only manually call onResume if fragment is already visible
        //Otherwise allow natural fragment lifecycle to call onResume
        onResume();
    }
}

@Override
public void onResume()
{
    super.onResume();
    if (!getUserVisibleHint())
    {
        return;
    }

    //INSERT CUSTOM CODE HERE
}

105
2017-08-03 03:02



Voici une autre façon d'utiliser onPageChangeListener:

  ViewPager pager = (ViewPager) findByViewId(R.id.viewpager);
  FragmentPagerAdapter adapter = new FragmentPageAdapter(getFragmentManager);
  pager.setAdapter(adapter);
  pager.setOnPageChangeListener(new OnPageChangeListener() {

  public void onPageSelected(int pageNumber) {
    // Just define a callback method in your fragment and call it like this! 
    adapter.getItem(pageNumber).imVisible();

  }

  public void onPageScrolled(int arg0, float arg1, int arg2) {
    // TODO Auto-generated method stub

  }

  public void onPageScrollStateChanged(int arg0) {
    // TODO Auto-generated method stub

  }
});

54
2017-08-03 14:41



setUserVisibleHint() est appelé parfois avant  onCreateView() et parfois après qui cause des ennuis.

Pour surmonter cela, vous devez vérifier isResumed() aussi à l'intérieur setUserVisibleHint() méthode. Mais dans ce cas, j'ai réalisé setUserVisibleHint() se fait appeler seulement si le fragment est repris et visible, PAS lors de la création.

Donc, si vous voulez mettre à jour quelque chose quand Fragment est visible, mettez votre fonction de mise à jour à la fois dans onCreate() et setUserVisibleHint():

@Override
public View onCreateView(...){
    ...
    myUIUpdate();
    ...        
}
  ....
@Override
public void setUserVisibleHint(boolean visible){
    super.setUserVisibleHint(visible);
    if (visible && isResumed()){
        myUIUpdate();
    }
}

METTRE À JOUR: Encore j'ai réalisé myUIUpdate() est parfois appelé deux fois, la raison en est, si vous avez 3 onglets et que ce code est sur le 2ème onglet, lorsque vous ouvrez le 1er onglet, le 2ème onglet est également créé même s'il n'est pas visible et myUIUpdate() est appelé. Ensuite, lorsque vous faites glisser vers le 2ème onglet, myUIUpdate() de if (visible && isResumed()) est appelé et, par conséquent,myUIUpdate() peut être appelé deux fois par seconde.

L'autre problème est !visible dans setUserVisibleHint est appelé à la fois 1) lorsque vous sortez de l'écran de fragment et 2) avant qu'il ne soit créé, lorsque vous passez à l'écran de fragment première fois.

Solution: 

private boolean fragmentResume=false;
private boolean fragmentVisible=false;
private boolean fragmentOnCreated=false;
...

@Override
public View onCreateView(...){
    ...
    //Initialize variables
    if (!fragmentResume && fragmentVisible){   //only when first time fragment is created
        myUIUpdate();
    }
    ...        
}

@Override
public void setUserVisibleHint(boolean visible){
    super.setUserVisibleHint(visible);
    if (visible && isResumed()){   // only at fragment screen is resumed
        fragmentResume=true;
        fragmentVisible=false;
        fragmentOnCreated=true;
        myUIUpdate();
    }else  if (visible){        // only at fragment onCreated
        fragmentResume=false;
        fragmentVisible=true;
        fragmentOnCreated=true;
    }
    else if(!visible && fragmentOnCreated){// only when you go out of fragment screen
        fragmentVisible=false;
        fragmentResume=false;
    }
}

Explication: 

fragmentResume,fragmentVisible: Il s'assure de myUIUpdate() dans onCreateView() est appelé uniquement lorsque le fragment est créé et visible, pas sur le CV. Il résout également le problème lorsque vous êtes au 1er onglet, le 2ème onglet est créé même s'il n'est pas visible. Cela résout cela et vérifie si l'écran fragment est visible lorsque onCreate.

fragmentOnCreated: S'assure que le fragment n'est pas visible et n'est pas appelé lorsque vous créez un fragment la première fois. Alors maintenant, cette clause if n'est appelée que lorsque vous supprimez un fragment.

Mettre à jour Vous pouvez mettre tout ce code dans BaseFragment code comme ça et remplacer la méthode.


50
2018-04-14 07:27



package com.example.com.ui.fragment;


import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.example.com.R;

public class SubscribeFragment extends Fragment {

    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_subscribe, container, false);
        return view;
    }

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);

        if (isVisibleToUser) {
            // called here
        }
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
    }
}

22
2018-01-06 13:54



Passer outre setPrimaryItem() dans le FragmentPagerAdapter sous-classe. J'utilise cette méthode, et cela fonctionne bien.

@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
    // This is what calls setMenuVisibility() on the fragments
    super.setPrimaryItem(container, position, object);

    if (object instanceof MyWhizBangFragment) {
        MyWhizBangFragment fragment = (MyWhizBangFragment) object;
        fragment.doTheThingYouNeedToDoOnBecomingVisible();
    }
}

14
2018-06-19 18:34