场景问题:
使用BottomNavigationView+Navigation进行底部导航栏页面切换时,每次点击都会重新创建fragment
这个可以延伸到navigation其他类似场景中
解决方法步骤:
1.重写与之相关联的两个类:FragmentNavigator和NavHostFragment(两个类的代码在下面)
2.修改xml之前对androidx.navigation.fragment.NavHostFragment的引用,改为重写的NavHostFragment
浅析问题所在:(可跳过)
存在这种现象原因:
在切换fragment的时候,使用的是replace进行的替换
解决思路:
修改切换的replace,还是用我们之前的hide-show来进行替换
通过manager获取fragment,然后遍历,判断是否当前的fragment已经创建
然后通过isAdded来进行add还是show的显示
到此以为修改完成了,然后问题又出现了,在每次切换的时候manager.getFragments()一直在改变,然后定位问题在:addToBackStack
每次切换的过程中,原先的代码会判断是否加入回退栈,当加入回退栈之后,fragments就会改变,从而在第二步判断fragment是否创建,这步受到影响
因为我的需求是一个底部导航栏切换页面,然后点击返回就退出的场景,所以我删除了将fragment加入回退栈的代码
完毕!
(重新创建的问题必然解决!!!)
NavHostFragment:
public class NavHostFragment 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 androidx.navigation.fragment.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 NavHostFragment) {
return ((NavHostFragment) findFragment).getNavController();
}
Fragment primaryNavFragment = findFragment.requireFragmentManager()
.getPrimaryNavigationFragment();
if (primaryNavFragment instanceof NavHostFragment) {
return ((NavHostFragment) 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 NavController mNavController;
// 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 NavHostFragment 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 NavHostFragment 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 NavHostFragment result = new NavHostFragment();
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) {
requireFragmentManager().beginTransaction()
.setPrimaryNavigationFragment(this)
.commit();
}
}
@CallSuper
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final Context context = requireContext();
mNavController = new NavController(context);
mNavController.getNavigatorProvider().addNavigator(createFragmentNavigator());
Bundle navState = null;
if (savedInstanceState != null) {
navState = savedInstanceState.getBundle(KEY_NAV_CONTROLLER_STATE);
if (savedInstanceState.getBoolean(KEY_DEFAULT_NAV_HOST, false)) {
mDefaultNavHost = true;
requireFragmentManager().beginTransaction()
.setPrimaryNavigationFragment(this)
.commit();
}
}
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);
}
}
}
/**
* Create the FragmentNavigator that this NavHostFragment will use. By default, this uses
* {@link androidx.navigation.fragment.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
*/
@NonNull
protected Navigator<? extends FragmentNavigator.Destination> createFragmentNavigator() {
return new FragmentNavigator(requireContext(), getChildFragmentManager(), getId());
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
FrameLayout frameLayout = new FrameLayout(inflater.getContext());
// When added via XML, this has no effect (since this FrameLayout 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
frameLayout.setId(getId());
return frameLayout;
}
@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");
}
// When added via XML, the parent is null and our view is the root of the NavHostFragment
// but when added programmatically, we need to set the NavController on the parent - i.e.,
// the View that has the ID matching this NavHostFragment.
View rootView = view.getParent() != null ? (View) view.getParent() : view;
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 a = context.obtainStyledAttributes(attrs, R.styleable.NavHostFragment);
final int graphId = a.getResourceId(R.styleable.NavHostFragment_navGraph, 0);
final boolean defaultHost = a.getBoolean(R.styleable.NavHostFragment_defaultNavHost, false);
if (graphId != 0) {
mGraphId = graphId;
}
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);
}
}
}
FragmentNavigator:
@Navigator.Name("fragment")
public class FragmentNavigator extends Navigator<FragmentNavigator.Destination> {
private static final String TAG = "FragmentNavigator";
private static final String KEY_BACK_STACK_IDS = "androidx-nav-fragment:navigator:backStackIds";
private final Context mContext;
@SuppressWarnings("WeakerAccess") /* synthetic access */
final FragmentManager mFragmentManager;
private final int mContainerId;
@SuppressWarnings("WeakerAccess") /* synthetic access */
ArrayDeque<Integer> mBackStack = new ArrayDeque<>();
@SuppressWarnings("WeakerAccess") /* synthetic access */
boolean mIsPendingBackStackOperation = false;
/**
* A fragment manager back stack change listener used to detect a fragment being popped due to
* onBackPressed().
*
* Since a back press is a pop in the FragmentManager not caused by this navigator a flag is
* used to identify operations by this navigator. If the flag is ON, this listener doesn't do
* anything since the change in the fragment manager's back stack was caused by the navigator.
* The flag is reset once this navigator's back stack matches the fragment manager's back stack.
* If the flag is OFF then a change in the back stack was not caused by this navigator, it is
* then appropriate to check if a fragment was popped to dispatch navigator events.
*
* Note that onBackPressed() invokes popBackStackImmediate(), meaning pending transactions - if
* any - before the pop will be executed causing this listener to be called one or more times
* until the flag is reset. Finally, the pop due to pressing back occurs, at which it is
* appropriate to dispatch a navigator popped event.
*/
private final FragmentManager.OnBackStackChangedListener mOnBackStackChangedListener =
new FragmentManager.OnBackStackChangedListener() {
@SuppressLint("RestrictedApi")
@Override
public void onBackStackChanged() {
// If we have pending operations made by us then consume this change, otherwise
// detect a pop in the back stack to dispatch callback.
if (mIsPendingBackStackOperation) {
mIsPendingBackStackOperation = !isBackStackEqual();
return;
}
// The initial Fragment won't be on the back stack, so the
// real count of destinations is the back stack entry count + 1
int newCount = mFragmentManager.getBackStackEntryCount() + 1;
if (newCount < mBackStack.size()) {
// Handle cases where the user hit the system back button
while (mBackStack.size() > newCount) {
mBackStack.removeLast();
}
dispatchOnNavigatorBackPress();
}
}
};
public FragmentNavigator(@NonNull Context context, @NonNull FragmentManager manager,
int containerId) {
mContext = context;
mFragmentManager = manager;
mContainerId = containerId;
}
@Override
protected void onBackPressAdded() {
mFragmentManager.addOnBackStackChangedListener(mOnBackStackChangedListener);
}
@Override
protected void onBackPressRemoved() {
mFragmentManager.removeOnBackStackChangedListener(mOnBackStackChangedListener);
}
/**
* {@inheritDoc}
* <p>
* This method must call
* {@link FragmentTransaction#setPrimaryNavigationFragment(Fragment)}
* if the pop succeeded so that the newly visible Fragment can be retrieved with
* {@link FragmentManager#getPrimaryNavigationFragment()}.
* <p>
* Note that the default implementation pops the Fragment
* asynchronously, so the newly visible Fragment from the back stack
* is not instantly available after this call completes.
*/
@Override
public boolean popBackStack() {
if (mBackStack.isEmpty()) {
return false;
}
if (mFragmentManager.isStateSaved()) {
Log.i(TAG, "Ignoring popBackStack() call: FragmentManager has already"
+ " saved its state");
return false;
}
if (mFragmentManager.getBackStackEntryCount() > 0) {
mFragmentManager.popBackStack(
generateBackStackName(mBackStack.size(), mBackStack.peekLast()),
FragmentManager.POP_BACK_STACK_INCLUSIVE);
mIsPendingBackStackOperation = true;
} // else, we're on the first Fragment, so there's nothing to pop from FragmentManager
mBackStack.removeLast();
return true;
}
@NonNull
@Override
public FragmentNavigator.Destination createDestination() {
return new FragmentNavigator.Destination(this);
}
/**
* Instantiates the Fragment.
*
* Note that this method is <strong>not</strong> responsible for calling
* {@link Fragment#setArguments(Bundle)} on the returned Fragment instance.
*
* @param context Context providing the correct {@link ClassLoader}
* @param fragmentManager FragmentManager the Fragment will be added to
* @param className The Fragment to instantiate
* @param args The Fragment's arguments, if any
* @return A new fragment instance.
*/
@NonNull
public Fragment instantiateFragment(@NonNull Context context,
@SuppressWarnings("unused") @NonNull FragmentManager fragmentManager,
@NonNull String className, @Nullable Bundle args) {
return Fragment.instantiate(context, className, args);
}
/**
* {@inheritDoc}
* <p>
* This method should always call
* {@link FragmentTransaction#setPrimaryNavigationFragment(Fragment)}
* so that the Fragment associated with the new destination can be retrieved with
* {@link FragmentManager#getPrimaryNavigationFragment()}.
* <p>
* Note that the default implementation commits the new Fragment
* asynchronously, so the new Fragment is not instantly available
* after this call completes.
*/
private Fragment currShowFragment;
@Nullable
@Override
public NavDestination navigate(@NonNull FragmentNavigator.Destination destination, @Nullable Bundle args,
@Nullable NavOptions navOptions, @Nullable Navigator.Extras navigatorExtras) {
if (mFragmentManager.isStateSaved()) {
Log.i(TAG, "Ignoring navigate() call: FragmentManager has already"
+ " saved its state");
return null;
}
String className = destination.getClassName();//获取类名
if (className.charAt(0) == '.') {
className = mContext.getPackageName() + className;
}//在此相当于重新创建了一个
Fragment frag;
Fragment hasObj=hasCurrFragmentToObj(className);
if (hasObj==null){
frag = instantiateFragment(mContext, mFragmentManager,
className, args);
}else{
frag=hasObj;
}
frag.setArguments(args);
final FragmentTransaction ft = mFragmentManager.beginTransaction();
int enterAnim = navOptions != null ? navOptions.getEnterAnim() : -1;
int exitAnim = navOptions != null ? navOptions.getExitAnim() : -1;
int popEnterAnim = navOptions != null ? navOptions.getPopEnterAnim() : -1;
int popExitAnim = navOptions != null ? navOptions.getPopExitAnim() : -1;
if (enterAnim != -1 || exitAnim != -1 || popEnterAnim != -1 || popExitAnim != -1) {
enterAnim = enterAnim != -1 ? enterAnim : 0;
exitAnim = exitAnim != -1 ? exitAnim : 0;
popEnterAnim = popEnterAnim != -1 ? popEnterAnim : 0;
popExitAnim = popExitAnim != -1 ? popExitAnim : 0;
ft.setCustomAnimations(enterAnim, exitAnim, popEnterAnim, popExitAnim);
}
//在此对fragment进行了替换
if (currShowFragment!=null){
ft.hide(currShowFragment);
}
if (frag.isAdded()){
ft.show(frag);
}else{
ft.add(mContainerId,frag);
}
ft.setPrimaryNavigationFragment(frag);
final @IdRes int destId = destination.getId();
final boolean initialNavigation = mBackStack.isEmpty();
// TODO Build first class singleTop behavior for fragments
final boolean isSingleTopReplacement = navOptions != null && !initialNavigation
&& navOptions.shouldLaunchSingleTop()
&& mBackStack.peekLast() == destId;
boolean isAdded=false;
// if (initialNavigation) {
// isAdded = true;
// } else if (isSingleTopReplacement) {
// // Single Top means we only want one instance on the back stack
// if (mBackStack.size() > 1) {
// // If the Fragment to be replaced is on the FragmentManager's
// // back stack, a simple replace() isn't enough so we
// // remove it from the back stack and put our replacement
// // on the back stack in its place
// mFragmentManager.popBackStack(
// generateBackStackName(mBackStack.size(), mBackStack.peekLast()),
// FragmentManager.POP_BACK_STACK_INCLUSIVE);
// ft.addToBackStack(generateBackStackName(mBackStack.size(), destId));
// mIsPendingBackStackOperation = true;
// }
// isAdded = false;
// } else {
// ft.addToBackStack(generateBackStackName(mBackStack.size() + 1, destId));
// mIsPendingBackStackOperation = true;
// isAdded = true;
// }
//Fragment切换时, 有一些元素(element)会保持不变, 使这些元素切换时, 赋予动画效果
if (navigatorExtras instanceof FragmentNavigator.Extras) {
FragmentNavigator.Extras extras = (FragmentNavigator.Extras) navigatorExtras;
for (Map.Entry<View, String> sharedElement : extras.getSharedElements().entrySet()) {
ft.addSharedElement(sharedElement.getKey(), sharedElement.getValue());
}
}
currShowFragment=frag;
ft.setReorderingAllowed(true);
ft.commit();
// The commit succeeded, update our view of the world
if (isAdded) {
mBackStack.add(destId);
return destination;
} else {
return null;
}
}
private Fragment hasCurrFragmentToObj(String className){
List<Fragment> list=mFragmentManager.getFragments();
for (int i = 0; i < list.size(); i++) {
Fragment fragment=list.get(i);
String name=fragment.getClass().getName();
if (className.equals(name)){
return fragment;
}
}
return null;
}
@Override
@Nullable
public Bundle onSaveState() {
Bundle b = new Bundle();
int[] backStack = new int[mBackStack.size()];
int index = 0;
for (Integer id : mBackStack) {
backStack[index++] = id;
}
b.putIntArray(KEY_BACK_STACK_IDS, backStack);
return b;
}
@Override
public void onRestoreState(@Nullable Bundle savedState) {
if (savedState != null) {
int[] backStack = savedState.getIntArray(KEY_BACK_STACK_IDS);
if (backStack != null) {
mBackStack.clear();
for (int destId : backStack) {
mBackStack.add(destId);
}
}
}
}
@NonNull
private String generateBackStackName(int backStackIndex, int destId) {
return backStackIndex + "-" + destId;
}
private int getDestId(@Nullable String backStackName) {
String[] split = backStackName != null ? backStackName.split("-") : new String[0];
if (split.length != 2) {
throw new IllegalStateException("Invalid back stack entry on the "
+ "NavHostFragment's back stack - use getChildFragmentManager() "
+ "if you need to do custom FragmentTransactions from within "
+ "Fragments created via your navigation graph.");
}
try {
// Just make sure the backStackIndex is correctly formatted
Integer.parseInt(split[0]);
return Integer.parseInt(split[1]);
} catch (NumberFormatException e) {
throw new IllegalStateException("Invalid back stack entry on the "
+ "NavHostFragment's back stack - use getChildFragmentManager() "
+ "if you need to do custom FragmentTransactions from within "
+ "Fragments created via your navigation graph.");
}
}
/**
* Checks if this FragmentNavigator's back stack is equal to the FragmentManager's back stack.
*/
@SuppressWarnings("WeakerAccess") /* synthetic access */
boolean isBackStackEqual() {
int fragmentBackStackCount = mFragmentManager.getBackStackEntryCount();
// Initial fragment won't be on the FragmentManager's back stack so +1 its count.
if (mBackStack.size() != fragmentBackStackCount + 1) {
return false;
}
// From top to bottom verify destination ids match in both back stacks/
Iterator<Integer> backStackIterator = mBackStack.descendingIterator();
int fragmentBackStackIndex = fragmentBackStackCount - 1;
while (backStackIterator.hasNext() && fragmentBackStackIndex >= 0) {
int destId = backStackIterator.next();
try {
int fragmentDestId = getDestId(mFragmentManager
.getBackStackEntryAt(fragmentBackStackIndex--)
.getName());
if (destId != fragmentDestId) {
return false;
}
} catch (NumberFormatException e) {
throw new IllegalStateException("Invalid back stack entry on the "
+ "NavHostFragment's back stack - use getChildFragmentManager() "
+ "if you need to do custom FragmentTransactions from within "
+ "Fragments created via your navigation graph.");
}
}
return true;
}
/**
* NavDestination specific to {@link androidx.navigation.fragment.FragmentNavigator}
*/
@NavDestination.ClassType(Fragment.class)
public static class Destination extends NavDestination {
private String mClassName;
/**
* Construct a new fragment destination. This destination is not valid until you set the
* Fragment via {@link #setClassName(String)}.
*
* @param navigatorProvider The {@link NavController} which this destination
* will be associated with.
*/
public Destination(@NonNull NavigatorProvider navigatorProvider) {
this(navigatorProvider.getNavigator(FragmentNavigator.class));
}
/**
* Construct a new fragment destination. This destination is not valid until you set the
* Fragment via {@link #setClassName(String)}.
*
* @param fragmentNavigator The {@link androidx.navigation.fragment.FragmentNavigator} which this destination
* will be associated with. Generally retrieved via a
* {@link NavController}'s
* {@link NavigatorProvider#getNavigator(Class)} method.
*/
public Destination(@NonNull Navigator<? extends FragmentNavigator.Destination> fragmentNavigator) {
super(fragmentNavigator);
}
@CallSuper
@Override
public void onInflate(@NonNull Context context, @NonNull AttributeSet attrs) {
super.onInflate(context, attrs);
TypedArray a = context.getResources().obtainAttributes(attrs,
R.styleable.FragmentNavigator);
String className = a.getString(R.styleable.FragmentNavigator_android_name);
if (className != null) {
setClassName(className);
}
a.recycle();
}
/**
* Set the Fragment class name associated with this destination
* @param className The class name of the Fragment to show when you navigate to this
* destination
* @return this {@link androidx.navigation.fragment.FragmentNavigator.Destination}
* @see #instantiateFragment(Context, FragmentManager, String, Bundle)
*/
@NonNull
public final FragmentNavigator.Destination setClassName(@NonNull String className) {
mClassName = className;
return this;
}
/**
* Gets the Fragment's class name associated with this destination
*
* @throws IllegalStateException when no Fragment class was set.
* @see #instantiateFragment(Context, FragmentManager, String, Bundle)
*/
@NonNull
public final String getClassName() {
if (mClassName == null) {
throw new IllegalStateException("Fragment class was not set");
}
return mClassName;
}
}
/**
* Extras that can be passed to FragmentNavigator to enable Fragment specific behavior
*/
public static final class Extras implements Navigator.Extras {
private final LinkedHashMap<View, String> mSharedElements = new LinkedHashMap<>();
Extras(Map<View, String> sharedElements) {
mSharedElements.putAll(sharedElements);
}
/**
* Gets the map of shared elements associated with these Extras. The returned map
* is an {@link Collections#unmodifiableMap(Map) unmodifiable} copy of the underlying
* map and should be treated as immutable.
*/
@NonNull
public Map<View, String> getSharedElements() {
return Collections.unmodifiableMap(mSharedElements);
}
/**
* Builder for constructing new {@link androidx.navigation.fragment.FragmentNavigator.Extras} instances. The resulting instances are
* immutable.
*/
public static final class Builder {
private final LinkedHashMap<View, String> mSharedElements = new LinkedHashMap<>();
/**
* Adds multiple shared elements for mapping Views in the current Fragment to
* transitionNames in the Fragment being navigated to.
*
* @param sharedElements Shared element pairs to add
* @return this {@link androidx.navigation.fragment.FragmentNavigator.Extras.Builder}
*/
@NonNull
public FragmentNavigator.Extras.Builder addSharedElements(@NonNull Map<View, String> sharedElements) {
for (Map.Entry<View, String> sharedElement : sharedElements.entrySet()) {
View view = sharedElement.getKey();
String name = sharedElement.getValue();
if (view != null && name != null) {
addSharedElement(view, name);
}
}
return this;
}
/**
* Maps the given View in the current Fragment to the given transition name in the
* Fragment being navigated to.
*
* @param sharedElement A View in the current Fragment to match with a View in the
* Fragment being navigated to.
* @param name The transitionName of the View in the Fragment being navigated to that
* should be matched to the shared element.
* @return this {@link androidx.navigation.fragment.FragmentNavigator.Extras.Builder}
* @see FragmentTransaction#addSharedElement(View, String)
*/
@NonNull
public FragmentNavigator.Extras.Builder addSharedElement(@NonNull View sharedElement, @NonNull String name) {
mSharedElements.put(sharedElement, name);
return this;
}
/**
* Constructs the final {@link androidx.navigation.fragment.FragmentNavigator.Extras} instance.
*
* @return An immutable {@link androidx.navigation.fragment.FragmentNavigator.Extras} instance.
*/
@NonNull
public FragmentNavigator.Extras build() {
return new FragmentNavigator.Extras(mSharedElements);
}
}
}
}