Как получить отображаемый фрагмент? - PullRequest
395 голосов
/ 15 февраля 2012

Я играю с фрагментами в Android.

Я знаю, что могу изменить фрагмент, используя следующий код:

FragmentManager fragMgr = getSupportFragmentManager();
FragmentTransaction fragTrans = fragMgr.beginTransaction();

MyFragment myFragment = new MyFragment(); //my custom fragment

fragTrans.replace(android.R.id.content, myFragment);
fragTrans.addToBackStack(null);
fragTrans.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
fragTrans.commit();

У меня вопрос в файле Java, как я могу получить отображаемый в данный момент экземпляр фрагмента?

Ответы [ 41 ]

2 голосов
/ 13 марта 2014
final FragmentManager fm=this.getSupportFragmentManager();
final Fragment fragment=fm.findFragmentByTag("MY_FRAGMENT");

if(fragment != null && fragment.isVisible()){
      Log.i("TAG","my fragment is visible");
}
else{
      Log.i("TAG","my fragment is not visible");
}
1 голос
/ 23 августа 2015

Я столкнулся с подобной проблемой, когда я хотел узнать, какой фрагмент отображался в последний раз при нажатии клавиши «назад». Я использовал очень простое решение, которое сработало для меня. Каждый раз, когда я открываю фрагмент, в методе onCreate () я устанавливаю переменную в моем синглтоне (замените «myFragment» именем вашего фрагмента)

MySingleton.currentFragment = myFragment.class;

Переменная объявлена ​​в синглтоне как

public static Class currentFragment = null; 

Затем в onBackPressed () я проверяю

    if (MySingleton.currentFragment == myFragment.class){
        // do something
        return;
    }
    super.onBackPressed();

Обязательно вызовите super.onBackPressed (); после возврата, в противном случае приложение обработает клавишу возврата, что в моем случае привело к завершению работы приложения.

1 голос
/ 16 апреля 2013

В основном упражнении метод onAttachFragment (фрагмент фрагмента) вызывается, когда к действию присоединяется новый фрагмент.В этом методе вы можете получить экземпляр текущего фрагмента.Однако метод onAttachFragment не вызывается, когда фрагмент извлекается из стека назад, т. Е. Когда нажимается кнопка «Назад», чтобы получить верхний фрагмент поверх стека.Я все еще ищу метод обратного вызова, который запускается в основном действии, когда фрагмент становится видимым внутри действия.

1 голос
/ 06 ноября 2017

В случае прокручиваемых фрагментов, когда вы используете экземпляр класса ViewPager, предположим, что mVeiwPager, вы можете вызвать mViewPager.getCurrentItem () для получения текущего номера фрагмента int.

в MainLayout.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    android:orientation="vertical"
    tools:context="unidesign.photo360.MainActivity">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/appbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:fitsSystemWindows="false"
        android:theme="@style/AppTheme.AppBarOverlay"
        app:expanded="false">

        <android.support.v7.widget.Toolbar
            android:id="@+id/main_activity_toolbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            app:popupTheme="@style/AppTheme.PopupOverlay"
            app:title="@string/app_name">

        </android.support.v7.widget.Toolbar>

    </android.support.design.widget.AppBarLayout>


    <android.support.v4.view.ViewPager
        android:id="@+id/view_pager"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

    </android.support.v4.view.ViewPager>
    
</android.support.design.widget.CoordinatorLayout>

в MainActivity.kt

class MainActivity : AppCompatActivity() {
    
        lateinit var mViewPager: ViewPager
        lateinit var pageAdapter: PageAdapter
        
//      ...
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
            
            pageAdapter = PageAdapter(supportFragmentManager)
            mViewPager = findViewById(R.id.view_pager)
//          ...
            }
            
        override fun onResume() {
          super.onResume()
          var currentFragment = pageAdapter.getItem(mViewPager.currentItem)
//         ...
          }
0 голосов
/ 09 апреля 2019

В случае, если у вас есть вложенные фрагменты, такие как видовые пейджеры внутри видовых пейджеров и т. Д., И вы хотите получить все вложенные фрагменты.

Благодарность и любезность Ответ Мэтта Момбрии небольшая измененная версия.

private List<Fragment> getVisibleFragments(List<Fragment> searchFragments, List<Fragment> visibleFragments) {
    if (searchFragments != null && searchFragments.size() > 0) {
        for (Fragment fragment : searchFragments) {
            List<Fragment> nestedFragments = new ArrayList<>();
            List<Fragment> childFMFragments = fragment.getChildFragmentManager().getFragments();
            List<Fragment> fmFragments = fragment.getFragmentManager().getFragments();
            fmFragments.retainAll(childFMFragments);
            nestedFragments.addAll(childFMFragments);
            nestedFragments.addAll(fmFragments);
            getVisibleFragments(nestedFragments, visibleFragments);
            if (fragment != null && fragment.isVisible()) {
                visibleFragments.add(fragment);
            }
        }
    }
    return visibleFragments;
}

