Android Navigasyon Mimarisi Bileşeni - Mevcut görünür parçayı al


95

Navigasyon bileşenini denemeden önce, parça işlemlerini manuel olarak yapıyordum ve mevcut parçayı almak için parça etiketini kullandım.

val fragment:MyFragment = supportFragmentManager.findFragmentByTag(tag):MyFragment

Şimdi ana aktivite düzenimde şöyle bir şey var:

<fragment
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/nav_host"
        app:navGraph= "@navigation/nav_item"
        android:name="androidx.navigation.fragment.NavHostFragment"
        app:defaultNavHost= "true"
        />

Navigasyon bileşeni tarafından geçerli olarak görüntülenen parçayı nasıl alabilirim? Yapıyor

supportFragmentManager.findFragmentById(R.id.nav_host)

a döndürür NavHostFragmentve gösterilen 'MyFragment`ımı almak istiyorum.

Teşekkür ederim.


4
Mevcut parça stackoverflow.com/a/50689587/1268507'yi almanın bir yolu yok Neyi başarmaya çalışıyorsunuz? belki bunun için başka bir çözüm vardır.
Alex

Bir kamera niyetini başlatmak, fotoğraf çekmek ve çekilen görüntüyü kullanmak için parçamdan ihtiyacım vardı. Bunu yapmak için bir faaliyet başlattım ve onActivityResultana faaliyetimde sonuç bekledim . Parçayı alamadığım için, tüm bunları basitçe parçanın kendisine taşıdım ve çalışıyor gibi görünüyor.
Alin

Bu parça nesnesi üzerinde bir işlem yapmak istiyor musunuz? Ya da sadece hangi parçanın gösterilmesini istiyorsunuz?
Ranjan

Yanıtlar:


101

Şimdilik bir yol keşfetmeyi başardım ve şu şekilde:

NavHostFragment navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host);
navHostFragment.getChildFragmentManager().getFragments().get(0);

Tabii ki bunun ilk parça olduğunu biliyorsunuz. Hala bu olmadan bir yol araştırıyorum. Bunun en iyi yol olmadığına katılıyorum ama şimdilik bu bir şey olmalı.


6
Çalışan bir çözüm görmek harika. Bundan vazgeçtim ve etkinlik ve parça arasında paylaşılan bir viewModel kullanmaya başladım, Bu, geri çağırmalara veya doğrudan erişime ihtiyaç duymadan olayları aralarında geçirebileceğim anlamına geliyor.
Alin

Bu hata raporu sorununda belirtildiği gibi issuetracker.google.com/issues/119800853 bunu yapmak için doğru yöntem değildir. Lütfen doğru cevabı değiştirmeyi düşünün!
Nicolas Pietri

2
Bahsedildiği gibi çözüm değil, uygun bir çözüm bulunana kadar geçici bir çözümdür.
Andrei Toader

1
Bu işe yarıyor, çok teşekkürler. Hata izleyicide önerildiği gibi getPrimaryNavigationFragment () denedim ama işi tamamlamadı.
Jerry Hu

1
Bu çözüme dayanarak, mevcut parçanın belirli bir tipte (id yerine) olup olmadığını kontrol edebilen bir kotlin işlevi oluşturdum: navHostFragment!!.childFragmentManager.fragments.any { it.javaClass == fragmentClass && it.isVisible }Oldukça benzer çalışıyor. Umarım herkese yardımcı olur!
P Kuijpers

49

Mevcut parça örneğini bulmamın hiçbir yolu yok. Ancak, aşağıdaki kodu kullanarak son eklenen parçanın kimliğini alabilirsiniz.

navController.currentDestination?.getId()

ID'yi navigasyon dosyasında döndürür. Bu yardımcı olur umarım.


Cevabınız için teşekkür ederim. Parçayı geri almam gerekiyordu, böylece onunla etkileşim kurabilirim. NavController onu geri döndüremediğinden, etkinlik ve parçaları arasında konuşmak için paylaşılan bir görünüm modeli kullanmayı bıraktım
Alin

