Android नेविगेशन आर्किटेक्चर घटक - वर्तमान दृश्यमान टुकड़ा प्राप्त करें


103

नेविगेशन घटक को आज़माने से पहले मैंने मैन्युअल रूप से टुकड़ा लेनदेन किया था और वर्तमान टुकड़े को लाने के लिए टुकड़ा टैग का उपयोग किया था।

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

अब मेरे मुख्य गतिविधि लेआउट में मेरे पास कुछ इस तरह है:

<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"
        />

मैं नेविगेशन घटक द्वारा वर्तमान प्रदर्शित टुकड़े को कैसे पुनः प्राप्त कर सकता हूं? करते हुए

supportFragmentManager.findFragmentById(R.id.nav_host)

एक रिटर्न देता है NavHostFragmentऔर मैं अपने दिखाए गए 'MyFragment` को पुनः प्राप्त करना चाहता हूं।

धन्यवाद।


4
वर्तमान टुकड़ा stackoverflow.com/a/50689587/1268507 को पुनः प्राप्त करने का कोई तरीका नहीं है जिसे आप प्राप्त करने की कोशिश कर रहे हैं? शायद इसके लिए कोई और उपाय हो।
एलेक्स

मुझे अपने इरादे से एक कैमरा इरादा शुरू करने, एक तस्वीर लेने और ली गई छवि का उपयोग करने की आवश्यकता थी। ऐसा करने के लिए, मैंने एक गतिविधि शुरू की है onActivityResultऔर अपनी मुख्य गतिविधि के परिणाम का इंतजार किया है । चूंकि मुझे टुकड़ा नहीं मिला, इसलिए मैंने बस इस टुकड़े को स्वयं में स्थानांतरित कर दिया और काम करने लगता है।
अलीन

क्या आप उस खंड वस्तु पर एक ऑपरेशन करना चाहते हैं। या बस आप चाहते हैं कि कौन सा टुकड़ा दिखाया गया है?
रंजन

जवाबों:


106

मैं अभी के लिए एक रास्ता खोजने में कामयाब रहा और यह इस प्रकार है:

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

बेशक आप जानते हैं कि यह पहला टुकड़ा है। मैं अभी भी इसके बिना एक तरीके की जांच कर रहा हूं। मैं मानता हूं कि यह सबसे अच्छा तरीका नहीं है लेकिन अभी के लिए कुछ होना चाहिए।


7
यह काम कर समाधान देखने के लिए बहुत अच्छा है। मैंने इस पर ध्यान दिया और गतिविधि और टुकड़े के बीच एक साझा दृश्यमॉडल का उपयोग करना शुरू कर दिया, इसका मतलब है कि मैं कॉलबैक या प्रत्यक्ष पहुंच की आवश्यकता के बिना उनके बीच की घटनाओं को पारित कर सकता हूं।
एलिन

1
जैसा कि इस बग रिपोर्ट में जारी किया गया है, जारी करने वाला पटाखा .google.com / issues / 119800853 यह करने का सही तरीका नहीं है। कृपया सही उत्तर बदलने पर विचार करें!
निकोलस पिएट्री

2
जैसा कि उल्लेख किया गया है, यह समाधान नहीं है, यह एक समाधान है जब तक कि एक उचित समाधान नहीं मिलता है।
आंद्रेई टॉडर

1
यह काम करता है, बहुत धन्यवाद। मैंने बग ट्रैकर में सुझाव के अनुसार getPrimaryNavigationFragment () की कोशिश की, लेकिन यह काम नहीं करता है।
जेरी हू

1
इस समाधान के आधार पर मैंने एक कोटलिन फ़ंक्शन बनाया है जो यह जांच सकता है कि वर्तमान टुकड़ा एक विशिष्ट प्रकार का है (आईडी के बजाय): navHostFragment!!.childFragmentManager.fragments.any { it.javaClass == fragmentClass && it.isVisible }काफी समान है। आशा है कि यह किसी की मदद करेंगे!
पी कुइजपर्स

51

कोई तरीका नहीं है जिससे मैं वर्तमान खंड उदाहरण को पुनः प्राप्त कर सकूं। हालांकि, आप नीचे दिए गए कोड का उपयोग करके अंतिम रूप से जोड़े गए टुकड़े की आईडी प्राप्त कर सकते हैं।

navController.currentDestination?.getId()

यह नेविगेशन फाइल में आईडी देता है। उम्मीद है की यह मदद करेगा।


आपके उत्तर के लिए धन्यवाद। मुझे खंड को पुनः प्राप्त करने की आवश्यकता थी ताकि मैं इसके साथ बातचीत कर सकूं। चूंकि नावकंट्रोलर इसे वापस नहीं कर सकता है, मैंने गतिविधि और इसके अंशों के बीच बात करने के लिए एक साझा दृश्यम का उपयोग करके समाप्त किया
अलाइन

