如何在嵌套片段中使用导航(NavHost)



我正试图从Fragment1(TransformFragment)打开Fragment2通过单击RecyclerView中的项目。我试着用Navigation (NavHost)来解决这个问题。

Fragment1代码如下:

class TransformFragment : Fragment() {
private lateinit var transformViewModel: TransformViewModel
private var _binding: FragmentTransformBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding
get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
transformViewModel = ViewModelProvider(this)[TransformViewModel::class.java]
_binding = FragmentTransformBinding.inflate(inflater, container, false)
val root: View = binding.root
val recyclerView = binding.recyclerviewTransform
val adapter = TransformAdapter()
recyclerView.adapter = adapter
transformViewModel.texts.observe(viewLifecycleOwner) { adapter.submitList(it) }
return root
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
class TransformAdapter() :
ListAdapter<String, TransformViewHolder>(
object : DiffUtil.ItemCallback<String>() {
override fun areItemsTheSame(oldItem: String, newItem: String): Boolean =
oldItem == newItem
override fun areContentsTheSame(oldItem: String, newItem: String): Boolean =
oldItem == newItem
}
) {
private val drawables =
listOf(
R.drawable.avatar_1,
R.drawable.avatar_2,
R.drawable.avatar_3,
R.drawable.avatar_4,
R.drawable.avatar_5,
R.drawable.avatar_6,
R.drawable.avatar_7,
R.drawable.avatar_8,
R.drawable.avatar_9,
R.drawable.avatar_10,
R.drawable.avatar_11,
R.drawable.avatar_12,
R.drawable.avatar_13,
R.drawable.avatar_14,
R.drawable.avatar_15,
R.drawable.avatar_16,
R.drawable.avatar_17,
)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TransformViewHolder {
val binding = ItemTransformBinding.inflate(LayoutInflater.from(parent.context))
return TransformViewHolder(binding)
}
override fun onBindViewHolder(holder: TransformViewHolder, position: Int) {
holder.textView.text = getItem(position)
holder.imageView.setImageDrawable(
ResourcesCompat.getDrawable(holder.imageView.resources, drawables[position], null)
)
holder.itemView.setOnClickListener {
// my navigation(NavHost) code
}
}
}
class TransformViewHolder(binding: ItemTransformBinding) :
RecyclerView.ViewHolder(binding.root) {
val imageView: ImageView = binding.imageViewItemTransform
val textView: TextView = binding.textViewItemTransform
}
}

我试着使用这个:

val navController = findNavController(R.id.nav_host_fragment_content_main)
navController.navigate(R.id.nav_detail)

nav_detail来导航Fragment2,以及我的片段容器。这是我的XML。我知道要显示动态碎片,必须使用FrameLayout,但它会产生错误,碎片容器也可以

<LinearLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:showIn="@layout/app_bar_main">
<fragment
android:id="@+id/nav_host_fragment_content_main"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginLeft="@dimen/fragment_horizontal_margin"
android:layout_marginRight="@dimen/fragment_horizontal_margin"
android:layout_weight="1"
app:defaultNavHost="true"
app:navGraph="@navigation/mobile_navigation" />
<!--
<FrameLayout
android:id="@+id/nav_host_fragment_content_main"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginLeft="@dimen/fragment_horizontal_margin"
android:layout_marginRight="@dimen/fragment_horizontal_margin"
android:layout_weight="1"
app:defaultNavHost="true"
app:navGraph="@navigation/mobile_navigation" />
-->

</LinearLayout>

我在Android开发人员文档中找到了正确的答案。

holder.itemView.setOnClickListener {
it.findNavController().navigate(R.id.nav_detail)
}

要使用findNavController()在片段之间导航,必须确保首先正确设置了活动。

所以,在你的活动布局中,首先添加容器,父需要点头成为FrameLayout本身,我将在下面使用ConstraintLayout

activity_main.xml

<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<!--    We declare attribute id to hook with MainActivity.java class-->
<!--    Attribute name will change behavior of simple fragment to NavHostFragment-->
<!--    Keep width and height to match_parent so that all our fragments take whole space-->
<!--    We change this NavHost to behave default NavHost-->
<!--    Attach our app navigation graph to this NavHostFragment-->
<fragment
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_graph" />
</androidx.constraintlayout.widget.ConstraintLayout>

现在,让我们将容器挂接为活动的代理主机。

主活动.kt

class MainActivity : AppCompatActivity() {
lateinit var navController: NavController
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// NavigationController to set default NavHost as nav_host_fragment.
navController = Navigation.findNavController(this, R.id.nav_host_fragment)
NavigationUI.setupActionBarWithNavController(this, navController)
}
override fun onSupportNavigateUp(): Boolean {
return navController.navigateUp()
}
}

onSupportNavigateUp函数可帮助您导航回在使用navigateUp()的任何视图上触发或调用的操作的上一个片段。

现在您要从Fragment1->碎片2.

  1. 请确保已将两个片段添加到导航图中
  2. 用行动将第一个片段连接到第二个片段
  3. 跟踪目的地Id以调用正确的Id
<?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/nav_graph"
app:startDestination="@id/firstFragment">
<fragment
android:id="@+id/firstFragment"
android:name=".FirstFragment"
android:label="FirstFragment"
tools:layout="@layout/fragment_first">
<action
android:id="@+id/action_first_fragment_to_second_fragment"
app:destination="@id/secondFragment" />
</fragment>
<fragment
android:id="@+id/secondFragment"
android:name=".SecondFragment"
android:label="Authors"
tools:layout="@layout/fragment_second" />
</navigation>

现在,一旦操作被触发,最后在控制器上调用id如下的操作。

yourListItemView.setOnClickListener {
findNavController(R.id.action_first_fragment_to_second_fragment)
}

就是这样。

请查看文档,它有很好的信息。

最新更新