7
Döndürülen id'nin nav xml'deki id ile eşleşmesini bekliyordum, ancak uymuyor, bu yüzden navController.getCurrentDestination (). getId () == R.id.myfrag
Leres Aldtai

4
@LeresAldtai Navigasyon dosyasındaki parçanın kimliğiyle eşleşir.
slhddn

1
Teşekkür ederim @slhddn. Yorumunuz bana yardımcı oldu ve kimliği parçadan alıp bunu çalıştırmayı başardı. Başkası için yararlı olması durumunda kodumla buraya bir cevap ekledim. Şerefe.
Francislainy Campos

31

Nav parçanızın childFragmentManager primaryNavigationFragment özelliğine bakmanız gerekir, bu, geçerli görüntülenen parçanın başvurulduğu yerdir.

val navHost = supportFragmentManager.findFragmentById(R.id.main_nav_fragment)
    navHost?.let { navFragment ->
        navFragment.childFragmentManager.primaryNavigationFragment?.let {fragment->
                //DO YOUR STUFF
        }
    }
}

2
Bu yöntem artık fragmentManager issuetracker.google.com/issues/119800853
Nicolas Pietri

bu biraz sorun gibi görünüyor. Yukarı navigasyonu işleme onSupportNaigateUp ()
filthy_wizard

18

Bu en temiz çözüm gibi görünüyor. Güncelleme: Uzantı işlevi özelliğe değiştirildi. Teşekkürler Igor Wojda .

1. Aşağıdaki uzantıyı oluşturun

import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager

val FragmentManager.currentNavigationFragment: Fragment?
    get() = primaryNavigationFragment?.childFragmentManager?.fragments?.first()

2. Activityile NavHostFragmentböyle kullanımı it:

val currentFragment = supportFragmentManager.currentNavigationFragment

2
Güzel - bunu değiştirirdim - Uzantıyı özellik olarak tanımlardım FragmentManager.currentNavigationFragment(işlev olarak değil)
Igor Wojda

16

Sahip addOnDestinationChangedListeneraktivitede kullanınNavHostFragment

Java için

 NavController navController= Navigation.findNavController(MainActivity.this,R.id.your_nav_host);

        navController.addOnDestinationChangedListener(new NavController.OnDestinationChangedListener() {
            @Override
            public void onDestinationChanged(@NonNull NavController controller, @NonNull NavDestination destination, @Nullable Bundle arguments) {
                Log.e(TAG, "onDestinationChanged: "+destination.getLabel());
            }
        });

Kotlin için

var navController :NavController=Navigation.findNavController(this, R.id.nav_host_fragment)
    navController.addOnDestinationChangedListener { controller, destination, arguments ->
        Log.e(TAG, "onDestinationChanged: "+destination.label);

    }

8

bu geç olabilir ama hala arayanlar için

val currentFragment = NavHostFragment.findNavController(nav_host_fragment).currentDestination?.id

o zaman şöyle bir şey yapabilirsin

if(currentFragment == R.id.myFragment){
     //do something
}

bunun kotlin için olduğuna dikkat edin, java kodu hemen hemen aynı olmalıdır



5
navController().currentDestination?.id

sana şu anki Fragmentkimliğini verecek

private fun navController() = Navigation.findNavController(this, R.id.navHostFragment)

bu id, Navigation Graph XMLdosyanızda fragmenttag altında vermiş olduğunuz id'dir . İsterseniz karşılaştırabilirsiniz currentDestination.label.


4

Çalışan bir çözüm bulundu.

private fun getCurrentFragment(): Fragment? {
    val currentNavHost = supportFragmentManager.findFragmentById(R.id.nav_host_id)
    val currentFragmentClassName = ((this as NavHost).navController.currentDestination as FragmentNavigator.Destination).className
    return currentNavHost?.childFragmentManager?.fragments?.filterNotNull()?.find {
        it.javaClass.name == currentFragmentClassName
    }
}

3

Kullanan bir Aktiviteden, NavHostFragmentaşağıdaki kodu kullanarak Active Fragment.

val fragmentInstance = myNavHostFragment?.childFragmentManager?.primaryNavigationFragment

3

