Android 탐색 아키텍처 구성 요소-현재 보이는 조각 가져 오기


105

탐색 구성 요소를 시도하기 전에 조각 트랜잭션을 수동으로 수행하고 현재 조각을 가져 오기 위해 조각 태그를 사용했습니다.

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)

a를 반환하고 NavHostFragment표시된 'MyFragment'를 검색하고 싶습니다.

감사합니다.


4
현재 조각을 검색 할 수있는 방법이 없습니다. stackoverflow.com/a/50689587/1268507 달성하려는 것은 무엇입니까? 다른 해결책이있을 수 있습니다.
Alex

카메라 의도를 시작하고 사진을 찍고 찍은 이미지를 사용하려면 조각에서 필요했습니다. 이를 위해 활동을 시작하고 onActivityResult주요 활동의 결과를 기다렸습니다 . 조각을 가져올 수 없었기 때문에이 모든 것을 조각 자체로 옮기고 작동하는 것처럼 보입니다.
Alin

해당 조각 개체에 대해 작업을 수행 하시겠습니까? 아니면 어떤 조각이 표시되고 싶습니까?
Ranjan

답변:


106

나는 지금 방법을 발견했으며 다음과 같습니다.

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

물론 당신은 그것이 첫 번째 조각이라는 것을 알고 있습니다. 나는 아직도 이것없이 방법을 조사하고있다. 나는 그것이 최선의 방법이 아니라는 데 동의하지만 지금은 그럴 것입니다.


7
작동하는 솔루션을 보는 것이 좋습니다. 나는 이것을 포기하고 활동과 프래그먼트 사이에 공유 viewModel을 사용하기 시작했습니다. 이것은 콜백이나 직접 액세스 없이도 이벤트를 전달할 수 있음을 의미합니다.
Alin

1
이 버그 보고서 문제 issuetracker.google.com/issues/119800853 에서 언급했듯이 이것은 올바른 방법이 아닙니다. 정답을 변경해보십시오!
Nicolas Pietri

2
언급했듯이 이것은 해결책이 아니며 적절한 해결책을 찾을 때까지 해결 방법입니다.
Andrei Toader

1
이것은 작동합니다, 많은 감사합니다. 버그 추적기에서 제안한대로 getPrimaryNavigationFragment ()를 시도했지만 작업이 완료되지 않았습니다.
제리 후

1
이 솔루션을 기반으로 현재 조각이 특정 유형 (id 대신)인지 확인할 수있는 kotlin 함수를 만들었습니다 navHostFragment!!.childFragmentManager.fragments.any { it.javaClass == fragmentClass && it.isVisible }. 매우 유사하게 작동합니다. 누구에게나 도움이되기를 바랍니다!
P Kuijpers

51

현재 조각 인스턴스를 검색 할 방법이 없습니다. 그러나 아래 코드를 사용하여 마지막으로 추가 된 조각의 ID를 얻을 수 있습니다.

navController.currentDestination?.getId()

내비게이션 파일의 ID를 반환합니다. 도움이 되었기를 바랍니다.


답변 주셔서 감사합니다. 조각과 상호 작용할 수 있도록 조각을 검색해야했습니다. navController가 그것을 반환 할 수 없기 때문에, 나는 공유 된 뷰 모델을 사용하여 활동과 그 조각들 사이에 이야기를 끝냈습니다
Alin

8
반환 된 ID가 nav xml의 ID와 일치한다고 예상했지만 일치하지 않습니다. 즉, navController.getCurrentDestination (). getId () == R.id.myfrag
Leres Aldtai

4
@LeresAldtai 탐색 파일의 조각 ID와 일치합니다.
slhddn

1
@slhddn 감사합니다. 귀하의 의견은 나를 도왔고 조각에서 ID를 검색 하고이 작업을 수행 할 수있었습니다. 다른 사람에게 유용한 경우를 대비하여 여기에 내 코드와 함께 답변을 추가했습니다. 건배.
Francislainy 캄포스

36

탐색 프래그먼트의 childFragmentManager primaryNavigationFragment 속성을 확인해야합니다. 여기에서 현재 표시된 프래그먼트가 참조됩니다.

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