А вот использование:

List<Fragment> allVisibleFragments = getVisibleFragments(searchFragments, visibleFragments);

Например:

List<Fragment> visibleFragments = new ArrayList<>();
List<Fragment> searchFragments = MainActivity.this.getSupportFragmentManager().getFragments();
Toast.makeText(this, ""+getVisibleFragments(searchFragments, visibleFragments), Toast.LENGTH_LONG).show();
0 голосов
/ 13 марта 2019

Я должен был сделать это совсем недавно, и ни один из ответов здесь действительно не подходил для этого сценария.

Если вы уверены, что будет виден только один фрагмент (в полноэкранном режиме), так что действительно хотите найти то, что находится на вершине backstack. Например, как Kotlin для Fragment:

import androidx.fragment.app.Fragment

fun Fragment.setVisibilityChangeListener(clazz: Class<out Fragment>, listener: (Boolean) -> Unit) {
    fragmentManager?.run {
        addOnBackStackChangedListener {
            val topFragmentTag = getBackStackEntryAt(backStackEntryCount - 1).name
            val topFragment = findFragmentByTag(topFragmentTag)
            listener(topFragment != null && topFragment::class.java == clazz)
        }
    }
}

И используйте это как:

class MyFragment: Fragment {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        setVisibilityChangeListener(this::class.java) { visible -> 
            // Do stuff
        }
    }
}
0 голосов
/ 16 июля 2015

Использование шины событий (например, Otto , EventBus или RxJava Bus ) особенно удобно в этих ситуациях.

Хотя этоподход не обязательно передает вам видимый в данный момент фрагмент как объект (хотя это тоже можно сделать, но это приводит к более длинной цепочке вызовов), он позволяет вам выполнять действия с видимым в данный момент фрагментом (что обычно и требуется)зная текущий видимый фрагмент).

  1. убедитесь, что вы соблюдаете жизненный цикл фрагмента и регистрируете / отменяете регистрацию шины событий в подходящее время
  2. в точке, где вам нужно знатьна данный момент видим фрагмент и выполняем набор действий.снимите событие с помощью шины событий.

все видимые фрагменты, зарегистрированные на шине, выполнят необходимое действие.

0 голосов
/ 21 сентября 2015

Немного странно, но я посмотрел на FragmentManager $ FragmentManagerImpl и у меня работает следующее:

public static Fragment getActiveFragment(Activity activity, int index)
{
    Bundle bundle = new Bundle();
    String key = "i";
    bundle.putInt(key,index);
    Fragment fragment=null;
    try
    {
        fragment = activity.getFragmentManager().getFragment(bundle, key);
    } catch(Exception e){}
    return fragment;
}

, чтобы получить первый активный фрагмент, используя 0 в качестве индекса

0 голосов
/ 06 октября 2015
public Fragment getVisibleFragment() {
    FragmentManager fragmentManager = getSupportFragmentManager();
    List<Fragment> fragments = fragmentManager.getFragments();
    if(fragments != null) {
        for (Fragment fragment : fragments) {
            if (fragment != null && fragment.isVisible())
                return fragment;
        }
    }
    return null;
}

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

Возвращаемый фрагмент можно сравнить с фрагментом, который вы хотите поместить в стек.

0 голосов
/ 16 сентября 2018

Я нашел findFragmentByTag не так удобно. Если у вас есть String currentFragmentTag в вашем Activity или родительском Fragment, вам нужно сохранить его в onSaveInstanceState и восстановить в onCreate. Даже если вы сделаете это, когда воссоздан Activity, onAttachFragment будет вызван раньше onCreate, поэтому вы не можете использовать currentFragmentTag в onAttachFragment (например, обновить некоторые представления на основе currentFragmentTag), потому что возможно, он еще не восстановлен.

Я использую следующий код:

Fragment getCurrentFragment() {
    List<Fragment> fragments = getSupportFragmentManager().getFragments();
    if(fragments.isEmpty()) {
        return null;
    }
    return fragments.get(fragments.size()-1);
}

В документе FragmentManager говорится, что

Порядок фрагментов в списке - это порядок, в котором они были добавлены или присоединены.

Когда вам нужно сделать что-то на основе текущего типа фрагмента, просто используйте getCurrentFragment() instance of MyFragment вместо currentFragmentTag.equals("my_fragment_tag").

Обратите внимание, что getCurrentFragment() в onAttachFragment не получит прикрепленный Fragment, но предыдущий прикрепленный.

...