Benim ihtiyacım mevcut görünür parçayı Ebeveyn etkinliğinden almaktır, benim çözümüm

 private LoginFragment getCurrentVisibleFragment() {
        NavHostFragment navHostFragment = (NavHostFragment)getSupportFragmentManager().getPrimaryNavigationFragment();
        FragmentManager fragmentManager = navHostFragment.getChildFragmentManager();
        Fragment loginFragment = fragmentManager.getPrimaryNavigationFragment();
        if(loginFragment instanceof LoginFragment){
            return (LoginFragment)loginFragment;
        }
        return null;
    }

Bu, aynı sorunu olan birine yardımcı olabilir.


Kotlin lang var mı?
IgorGanapolsky

1
Bu benim için mükemmel çalışıyor, diğer cevapların ne olduğundan emin değil misiniz? Belki daha önce işe yaramadı ama şimdi bir cazibe gibi çalışıyor.
Wess

2

@Slhddn cevabına ve yorumuna göre, onu nasıl kullanıyorum ve nav_graph.xml dosyasından parça kimliğini alıyorum :

class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    setSupportActionBar(findViewById(R.id.toolbar))

    val navController = findNavController(this, R.id.nav_host_fragment)

    ivSettingsCog.setOnClickListener {

        if (navController.currentDestination?.id == R.id.updatesFragment) // Id as per set up on nav_graph.xml file
        {
            navController.navigate(R.id.action_updatesFragment_to_settingsFragment)
        }

    }

}

}

1

lütfen getChildFragmentManager()arayabilir misin

NavHostFragment fragment = supportFragmentManager.findFragmentById(R.id.nav_host);
MyFragment frag = (MyFragment) fragment.getChildFragmentManager().findFragmentByTag(tag);

1

Yapmak :

• parçanızdaki bazı düğmelerde:

val navController = findNavController(this)
  navController.popBackStack()

• OnBackPressed () Etkinliğinizde

override fun onBackPressed() {
        val navController = findNavController(R.id.nav_host_fragment)
        val id = navController.currentDestination?.getId()
        if (id == R.id.detailMovieFragment){
            navController.popBackStack()
            return
        }

        super.onBackPressed()
    } 

1

Parçanızın örneğine ihtiyacınız varsa, şu şekilde gidebilirsiniz:

(Etkinlik) => supportFragmentManager.fragments.first().childFragmentManager.fragments.first()

Bu çok çirkin ama oradan oynamak istediğiniz parçanın bir örneği olup olmadığını kontrol edebilirsiniz.


1

Androidx'te, gerekli parçayı bulmak için birçok yöntem denedim NavHostFragment. Sonunda aşağıdaki yöntemle çözebilirim

public Fragment getFunctionalFragment (String tag_name)
{
    NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.nav_host_fragment);
    FragmentManager navHostManager = Objects.requireNonNull(navHostFragment).getChildFragmentManager();

    Fragment fragment=null;
    List fragment_list = navHostManager.getFragments();

    for (int i=0; i < fragment_list.size() ; i ++ )
    {
        if ( fragment_list.get(i) instanceof HomeFragment && tag_name.equals("frg_home")) {
            fragment = (HomeFragment) fragment_list.get(i);
            break;
        }
    }

    return fragment;
}

1
SO'ya hoş geldiniz! Lütfen cevabınızı göndermeden önce kontrol edin ... Kod net değil. Başka bir konu: eğer sadece kod getiriyorsanız, çözümünüzü biraz, en fazla 16 cevap daha olduğunda açıklayın, bu yüzden cevabınızın Artılarını açıklamalısınız.
David García Bodego

1

Navhost fragmanındaki ilk fragman mevcut fragmandır

Fragment navHostFragment = getSupportFragmentManager().getPrimaryNavigationFragment();
if (navHostFragment != null) 
{Fragment fragment = navHostFragment.getChildFragmentManager().getFragments().get(0);}

Cevabınızı biraz daha detaylandırır mısınız? Belki kodunuzu açıklayarak.
Yirmi

Yalnızca kod yanıtları önerilmez. Lütfen cevabınızın sorunu neden ve nasıl çözdüğünü açıklayın.
Igor F.