3
이 방법은 지금 fragmentManager에 설명되어 issuetracker.google.com/issues/119800853
니콜라스 Pietri을

이것은 약간의 문제인 것 같습니다. 내가 onSupportNaigateUp에 ()를 호출 얻기 위해 탐색을 액션 바을 설정 한 최대 처리
filthy_wizard

20

이것은 가장 깨끗한 해결책처럼 보입니다. 업데이트 : 확장 기능을 속성으로 변경했습니다. 감사합니다 Igor Wojda .

1. 다음 확장을 만듭니다.

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

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

2. 다음 ActivityNavHostFragment같이 사용합니다.

val currentFragment = supportFragmentManager.currentNavigationFragment

2
니스 - 일이 내가 바꿀 것 - 나는 속성으로 확장 정의 할 FragmentManager.currentNavigationFragment(하지 기능 등)
이고르 Wojda

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

Kotlin의 경우

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
}

이것은 kotlin에 대한 것이며 Java 코드는 거의 동일해야합니다.


2
여기에 자바 코드입니다 stackoverflow.com/a/60539704/4291272은
파이 샤이 크

5
navController().currentDestination?.id

현재 Fragment의 ID를 제공합니다.

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

이 ID는 태그 Navigation Graph XML아래 파일에 부여한 ID입니다 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;
    }

이것은 같은 문제를 가진 사람에게 도움이 될 수 있습니다.


Kotlin 언어가 있습니까?
IgorGanapolsky

1
이것은 나를 위해 완벽하게 작동하지만 다른 답변은 무엇인지 확실하지 않습니까? 이전에는 작동하지 않았을 수도 있지만 지금은 매력처럼 작동합니다.
Wess

3

를 사용하는 활동에서 NavHostFragment아래 코드를 사용하여 Active Fragment.

val fragmentInstance = myNavHostFragment?.childFragmentManager?.primaryNavigationFragment

2

@slhddn 답변 및 주석에 따라 이것이 내가 그것을 사용 하고 nav_graph.xml 파일 에서 조각 ID를 검색하는 방법입니다 .

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

• 활동 onBackPressed ()

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
SO에 오신 것을 환영합니다! 답변을 게시하기 전에 확인하십시오 ... 코드가 명확하지 않습니다. 또 다른 문제 : 방금 코드를 가져 오는 경우 솔루션에 대해 조금, 최대 16 개의 답변이 더있을 때 최대 값을 설명하므로 답변의 장점을 설명해야합니다.
David García Bodego

1

navhost 조각의 첫 번째 조각은 현재 조각입니다.

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

답변에 대해 좀 더 자세히 설명해 주시겠습니까? 아마도 코드를 설명함으로써.
20

코드 전용 답변은 권장하지 않습니다. 귀하의 답변이 문제를 해결하는 이유와 방법을 설명해주십시오.
Igor F.

1

먼저 현재 조각을 id로 얻은 다음 해당 id에 따라 조각을 찾을 수 있습니다.

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

0

나는 결합 안드레이 Toaders 대답 하고 Mukul을 Bhardwajs 응답 과를 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
반사와 같은이 외모
IgorGanapolsky

0

이것은 늦을 수 있지만 나중에 누군가를 도울 수 있습니다.

중첩 탐색을 사용하는 경우 Kotlin에서 이와 같은 ID를 얻을 수 있습니다.

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

그리고 이것은 fragment_nav_host.xml의 조각 중 하나입니다.

<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. onCreate () 활동에서 인스턴스를 가져 오려는 프래그먼트 내부에 리스너를 만듭니다.

    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. 호스트 Fragment / Activity에서 리스너 구현

    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 개의 조각, Kotlin, 내비게이션 사용으로 알아낼 수있는 가장 좋은 방법은 다음과 같습니다.

레이아웃 파일에 "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"
        />

활동 :

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
시간 내 주셔서 감사합니다. 탐색 구성 요소 자체에서 사용할 것을 찾고있었습니다.
Alin
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.