Життєвий цикл фрагмента - який метод викликається показати / приховати?


99

Я використовую наступний метод для перемикання між фрагментами (у своєму NavigationDrawer), показуючи / приховуючи їх.

protected void showFragment(int container, Fragment fragment, String tag, String lastTag, boolean addToBackStack ) {

        FragmentManager fragmentManager = getSupportFragmentManager();
        FragmentTransaction transaction = fragmentManager.beginTransaction();

        if ( lastTag != null && !lastTag.equals("")) {
            Fragment lastFragment = fragmentManager.findFragmentByTag( lastTag );
            if ( lastFragment != null ) {
                transaction.hide( lastFragment );
            }
        }

        if ( fragment.isAdded() ) {
            transaction.show( fragment );
        }
        else {
            transaction.add( container, fragment, tag );
        }

        if ( addToBackStack ) {
            transaction.addToBackStack( tag );
        }

        transaction.commit();

        // set the active tag
        activeFragTag = tag;
    }

Мені незрозуміло, який метод життєвого циклу Фрагменти викликається, коли я показую його чи приховую? (оскільки немає таких методів, як onShow () або onHide (), я не зовсім впевнений, що використовувати). Я хочу виконувати конкретні дії, показуючи та приховуючи певний фрагмент.


коли ви зателефонуєте на Fragment.show (), то в якийсь момент пізніше фрагмент запускається onCreate(), а onCreateDialog()даліonCreateView()
Хтось десь

Відповіді:


122

Подібно до життєвого циклу діяльності, Android закликає OnStart (), коли фрагмент стає видимим. onStop()зазвичай називається, коли фрагмент стає невидимим, але його також можна назвати пізніше.

Залежно від вашого макета Android може зателефонувати onStart()навіть тоді, коли ваш фрагмент ще не видно, але він належить до видимого батьківського контейнера. Наприклад, це дійсно, для android.support.v4.view.ViewPagerчого потрібно переосмислити Fragment.setUserVisibleHint()метод. У будь-якому випадку, якщо вам потрібно зареєструвати / відреєструвати BroadcastReceivers або інших слухачів, ви можете сміливо використовувати onStart()та onStop()методи, тому що вони будуть називатися завжди.

Примітка. Деякі контейнери з фрагментами можуть зберігати невидимі фрагменти. Щоб вирішити цю ситуацію, ви можете перекрити Fragment.onHiddenChanged(boolean hidden). Згідно з документацією , фрагмент повинен бути як запущеним, так і видимим (не прихованим) , щоб бути видимим користувачеві.

Оновлення: якщо ви використовуєте, android.support.v4.widget.DrawerLayoutтоді фрагмент під ящиком залишається запущеним і видимим, навіть коли ящик відкритий. В цьому випадку ви повинні використовувати DrawerLayout.setDrawerListener()і слухати onDrawerClosed()і onDrawerOpened()зворотні виклики.


14
onStopі onPauseне називаються, коли фрагмент стає невидимим за допомогою транзакції. Тим не менш onHiddenChanged, називається так, як пропонує s1rius відповідь
Йоанн Херкует

Це не працює в NavigationDrawer. onHiddenChanged не викликається на v4 / v11 підтримку lib. onStart і onResume також будуть викликатися не кожен раз, коли відкриється макет ящика.
drdrej

@drdrej Проблема полягає в тому, що ящик не приховує фрагмент внизу повністю. Якщо ви використовуєте DrawerLayout з бібліотеки підтримки, вам потрібно використовувати DrawerListener.
sergej shafarenka

69

Я @Override цей метод і вирішити свою проблему:

@Override
public void onHiddenChanged(boolean hidden) {
    super.onHiddenChanged(hidden);
    if (hidden) {
        //do when hidden
    } else {
       //do when show
    }
}

1
Пробували не вирішувати, але використовуючи, setUserVisibleHintяк показано в stackoverflow.com/a/18375436/1815624 робіт
CrandellWS

36

Звичайно, ви можете @Orride наступний метод зробити це:

@Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (isVisibleToUser) {
            // Do your Work
        } else {
            // Do your Work
        }
    }

І можна легко дізнатися, чи фрагмент видно користувачеві чи ні, зателефонувавшиgetUserVisibleHint()
ARiF

2
setUserVisibleHint працює з пейджером перегляду, але не з регулярним контейнером фрагментів.
MikeL

Завдяки цьому вирішується моя проблема :)
RAJESH KUMAR ARUMUGAM

Це працювало для мене на ViewPager. onHiddenChanged не працював.
live-love

Вирішив мою проблему!
Джад

3

Фрагмент у поведінці пейджера перегляду відрізняється від звичайного контейнера фрагмента.

Спробуйте цей код:

    boolean mIsVisibleToUser;

    /**
     * is visible to user
     */
    public void show() {
        //do when show
    }

    /**
     * is invisible to user
     */
    public void hide() {
        //do when gone
    }

    @Override
    public void onResume() {
        super.onResume();
        if (!mIsVisibleToUser && getUserVisibleHint()) {
            mIsVisibleToUser = true;
            show();
        }
    }

    @Override
    public void onPause() {
        super.onPause();
        if (mIsVisibleToUser && getUserVisibleHint()) {
            mIsVisibleToUser = false;
            hide();
        }
    }

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (isResumed()) {
            if (mIsVisibleToUser != isVisibleToUser) {
                mIsVisibleToUser = isVisibleToUser;
                if (isVisibleToUser) show();
                else hide();
            }
        }
    }

    public boolean isVisibleToUser() {
        return mIsVisibleToUser;
    }