1

İlk olarak, mevcut parçayı id'ye göre alırsınız, ardından bu kimliğe bağlı olarak parçayı bulabilirsiniz.

int id = navController.getCurrentDestination().getId();
Fragment fragment = getSupportFragmentManager().findFragmentById(id);

0

Andrei Toaders yanıtını birleştirdim ve Mukul Bhardwajs yanıtını bir OnBackStackChangedListener.

Nitelik olarak:

private FooFragment fragment;

Benim .. De onCreate

NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.nav_host);
FragmentManager navHostManager = Objects.requireNonNull(navHostFragment).getChildFragmentManager();
FragmentManager.OnBackStackChangedListener listener = () -> {
        List<Fragment> frags = navHostManager.getFragments();
        if(!frags.isEmpty()) {
            fragment = (FooFragment) frags.get(0);
        }
};
navController.addOnDestinationChangedListener((controller, destination, arguments) -> {
        if(destination.getId()==R.id.FooFragment){
            navHostManager.addOnBackStackChangedListener(listener);
        } else {
            navHostManager.removeOnBackStackChangedListener(listener);
           fragment = null;
        }
});

Bu şekilde, daha sonra görüntülenecek bir parça elde edebilirim. Hatta bir tanesi döngü yapabilir fragsve birden fazla parçayı kontrol edebilir instanceof.


0

Bir alt gezinme görünümü ayarlamak için bunu yapmam gerekiyor ve bunu şu şekilde yaptım:

val navController = Navigation.findNavController(requireActivity(), R.id.nav_tabs_home)
        val bottomNavBar: BottomNavigationView = nav_content_view
        NavigationUI.setupWithNavController(bottomNavBar, navController)

0

Bunu başarmanın en iyi yolu, bir parça yaşam döngüsü geri araması kaydetmektir .

Asıl soruya göre, eğer sizin NavHostFragmenttanımınız ...

<fragment
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/nav_host"
        app:navGraph= "@navigation/nav_item"
        android:name="androidx.navigation.fragment.NavHostFragment"
        app:defaultNavHost= "true"
        />

Sonra ana faaliyetinizde onCreate(..)...

nav_host.childFragmentManager.registerFragmentLifecycleCallbacks(
    object:FragmentManager.FragmentLifecycleCallbacks() {
        override fun onFragmentViewCreated(
            fm: FragmentManager, f: Fragment, v: View,
            savedInstanceState: Bundle?
        ) {
            // callback method always called whenever a
            // fragment is added, or, a back-press returns
            // to the start-destination
        }
    }
)

Gereksinimlerinize uyması için diğer geri arama yöntemleri geçersiz kılınabilir.


0

Bu çözüm çoğu durumda işe yarayacaktır Şunu deneyin:

val mainFragment = fragmentManager?.primaryNavigationFragment?.parentFragment?.parentFragment as MainFragment

veya bu:

val mainFragment = fragmentManager?.primaryNavigationFragment?.parentFragment as MainFragment

0

Bu kod benden çalışıyor

NavDestination current = NavHostFragment.findNavController(getSupportFragmentManager().getPrimaryNavigationFragment().getFragmentManager().getFragments().get(0)).getCurrentDestination();

switch (current.getId()) {
    case R.id.navigation_saved:
        // WRITE CODE
        break;
}

0

Bu benim için çalışıyor

(navController.currentDestination as FragmentNavigator.Destination).className 

canonicalNameParçanın geri dönecek


Bu Yansıma gibi görünüyor
IgorGanapolsky

0

bu geç olabilir, ancak daha sonra birine yardımcı olabilir.

iç içe geçmiş gezinme kullanıyorsanız, Kotlin'de böyle bir kimlik alabilirsiniz

val nav = Navigation.findNavController(requireActivity(), R.id.fragment_nav_host).currentDestination

ve bu fragment_nav_host.xml'deki parçalardan biridir

<fragment
    android:id="@+id/sampleFragment"
    android:name="com.app.sample.SampleFragment"
    android:label="SampleFragment"
    tools:layout="@layout/fragment_sample" />