8
मुझे उम्मीद थी कि नौसेना आईडी में रिटर्न आईडी आईडी से मेल खाता है, लेकिन ऐसा नहीं है, इसलिए दूसरे शब्दों में आप navController.getCurrentDestination ()। getId () == R.id.myfrag
Leres Aldtai

4
@LeresAldtai यह नेविगेशन फ़ाइल में टुकड़े की आईडी से मेल खाता है।
19 slhddn

1
साभार @slhddn आपकी टिप्पणी ने मुझे मदद की और खंड से आईडी को पुनः प्राप्त करने और यह काम करने में सक्षम था। किसी और के उपयोगी होने के मामले में मेरे कोड के साथ यहां एक उत्तर जोड़ा गया। चीयर्स।
फ्रांसिस्लैनी कैम्पोस

36

आपको चाइल्डफ्रैग्मेंटमैनेजर प्राइमरी नेवीगेशन को देखना चाहिए, अपने नेवी फ्रैगमेंट की प्रॉपर्टी को, यह वह जगह है जहां करंट डिस्पले को रेफर किया जाता है।

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

3
इस विधि को अब टुकड़े टुकड़े में जारी किया
निकोलस

यह एक मुद्दा सा लगता है। नेविगेशन को संभालने के लिए मुझे onSupportNaigateUp () पर कॉल करने के लिए एक्शनबार सेट करना होगा
filthy_wizard

20

यह सबसे साफ समाधान की तरह लगता है। अद्यतन: संपत्ति में परिवर्तन विस्तार समारोह। धन्यवाद इगोर वोज्डा

1. निम्नलिखित एक्सटेंशन बनाएं

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

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

2. इस तरह से उपयोग के Activityसाथ NavHostFragment:

val currentFragment = supportFragmentManager.currentNavigationFragment

2
नाइस - एक मैं इसे बदल FragmentManager.currentNavigationFragment
दूंगा

17

addOnDestinationChangedListenerगतिविधि होने में उपयोग करेंNavHostFragment

जावा के लिए

 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());
            }
        });

कोटलिन के लिए

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

    }

9

यह देर हो सकती है लेकिन किसी को भी, जो अभी भी देख रहा है

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

तो आप ऐसा कुछ कर सकते हैं

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

ध्यान दें कि यह कोटलिन के लिए है, जावा कोड लगभग समान होना चाहिए


2
यहाँ जावा कोड, stackoverflow.com/a/60539704/4291272
फैसल शेख

5
navController().currentDestination?.id

आप अपना वर्तमान Fragmentआईडी कहां देंगे

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

यह आईडी वह आईडी है जो आपने टैग के Navigation Graph XMLतहत अपनी फाइल में दी है fragment। आप currentDestination.labelचाहें तो तुलना भी कर सकते हैं।


4

काम करने का हल मिला।

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
    }
}

4

मेरी आवश्यकता पेरेंट गतिविधि से वर्तमान दृश्यमान टुकड़ा प्राप्त करना है, मेरा समाधान है

 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;
    }

यह कुछ एक ही समस्या के साथ मदद कर सकता है।


कोटलिन लैंग मिला?
इगोरगानापोलस्की

1
यह मेरे लिए पूरी तरह से काम करता है, सुनिश्चित नहीं है कि अन्य उत्तरों के साथ क्या हो रहा है? शायद यह पहले काम नहीं करता था, लेकिन अब यह एक आकर्षण की तरह काम करता है।
वेस

3

का उपयोग करने वाली गतिविधि से NavHostFragment, आप नीचे दिए गए कोड का उपयोग कर के उदाहरण को पुनः प्राप्त कर सकते हैं Active Fragment

val fragmentInstance = myNavHostFragment?.childFragmentManager?.primaryNavigationFragment

2

@Slhddn के उत्तर के अनुसार और टिप्पणी करें कि मैं इसे कैसे उपयोग कर रहा हूं और nav_graph.xml फ़ाइल से खंड आईडी को पुनः प्राप्त कर रहा हूं :

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

क्या आप getChildFragmentManager()कॉल के साथ जाँच कर सकते हैं

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

1

बनाना :

• आपके टुकड़े में कुछ बटन में:

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

• आपकी गतिविधि पर

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

यदि आपको अपने टुकड़े के उदाहरण की आवश्यकता है, तो आप इसके साथ जा सकते हैं:

(गतिविधि) => supportFragmentManager.fragments.first().childFragmentManager.fragments.first()

यह बहुत ही बदसूरत है, लेकिन वहाँ से आप यह जाँच सकते हैं कि यह उस टुकड़े का उदाहरण है जिसे आप अपने साथ खेलना चाहते हैं


1

Androidx पर, मैंने आवश्यक टुकड़े को खोजने के लिए कई तरीकों की कोशिश की है NavHostFragment। अंत में मैं इसे नीचे विधि से क्रैक कर सकता था

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
एसओ में आपका स्वागत है! कृपया, अपना उत्तर पोस्ट करने से पहले, इसे जांचें ... कोड स्पष्ट नहीं है। एक और मुद्दा: यदि आप केवल कोड ला रहे हैं, तो अपने समाधान को थोड़ा स्पष्ट करें, अधिकतम जब 16 और उत्तर हों, तो आपको अपने उत्तर के पेशेवरों को समझाना चाहिए।
डेविड गार्सिया बोडेगो

