Last active
June 13, 2022 02:36
-
-
Save farhanahmed95/a33aaabdb4fb602d515005c34e864ffe to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
xmlns:app="http://schemas.android.com/apk/res-auto" | |
android:layout_width="match_parent" | |
android:id="@+id/activityMain" | |
android:layout_height="match_parent"> | |
<fragment | |
app:navGraph="@navigation/main_nav" | |
app:defaultNavHost="true" | |
android:id="@+id/navHostFragment" | |
android:name="com.example.MainHostFragment" | |
android:layout_width="0dp" | |
android:layout_height="0dp" | |
app:layout_constraintBottom_toBottomOf="parent" | |
app:layout_constraintEnd_toEndOf="parent" | |
app:layout_constraintStart_toStartOf="parent" | |
app:layout_constraintTop_toTopOf="parent" /> | |
</androidx.constraintlayout.widget.ConstraintLayout> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.content.Context; | |
import android.content.res.TypedArray; | |
import android.os.Bundle; | |
import android.util.AttributeSet; | |
import android.view.LayoutInflater; | |
import android.view.View; | |
import android.view.ViewGroup; | |
import androidx.annotation.CallSuper; | |
import androidx.annotation.NavigationRes; | |
import androidx.annotation.NonNull; | |
import androidx.annotation.Nullable; | |
import androidx.fragment.app.Fragment; | |
import androidx.fragment.app.FragmentContainerView; | |
import androidx.fragment.app.FragmentManager; | |
import androidx.navigation.NavController; | |
import androidx.navigation.NavGraph; | |
import androidx.navigation.NavHost; | |
import androidx.navigation.NavHostController; | |
import androidx.navigation.Navigation; | |
import androidx.navigation.Navigator; | |
import androidx.navigation.fragment.DialogFragmentNavigator; | |
import androidx.navigation.fragment.FragmentNavigator; | |
import androidx.navigation.fragment.NavHostFragment; | |
public class MainHostFragment extends Fragment implements NavHost { | |
private static final String KEY_GRAPH_ID = "android-support-nav:fragment:graphId"; | |
private static final String KEY_START_DESTINATION_ARGS = | |
"android-support-nav:fragment:startDestinationArgs"; | |
private static final String KEY_NAV_CONTROLLER_STATE = | |
"android-support-nav:fragment:navControllerState"; | |
private static final String KEY_DEFAULT_NAV_HOST = "android-support-nav:fragment:defaultHost"; | |
/** | |
* Find a {@link NavController} given a local {@link Fragment}. | |
* | |
* <p>This method will locate the {@link NavController} associated with this Fragment, | |
* looking first for a {@link NavHostFragment} along the given Fragment's parent chain. | |
* If a {@link NavController} is not found, this method will look for one along this | |
* Fragment's {@link Fragment#getView() view hierarchy} as specified by | |
* {@link Navigation#findNavController(View)}.</p> | |
* | |
* @param fragment the locally scoped Fragment for navigation | |
* @return the locally scoped {@link NavController} for navigating from this {@link Fragment} | |
* @throws IllegalStateException if the given Fragment does not correspond with a | |
* {@link NavHost} or is not within a NavHost. | |
*/ | |
@NonNull | |
public static NavController findNavController(@NonNull Fragment fragment) { | |
Fragment findFragment = fragment; | |
while (findFragment != null) { | |
if (findFragment instanceof MainHostFragment) { | |
return ((MainHostFragment) findFragment).getNavController(); | |
} | |
Fragment primaryNavFragment = findFragment.getParentFragmentManager() | |
.getPrimaryNavigationFragment(); | |
if (primaryNavFragment instanceof MainHostFragment) { | |
return ((MainHostFragment) primaryNavFragment).getNavController(); | |
} | |
findFragment = findFragment.getParentFragment(); | |
} | |
// Try looking for one associated with the view instead, if applicable | |
View view = fragment.getView(); | |
if (view != null) { | |
return Navigation.findNavController(view); | |
} | |
throw new IllegalStateException("Fragment " + fragment | |
+ " does not have a NavController set"); | |
} | |
private NavHostController mNavController; | |
private Boolean mIsPrimaryBeforeOnCreate = null; | |
// State that will be saved and restored | |
private int mGraphId; | |
private boolean mDefaultNavHost; | |
/** | |
* Create a new NavHostFragment instance with an inflated {@link NavGraph} resource. | |
* | |
* @param graphResId resource id of the navigation graph to inflate | |
* @return a new NavHostFragment instance | |
*/ | |
@NonNull | |
public static MainHostFragment create(@NavigationRes int graphResId) { | |
return create(graphResId, null); | |
} | |
/** | |
* Create a new NavHostFragment instance with an inflated {@link NavGraph} resource. | |
* | |
* @param graphResId resource id of the navigation graph to inflate | |
* @param startDestinationArgs arguments to send to the start destination of the graph | |
* @return a new NavHostFragment instance | |
*/ | |
@NonNull | |
public static MainHostFragment create(@NavigationRes int graphResId, | |
@Nullable Bundle startDestinationArgs) { | |
Bundle b = null; | |
if (graphResId != 0) { | |
b = new Bundle(); | |
b.putInt(KEY_GRAPH_ID, graphResId); | |
} | |
if (startDestinationArgs != null) { | |
if (b == null) { | |
b = new Bundle(); | |
} | |
b.putBundle(KEY_START_DESTINATION_ARGS, startDestinationArgs); | |
} | |
final MainHostFragment result = new MainHostFragment(); | |
if (b != null) { | |
result.setArguments(b); | |
} | |
return result; | |
} | |
/** | |
* Returns the {@link NavController navigation controller} for this navigation host. | |
* This method will return null until this host fragment's {@link #onCreate(Bundle)} | |
* has been called and it has had an opportunity to restore from a previous instance state. | |
* | |
* @return this host's navigation controller | |
* @throws IllegalStateException if called before {@link #onCreate(Bundle)} | |
*/ | |
@NonNull | |
@Override | |
public final NavController getNavController() { | |
if (mNavController == null) { | |
throw new IllegalStateException("NavController is not available before onCreate()"); | |
} | |
return mNavController; | |
} | |
@CallSuper | |
@Override | |
public void onAttach(@NonNull Context context) { | |
super.onAttach(context); | |
// TODO This feature should probably be a first-class feature of the Fragment system, | |
// but it can stay here until we can add the necessary attr resources to | |
// the fragment lib. | |
if (mDefaultNavHost) { | |
getParentFragmentManager().beginTransaction() | |
.setPrimaryNavigationFragment(this) | |
.commit(); | |
} | |
} | |
@CallSuper | |
@Override | |
public void onCreate(@Nullable Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
final Context context = requireContext(); | |
mNavController = new NavHostController(context); | |
mNavController.setLifecycleOwner(this); | |
mNavController.setOnBackPressedDispatcher(requireActivity().getOnBackPressedDispatcher()); | |
// Set the default state - this will be updated whenever | |
// onPrimaryNavigationFragmentChanged() is called | |
mNavController.enableOnBackPressed( | |
mIsPrimaryBeforeOnCreate != null && mIsPrimaryBeforeOnCreate); | |
mIsPrimaryBeforeOnCreate = null; | |
mNavController.setViewModelStore(getViewModelStore()); | |
onCreateNavController(mNavController); | |
Bundle navState = null; | |
if (savedInstanceState != null) { | |
navState = savedInstanceState.getBundle(KEY_NAV_CONTROLLER_STATE); | |
if (savedInstanceState.getBoolean(KEY_DEFAULT_NAV_HOST, false)) { | |
mDefaultNavHost = true; | |
getParentFragmentManager().beginTransaction() | |
.setPrimaryNavigationFragment(this) | |
.commit(); | |
} | |
mGraphId = savedInstanceState.getInt(KEY_GRAPH_ID); | |
} | |
if (navState != null) { | |
// Navigation controller state overrides arguments | |
mNavController.restoreState(navState); | |
} | |
if (mGraphId != 0) { | |
// Set from onInflate() | |
mNavController.setGraph(mGraphId); | |
} else { | |
// See if it was set by NavHostFragment.create() | |
final Bundle args = getArguments(); | |
final int graphId = args != null ? args.getInt(KEY_GRAPH_ID) : 0; | |
final Bundle startDestinationArgs = args != null | |
? args.getBundle(KEY_START_DESTINATION_ARGS) | |
: null; | |
if (graphId != 0) { | |
mNavController.setGraph(graphId, startDestinationArgs); | |
} | |
} | |
} | |
/** | |
* Callback for when the {@link #getNavController() NavController} is created. If you | |
* support any custom destination types, their {@link Navigator} should be added here to | |
* ensure it is available before the navigation graph is inflated / set. | |
* <p> | |
* By default, this adds a {@link FragmentNavigator}. | |
* <p> | |
* This is only called once in {@link #onCreate(Bundle)} and should not be called directly by | |
* subclasses. | |
* | |
* @param navController The newly created {@link NavController}. | |
*/ | |
@SuppressWarnings({"WeakerAccess", "deprecation"}) | |
@CallSuper | |
protected void onCreateNavController(@NonNull NavController navController) { | |
navController.getNavigatorProvider().addNavigator( | |
new DialogFragmentNavigator(requireContext(), getChildFragmentManager())); | |
navController.getNavigatorProvider().addNavigator(createFragmentNavigator()); | |
} | |
@CallSuper | |
@Override | |
public void onPrimaryNavigationFragmentChanged(boolean isPrimaryNavigationFragment) { | |
if (mNavController != null) { | |
mNavController.enableOnBackPressed(isPrimaryNavigationFragment); | |
} else { | |
mIsPrimaryBeforeOnCreate = isPrimaryNavigationFragment; | |
} | |
} | |
/** | |
* Create the FragmentNavigator that this NavHostFragment will use. By default, this uses | |
* {@link FragmentNavigator}, which replaces the entire contents of the NavHostFragment. | |
* <p> | |
* This is only called once in {@link #onCreate(Bundle)} and should not be called directly by | |
* subclasses. | |
* @return a new instance of a FragmentNavigator | |
* @deprecated Use {@link #onCreateNavController(NavController)} | |
*/ | |
@SuppressWarnings("DeprecatedIsStillUsed") | |
@Deprecated | |
@NonNull | |
protected Navigator<? extends FragmentNavigator.Destination> createFragmentNavigator() { | |
return new MainFragmentNavigator(requireContext(), getChildFragmentManager(), | |
getContainerId()); | |
} | |
@Nullable | |
@Override | |
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, | |
@Nullable Bundle savedInstanceState) { | |
FragmentContainerView containerView = new FragmentContainerView(inflater.getContext()); | |
// When added via XML, this has no effect (since this FragmentContainerView is given the ID | |
// automatically), but this ensures that the View exists as part of this Fragment's View | |
// hierarchy in cases where the NavHostFragment is added programmatically as is required | |
// for child fragment transactions | |
containerView.setId(getContainerId()); | |
return containerView; | |
} | |
/** | |
* We specifically can't use {@link View#NO_ID} as the container ID (as we use | |
* {@link androidx.fragment.app.FragmentTransaction#add(int, Fragment)} under the hood), | |
* so we need to make sure we return a valid ID when asked for the container ID. | |
* | |
* @return a valid ID to be used to contain child fragments | |
*/ | |
private int getContainerId() { | |
int id = getId(); | |
if (id != 0 && id != View.NO_ID) { | |
return id; | |
} | |
// Fallback to using our own ID if this Fragment wasn't added via | |
// add(containerViewId, Fragment) | |
return R.id.nav_host_fragment_container; | |
} | |
@Override | |
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { | |
super.onViewCreated(view, savedInstanceState); | |
if (!(view instanceof ViewGroup)) { | |
throw new IllegalStateException("created host view " + view + " is not a ViewGroup"); | |
} | |
Navigation.setViewNavController(view, mNavController); | |
// When added programmatically, we need to set the NavController on the parent - i.e., | |
// the View that has the ID matching this NavHostFragment. | |
if (view.getParent() != null) { | |
View rootView = (View) view.getParent(); | |
if (rootView.getId() == getId()) { | |
Navigation.setViewNavController(rootView, mNavController); | |
} | |
} | |
} | |
@CallSuper | |
@Override | |
public void onInflate(@NonNull Context context, @NonNull AttributeSet attrs, | |
@Nullable Bundle savedInstanceState) { | |
super.onInflate(context, attrs, savedInstanceState); | |
final TypedArray navHost = context.obtainStyledAttributes(attrs, R.styleable.NavHost); | |
final int graphId = navHost.getResourceId(R.styleable.NavHost_navGraph, 0); | |
if (graphId != 0) { | |
mGraphId = graphId; | |
} | |
navHost.recycle(); | |
final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.NavHostFragment); | |
final boolean defaultHost = a.getBoolean(R.styleable.NavHostFragment_defaultNavHost, false); | |
if (defaultHost) { | |
mDefaultNavHost = true; | |
} | |
a.recycle(); | |
} | |
@CallSuper | |
@Override | |
public void onSaveInstanceState(@NonNull Bundle outState) { | |
super.onSaveInstanceState(outState); | |
Bundle navState = mNavController.saveState(); | |
if (navState != null) { | |
outState.putBundle(KEY_NAV_CONTROLLER_STATE, navState); | |
} | |
if (mDefaultNavHost) { | |
outState.putBoolean(KEY_DEFAULT_NAV_HOST, true); | |
} | |
if (mGraphId != 0) { | |
outState.putInt(KEY_GRAPH_ID, mGraphId); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Is it working for <dialog (Dialog fragments) tags ?