ve ihtiyacın olan her şeyi böyle kontrol edebilirsin

if (nav.id == R.id.sampleFragment || nav.label == "SampleFragment"){}

0

Nihayet, hala arama yapmakta olanlarınız için çalışan bir çözüm Aslında bu çok basit ve geri aramayı kullanarak bunu başarabilirsiniz.

bu adımları takip et:

  1. Örneği onCreate () etkinliğinden almak istediğiniz parçanın içinde bir dinleyici oluşturun

    public class HomeFragment extends Fragment {
    
    private OnCreateFragment createLIstener;
    
    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        createLIstener.onFragmentCreated(this);
        View root = inflater.inflate(R.layout.fragment_home, container, false);
        //findViews(root);
        return root;
    }
    
    @Override
    public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
        super.onCreateOptionsMenu(menu, inflater);
        inflater.inflate(R.menu.menu_main, menu);
    
    }
    
    @Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
        if (item.getItemId()==R.id.action_show_filter){
            //do something
        }
        return super.onOptionsItemSelected(item);
    }
    
    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        try {
            createLIstener = (OnCreateFragment) context;
        } catch (ClassCastException e) {
            throw new ClassCastException(context.toString() + " must implement OnArticleSelectedListener");
            }
        }
    
        public interface OnCreateFragment{
            void onFragmentCreated(Fragment f);
        }
    }
    
  2. Dinleyicinizi ana bilgisayar Parçasına / Etkinliğine uygulayın

    public class MainActivity extends AppCompatActivity implements HomeFragment.OnCreateFragment {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            BottomNavigationView navView = findViewById(R.id.nav_view);
           // Passing each menu ID as a set of Ids because each
           // menu should be considered as top level destinations.
            AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(
                    R.id.navigation_home,
                    R. ----)
            .build();
            NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
            NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
            NavigationUI.setupWithNavController(navView, navController);
        }
    
        @Override
        public void onFragmentCreated(Fragment f) {
            if (f!=null){
                H.debug("fragment created listener: "+f.getId());
                f.setHasOptionsMenu(true);
            }else {
                H.debug("fragment created listener: NULL");
            }
        }
    }
    

Ve işi yapmak için ihtiyacın olan her şey bu. Umarım bu birine yardım eder


0

1 parça, Kotlin, Navigasyon kullanımı ile anlayabileceğim en iyi yol:

Düzen dosyanıza şu etiketi ekleyin: "android: tag =" main_fragment_tag ""

<fragment
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/nav_host"
        app:navGraph= "@navigation/nav_item"
        android:tag="main_fragment_tag"
        android:name="androidx.navigation.fragment.NavHostFragment"
        app:defaultNavHost= "true"
        />

Aktivitenizde:

val navHostFragment = supportFragmentManager.findFragmentByTag("main_fragment_tag") as NavHostFragment
val mainFragment = navHostFragment.childFragmentManager.fragments[0] as MainFragment
mainFragment.mainFragmentMethod()

0
val fragment: YourFragment? = yourNavHost.findFragment()

Not: findFragmentuzantı işlevi androidx.fragment.apppakette bulunur ve genel işlevi


-2

Aktivitenizde bir parça nesnesi tanımlayın. Ve her bir parçadan, bu yöntemi bir parça nesnesi geçirerek çağırın, Öyleyse, statik parça nesnesi, her seferinde geçerli gösteren parça tarafından geçersiz kılınacaktır.

//method in MainActivity
private static Fragment fragment;

public void setFragment(Fragment fragment){
this.fragment = fragment;
}

//And from your fragment class, you can call
((<yourActivity in which fragment present>)getActivity()).setFragment(<your fragment object>);

//if you want to set it directly;
 ((<yourActivity in which fragment present>)getActivity()).fragment=<your fragment object>;

Daha iyi bir yaklaşım için parçadan etkinliğe geri aramayı da ayarlayabilir ve mevcut parça nesnenizi iletebilirsiniz.


2
Zaman ayırdığın için teşekkürler. Navigasyon bileşeninin kendisinden kullanılacak bir şey arıyordum.
Alin
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.