1

नवहोस टुकड़े में पहला टुकड़ा वर्तमान टुकड़ा है

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

क्या आप अपने उत्तर पर थोड़ा और विस्तार कर सकते हैं? शायद अपने कोड की व्याख्या करके।
बीस

कोड-केवल उत्तर हतोत्साहित किए जाते हैं। कृपया एक स्पष्टीकरण प्रदान करें कि आपका उत्तर समस्या का समाधान क्यों और कैसे करता है।
इगोर एफ।

1

सबसे पहले, आपको आईडी द्वारा वर्तमान टुकड़ा मिलता है, फिर आप उस आईडी के आधार पर टुकड़े को पा सकते हैं।

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

0

मैंने आंद्रेई टोआइटर्स के जवाब और मुकुल भारद्वाज के जवाब को एक साथ जोड़ दियाOnBackStackChangedListener

एक विशेषता के रूप में:

private FooFragment fragment;

मेरे में 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;
        }
});

इस तरह से मुझे एक टुकड़ा मिल सकता है, जिसे बाद में प्रदर्शित किया जाएगा। एक भी लूप करने में सक्षम हो सकता है fragsऔर इसके साथ कई अंशों की जांच कर सकता है instanceof


0

मुझे नीचे नेविगेशन दृश्य सेट करने के लिए ऐसा करने की आवश्यकता है और मैंने इसे इस तरह किया है:

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

0

इसे प्राप्त करने का सबसे अच्छा तरीका एक खंडित जीवनचक्र कॉलबैक को पंजीकृत करना है ।

मूल प्रश्न के अनुसार, यदि आपके NavHostFragmentरूप में परिभाषित किया गया है ...

<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"
        />

फिर अपनी मुख्य गतिविधि में 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
        }
    }
)

आपकी आवश्यकताओं को पूरा करने के लिए अन्य कॉलबैक विधियों को ओवरराइड किया जा सकता है।


0

यह समाधान अधिकांश स्थितियों में काम करेगा।

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

या यह:

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

0

यह कोड मुझसे काम करता है

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

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

0

यह मेरे लिए काम करता है

(navController.currentDestination as FragmentNavigator.Destination).className 

यह canonicalNameआपके टुकड़े की वापसी होगी


1
यह परावर्तन की तरह दिखता है
इगोरगानापोलस्की

0

यह देर हो सकती है लेकिन बाद में किसी की मदद कर सकती है।

यदि आप नेस्टेड नेवीगेशन का उपयोग कर रहे हैं, तो आप कोटलिन में इस तरह से आईडी प्राप्त कर सकते हैं

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

और यह टुकड़े में से एक है

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

और आप इस तरह की जरूरत है सभी की जाँच कर सकते हैं

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

0

अंत में आप में से जो लोग अभी भी खोज रहे हैं, उनके लिए काम करने का समाधान वास्तव में बहुत सरल है और आप कॉलबैक का उपयोग करके इसे प्राप्त कर सकते हैं।

इन कदमों का अनुसरण करें:

  1. उस गतिविधि के अंदर एक श्रोता बनाएं जिसे आप गतिविधि से उदाहरण प्राप्त करना चाहते हैं ()

    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. होस्ट फ्रैगमेंट / गतिविधि में अपने श्रोता को लागू करें

    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");
            }
        }
    }
    

और वह सब कुछ है जो आपको काम करने की आवश्यकता है। यह किसी की मदद करो


0

सबसे अच्छा तरीका मैं 1 टुकड़ा, कोटलिन, नेविगेशन उपयोग के साथ समझ सकता हूं:

अपनी लेआउट फ़ाइल पर टैग जोड़ें: "android: टैग =" 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"
        />

आपकी गतिविधि पर:

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()

नोट: findFragmentविस्तार फ़ंक्शन androidx.fragment.appपैकेज में स्थित है , और यह सामान्य कार्य है


-2

अपनी गतिविधि में एक खंड वस्तु को परिभाषित करें। और प्रत्येक टुकड़े से इस विधि को खंड वस्तु को पास करके कहते हैं, जैसे कि स्थैतिक टुकड़ा वस्तु को वर्तमान में हर बार टुकड़ा दिखाते हुए ओवरराइड किया जाएगा।

//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>;

आप बेहतर दृष्टिकोण के लिए, खंड से गतिविधि तक कॉलबैक भी सेट कर सकते हैं और अपना वर्तमान टुकड़ा ऑब्जेक्ट पास कर सकते हैं।


2
आपके समय के लिए शुक्रिया। मैं नेविगेशन घटक से ही उपयोग करने के लिए कुछ ढूंढ रहा था।
एलिन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.