2

Спробуйте цей код:

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

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

    //Add your code this section
}

2

Ви можете використовувати "onCreateView" (або "onActivityCreate") і "onHiddenChanged". Використовуйте "onCreateView" для першого показу, а потім "onHiddenChanged". "setMenuVisibility" не контролюється для контролю транзакцій.

@Override
public View OnCreateView() {
   // fragment will show first
}

@Override
public void onHiddenChanged(boolean hidden) {
    if (!hidden) {
        // fragment will show 
    }
    else {
        // fragment will hide
    }
}

onHiddenChanged () не називається моїм фрагментом
matdev

1

Просто спробуйте це у своєму setUserVisibleHint ()

@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    if(isVisibleToUser && getView() != null){
        isActive = true;
        init();
    }else if(isVisibleToUser && getView() == null){
        isActive = false;
    }else{
        isActive = true;
    }
}

І створіть цей код у onCreateView () :

public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
  if(!isActive){
      init();
  }
}

isVisibleToUser && getView() != nullпрацював ідеально для мене!
бобі

1

Інший спосіб виклику методу фрагмента, коли фрагмент видно, і ви використовуєте viewpager у діяльності.

// Перш за все ви створюєте інтерфейс

public interface ShowFragmentVisible{
      public void showFragment();}

// Після цього цей інтерфейс реалізуємо всередині фрагмента

      public class MyFragment extends Fragment implements 
         ShowFragmentVisible {
            @Override
public void showFragment() {
}

// Тепер виходить ваша діяльність, а потім створюйте об'єкт інтерфейсу і дзвоніть всередину, коли addOnViewpagerListener

   ShowFragmentVisible showFragmentVisible;

@Override
public void onAttachFragment(Fragment fragment) {
    super.onAttachFragment(fragment);

    if (fragment instanceof ShowFragmentVisible) {
        showFragmentVisible = (ShowFragmentVisible) fragment;
    }

}
     //your viewpager method
    viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

        }

        @Override
        public void onPageSelected(int position) {
            if (position==0){
                showFragmentVisible.showFragment();

           }

        }

        @Override
        public void onPageScrollStateChanged(int state) {

        }
    });


this is another alternative,but its work for me successfully

0

setUserVisibleHintдзвоніть раніше onCreateView. і ви не можете оновити будь-який перегляд усередині setUserVisibleHint, який я використовую

public void setMenuVisibility(final boolean visible)

для видимості та в режимі onHiddenChanged () не дзвонили вперше . він викликає, коли прихований стан змінюється. бо а fragment is visible by default. Щоб досягти цього методу вперше вам потрібно зателефонувати, mFragmentTransaction.hide(oldFragment)тоді він спрацює

Примітка

якщо ви хочете використовувати підказку setUserVisible та оновити Перегляд Використовуйте цей метод


0

Звичайно , ви можете перевизначити setUserVisibleHintабо , setMenuVisibilityале якщо вам потрібно отримати доступ Contextабо Activityвони будуть анульовані там! Існує ще один метод, у onStartякому завжди доступний контекст, але він буде викликаний лише один раз після створення фрагмента, і якщо ви почнете переміщуватися між вашими фрагментами в пейджері, ви побачите, що він не буде викликаний у другому вікні і після цього .

Отже ... що тепер робити?

Вирішення проблеми досить просте, використовувати його onStartдля першого відвідування та setMenuVisibilityдля подальшого відвідування. Ваш код, мабуть, буде виглядати приблизно так:

Клас фрагментів:

public class MyFragmentClass{
    private boolean isCurrentVisible = false;
...

@Override
public void onStart() {
    super.onStart();
    if (isCurrentVisible)
        doSth();
}

@Override
public void setMenuVisibility(boolean menuVisible){
    super.setMenuVisibility(menuVisible);
    this.isCurrentVisible = menuVisible;
    if(menuVisible && getContext() != null)
        doSth();
}

Цей спосіб Contextзавжди буде доступний doSth()методу.


0

Тільки це працювало на мене !! і setUserVisibleHint(...)тепер застаріло (я додав документи в кінці), що означає, що деякі інші відповіді застаріли ;-)

public class FragmentFirewall extends Fragment {
    /**
     * Required cause "setMenuVisibility(...)" is not guaranteed to be
     * called after "onResume()" and/or "onCreateView(...)" method.
     */
    protected void didVisibilityChange() {
        Activity activity = getActivity();
        if (isResumed() && isMenuVisible()) {
            // Once resumed and menu is visible, at last
            // our Fragment is really visible to user.
        }
    }

    @Override
    public void onResume() {
        super.onResume();
        didVisibilityChange();
    }

    @Override
    public void setMenuVisibility(boolean visible) {
        super.setMenuVisibility(visible);
        didVisibilityChange();
    }
}

Випробуваний і працює з ним NaviagationDrawer, isMenuVisible()завжди буде повертатися trueonResume()здається, що достатньо, але ми хочемо підтримати ViewPagerтакож).

setUserVisibleHintзастаріло. Якщо цей метод trueперевищує , поведінку, реалізовану під час передачі, слід перемістити до Fragment.onResume(), а поведінку, реалізовану при передачі, falseслід перемістити до Fragment.onPause().

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.