基本上,我有以下导航图:
我想在到达导航图后立即将导航图的起点更改为fragment 2
(以防止在按“后退”按钮时像回到启动屏幕一样回到fragment 1
)。
这是我的代码:
navGraph = navController.getGraph();
navGraph.setStartDestination(R.id.fragment2);
navController.setGraph(navGraph);
但是,很明显,它不起作用,并且在按下返回按钮后返回到fragment 1
。
我做错了吗? 还有其他解决方案吗?
答案 0 :(得分:20)
当您具有如下导航图时:
public function uploaderPost(Request $request)
{
// Here we get auth token and put into protected valiable `$this->token`
$this->authorizeApi();
$requestData = $request->except('_token');
$package = $requestData['file'];
$uploadPackageRequest =
$this->client->request('POST', config('bulk_api.url') .'/api/bulk/upload?token=' . $this->token,
[
'multipart' => [
[
'name' => 'file',
'contents' => fopen($package->getPathName(), 'r'),
'filename' => $package->getClientOriginalName(),
],
]
]);
$uploadPackageRequestJson = json_decode($uploadPackageRequest->getBody()->getContents());
$uploadPackageRequestStatus = $uploadPackageRequestJson->status;
if($uploadPackageRequestStatus == 1) {
$package = BulkUploadPackage::where('id', '=',$uploadPackageRequestJson->id)->first();
// If package is okay - running it
if($package !== null){
// Here where I expect job to be dispatched (code above)
$runPackageRequest =
$this->client->request('POST', config('api.url') .'/api/bulk/run?token=' . $this->token,
[
'multipart' => [
[
'name' => 'package_id',
'contents' => $package->id
],
]
]);
// Here I'm receiving stream for some reason
dd($runPackageRequest->getBody());
if($runPackageRequest->getStatusCode()==200){
return redirect(url('/success'));
}
}
}
return back();
}
您要导航到第二个片段并将其设为图的根,请指定下一个<fragment
android:id="@+id/firstFragment"
android:name="com.appname.package.FirstFragment" >
<action
android:id="@+id/action_firstFragment_to_secondFragment"
app:destination="@id/secondFragment" />
</fragment>
<fragment
android:id="@+id/secondFragment"
android:name="com.appname.package.SecondFragment"/>
:
NavOptions
并使用它们进行导航:
NavOptions navOptions = new NavOptions.Builder()
.setPopUpTo(R.id.firstFragment, true)
.build();
Navigation.findNavController(view).navigate(R.id.action_firstFragment_to_secondFragment, bundle, navOptions);
-导航至给定目的地。这将从后堆栈中弹出所有不匹配的目标,直到找到该目标为止。
setPopUpTo(int destinationId, boolean inclusive)
-弹出的目的地,清除所有中间目的地。
destinationId
-为true也将从后堆栈中弹出给定的目的地。
inclusive
然后在您的代码上:
<fragment
android:id="@+id/firstFragment"
android:name="com.appname.package.FirstFragment" >
<action
android:id="@+id/action_firstFragment_to_secondFragment"
app:destination="@id/secondFragment"
app:popUpTo="@+id/firstFragment"
app:popUpToInclusive="true" />
</fragment>
<fragment
android:id="@+id/secondFragment"
android:name="com.appname.package.SecondFragment"/>
已弃用:已弃用findNavController(fragment).navigate(
FirstFragmentDirections.actionFirstFragmentToSecondFragment())
中的动作属性clearTask
和NavOptions
中的关联API。
来源:https://developer.android.com/jetpack/docs/release-notes
如果要将根片段更改为fragment 2
(例如,按fragment 2
上的后退按钮将退出应用程序),则应将下一个属性置于action
或destination
:
app:clearTask="true"
实际上,它看起来是另一种方式:
<fragment
android:id="@+id/firstFragment"
android:name="com.appname.package.FirstFragment"
android:label="fragment_first" >
<action
android:id="@+id/action_firstFragment_to_secondFragment"
app:destination="@id/secondFragment"
app:clearTask="true" />
</fragment>
<fragment
android:id="@+id/secondFragment"
android:name="com.appname.package.SecondFragment"
android:label="fragment_second"/>
我已将app:clearTask="true"
添加到操作中。
现在,当您执行从fragment 1
到fragment 2
的导航时,请使用以下代码:
Navigation.findNavController(view)
.navigate(R.id.action_firstFragment_to_secondFragment);
答案 1 :(得分:2)
您真的不需要弹出飞溅片段。它可以在您的App余生中保持不变。您应该从“启动画面”中确定要显示的下一个画面。
在上面的图片中,您可以在“初始屏幕状态”中询问是否存在已保存的LoginToken。如果为空,则导航到登录屏幕。
完成登录屏幕后,您需要分析结果并保存令牌,然后导航到下一个片段主屏幕。
在主屏幕中按下“后退”按钮时,您会将结果消息发送回启动屏幕,指示其完成应用程序。
答案 2 :(得分:2)
在MainActivity.kt
val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
val inflater = navHostFragment.navController.navInflater
val graph = inflater.inflate(R.navigation.booking_navigation)
if (isTrue){
graph.startDestination = R.id.DetailsFragment
}else {
graph.startDestination = R.id.OtherDetailsFragment
}
val navController = navHostFragment.navController
navController.setGraph(graph, intent.extras)
从nav_graph.xml中删除startDestination
?xml version="1.0" encoding="utf-8"?>
<!-- app:startDestination="@id/oneFragment" -->
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/navigation_main">
<fragment
android:id="@+id/DetailFragment"
android:name="DetailFragment"
android:label="fragment_detail"
tools:layout="@layout/fragment_detail"/>
<fragment
android:id="@+id/OtherDetailFragment"
android:name="OtherDetailFragment"
android:label="fragment_other_detail"
tools:layout="@layout/fragment_other_detail"/>
</navigation>
答案 3 :(得分:1)
您也可以尝试以下方法。
$('.my-select').on('change', function() {
var value = $(this).val(); //get the value
$('.box').hide(); //hide all of them
$('#id' + value).show(); //show the correct one
});
$('document').ready(function() {
//trigger the change to run the process once
$('.my-select').trigger('change');
});
与其试图弹出目标位置或手动导航到目标位置,不如让另一个具有不同工作流程的导航图更好。 当您希望有条件地完全不同的导航流程时,这会更好。
答案 4 :(得分:1)
好吧,在弄乱了一点之后,我发现了一个对我有用的解决方案,不需要大量的工作。
似乎必须要做好两件事,好像您的secondFragment是起始目的地一样。
在接受的帖子中使用替代选项
<fragment
android:id="@+id/firstFragment"
android:name="com.appname.package.FirstFragment" >
<action
android:id="@+id/action_firstFragment_to_secondFragment"
app:destination="@id/secondFragment"
app:popUpTo="@+id/firstFragment"
app:popUpToInclusive="true" />
</fragment>
<fragment
android:id="@+id/secondFragment"
android:name="com.appname.package.SecondFragment"/>
以上内容将从移动堆栈中移除firstFragment,并在移动时使secondFragment膨胀。该应用程序无法再退回到firstFragment了,但是您的左边的secondFragment显示了一个后退箭头,如@szaske所述。
这就是与众不同的原因。我以前像这样使用NavigationController.graph定义了AppBarConfig
// Old code
val controller by lazy { findNavController(R.id.nav_host_fragment) }
val appBarConfig by lazy { AppBarConfiguration(controller.graph) }
更新它以定义一组顶级目的地,解决了在secondFragment上显示向后箭头而不是汉堡菜单图标的问题。
// secondFragment will now show hamburger menu instead of back arrow.
val appBarConfig by lazy { AppBarConfiguration(setOf(R.id.firstFragment, R.id.secondFragment)) }
设置开始目的地可能会对您的项目造成负面影响,也可能不会产生负面影响,因此请根据需要进行设置,但是在本示例中,我们不需要这样做。如果它使您变得温暖而模糊,以确保您的图形定义了正确的起始片段,则可以这样做。
controller.graph.startDestination = R.id.secondFragment
注意:设置此项不会阻止在第二片段中出现后退箭头,而且我发现这似乎对导航没有影响。
答案 5 :(得分:0)
对于那些具有与此内容相似的导航xml文件的用户:
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/mobile_navigation"
app:startDestination="@+id/nav_home">
<fragment
android:id="@+id/nav_home"
android:name="HomeFragment"
android:label="@string/menu_home"
tools:layout="@layout/fragment_home" />
<fragment
android:id="@+id/nav_users"
android:name="UsersFragment"
android:label="@string/users"
tools:layout="@layout/fragment_users" />
<fragment
android:id="@+id/nav_settings"
android:name="SettingsFragment"
android:label="@string/settings"
tools:layout="@layout/fragment_settings" />
</navigation>
假设当前打开的片段是home片段,并且您想导航到users片段,为此,只需从要导航到导航方法的元素中调用setOnClickListener,类似于以下代码:>
yourElement.setOnClickListener {
view.findNavController().navigate(R.id.nav_users)
}
这将使应用导航到该其他片段,并且还将处理工具栏中的标题。
答案 6 :(得分:-2)
我为此找到了解决方案,但这很丑陋。我想这在alpha库中是可以预期的,但是我希望Google考虑简化/修复它,因为这是一种非常流行的导航模式。
Alexey的解决方案对我不起作用。我的问题是,使用以下命令,我的操作栏上显示了向上箭头:
NavigationUI.setupActionBarWithNavController(this, navController)
如果我按照Alexey的建议进行操作,那么我的新起始片段仍然会有一个箭头指向我的初始起始片段。如果按下该向上箭头,我的应用程序将重新启动,然后过渡到自身(新的开始片段)
这是实现我想要的代码所需的代码:
这是完成此操作的代码。在我的活动的onCreate中:
// Setup the toolbar
val toolbar = findViewById<Toolbar>(R.id.toolbar)
setSupportActionBar(toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(false)
// Configure the navigation
val navHost = nav_host_fragment as NavHostFragment
graph = navHost.navController
.navInflater.inflate(R.navigation.nav_graph)
graph.startDestination = R.id.welcomeFragment
// This seems to be a magical command. Not sure why it's needed :(
navHost.navController.graph = graph
NavigationUI.setupActionBarWithNavController(this, navHost.navController)
还有:
fun makeHomeStart(){
graph.startDestination = R.id.homeFragment
}
然后根据Alexey的建议,在片段#1的onActivityCreated中创建:
override fun onActivityCreated(savedInstanceState: Bundle?) {
...
// Check for user authentication
if(sharedViewModel.isUserAuthenticated()) {
(activity as MainActivity).makeHomeStart() //<---- THIS is the key
val navOptions = NavOptions.Builder()
.setPopUpTo(R.id.welcomeFragment, true)
.build()
navController.navigate(R.id.action_welcomeFragment_to_homeFragment,null,navOptions)
} else {
navController.navigate(R.id.action_welcomeFragment_to_loginFragment)
}
}
关键代码是:
(activity as MainActivity).makeHomeStart()
仅在更改图表startDestination的活动中运行方法。我可以清理它并将其转换为界面,但是我将等待Google并希望他们改善整个过程。方法“ setPopUpTo”在我看来命名很差,而且命名您要从图中切出的片段的名称也不直观。我对他们在navOptions中进行这些更改也感到奇怪。我认为navOptions仅与它们连接的导航动作有关。
我什至不知道navHost.navController.graph = graph
的作用,但是没有它,向上箭头会返回。 :(
我正在使用导航1.0.0-alpha06。