如何在 kotlin 中使用 jetpack 导航到达上一个片段?
How to get to the previous fragment using jetpack navigation in kotlin?
我正在制作一个包含两个片段的应用程序,它们是 home-fragment 和 youtube-fragment。当我按下“搜索”按钮时,我可以正确地找到 youtube-fragment。但是,当我按下后退按钮(phone 上的后退按钮而不是工具栏中的后退箭头)时,我只是退出应用程序而没有收到任何错误或警告。我想在按下后退按钮后返回主页片段。
这是我的两个片段的代码:
homeFragment
package com.example.signlanguage_new
import android.os.Bundle
import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.GridLayout
import android.widget.Toast
import android.widget.Toast.LENGTH_SHORT
import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.GridLayoutManager
import com.example.signlanguage_new.databinding.FragmentHomeBinding
class HomeFragment : Fragment() {
private val viewModel: MyViewModel by activityViewModels {
MyViewModelFactory(
(activity?.application as SignLanguageApplication).database.VideoDao()
)
}
private var _binding: FragmentHomeBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentHomeBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
viewModel.result.observe(viewLifecycleOwner)
{
if(it==null) {
Toast.makeText(requireContext(), "查無資料", LENGTH_SHORT).show()
}
else
{
val action=HomeFragmentDirections.actionHomeFragmentToYoutubeFragment()
findNavController().navigate(action)
}
}
super.onViewCreated(view, savedInstanceState)
binding.apply {
searchBtn.setOnClickListener {
val search=binding.search.text.toString()
if(search=="")
{
Toast.makeText(requireContext(), "請輸入關鍵字", LENGTH_SHORT).show()
}
else
{
viewModel.searchVideo(search)
}
}
}
val adapter=homeButtonAdapter{
viewModel.category(it)
}
binding.recyclerView.adapter=adapter
binding.recyclerView.layoutManager=GridLayoutManager(this.context,2)
}
}
youtubeFragment
package com.example.signlanguage_new
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.activity.OnBackPressedCallback
import androidx.activity.addCallback
import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.signlanguage_new.data.Video
import com.example.signlanguage_new.databinding.FragmentYoutubeBinding
class youtubeFragment : Fragment() {
private val viewModel: MyViewModel by activityViewModels {
MyViewModelFactory(
(activity?.application as SignLanguageApplication).database.VideoDao()
)
}
private var _binding: FragmentYoutubeBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentYoutubeBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val Dataset= viewModel.result.value
binding.recyclerView.adapter= Dataset?.let {
VideoAdapter(requireContext(),
it,this.lifecycle)
}
binding.recyclerView.layoutManager = LinearLayoutManager(this.context)
}
}
这是 nav_graph 和我的 mainActivity:
nav_graph
<?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/homeFragment">
<fragment
android:id="@+id/homeFragment"
android:name="com.example.signlanguage_new.HomeFragment"
android:label="fragment_home"
tools:layout="@layout/fragment_home" >
<action
android:id="@+id/action_homeFragment_to_youtubeFragment"
app:destination="@id/youtubeFragment"
app:popUpTo="@id/homeFragment"
app:popUpToInclusive="true" />
</fragment>
<fragment
android:id="@+id/youtubeFragment"
android:name="com.example.signlanguage_new.youtubeFragment"
android:label="fragment_youtube"
tools:layout="@layout/fragment_youtube" />
</navigation>
MainActivity
package com.example.signlanguage_new
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.KeyEvent
import androidx.navigation.NavController
import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.ui.NavigationUI.setupActionBarWithNavController
class MainActivity : AppCompatActivity(R.layout.activity_main) {
private lateinit var navController: NavController
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Retrieve NavController from the NavHostFragment
val navHostFragment = supportFragmentManager
.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
navController = navHostFragment.navController
// Set up the action bar for use with the NavController
setupActionBarWithNavController(this, navController)
}
/**
* Handle navigation when the user chooses Up from the action bar.
*/
override fun onSupportNavigateUp(): Boolean {
return navController.navigateUp() || super.onSupportNavigateUp()
}
}
我想这可能与我在 youtube-fragment 中的 recyclerview 适配器有关,因为我提供了生命周期作为它的参数。
这里是:
视频适配器
package com.example.signlanguage_new
import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.example.signlanguage_new.data.Video
import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.YouTubePlayer
import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.listeners.AbstractYouTubePlayerListener
import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.views.YouTubePlayerView
class VideoAdapter (private val context: Context, private val dataset:List<Video>, private val lifecycle: Lifecycle) :RecyclerView.Adapter<VideoAdapter.ItemViewHolder>(){
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder {
val youTubePlayerView: YouTubePlayerView = LayoutInflater.from(parent.context).inflate(R.layout.videolistitem,parent,false) as YouTubePlayerView
lifecycle.addObserver(youTubePlayerView)
return ItemViewHolder(youTubePlayerView)
}
override fun onBindViewHolder(holder: ItemViewHolder, position: Int) {
val current=dataset[position]
holder.setIsRecyclable(false)
holder.loadVideo(current.ytId)
}
override fun getItemCount(): Int {
return dataset.size
}
class ItemViewHolder(playerView: YouTubePlayerView) :
RecyclerView.ViewHolder(playerView) {
val youTubePlayerView: YouTubePlayerView = playerView
var youTubePlayer: YouTubePlayer? = null
var currentVideoId: String? = null
fun loadVideo(videoId: String?) {
currentVideoId = videoId
if (youTubePlayer == null) return
if (videoId != null) {
youTubePlayer!!.cueVideo(videoId, 0F)
}
}
init {
youTubePlayerView.addYouTubePlayerListener(object : AbstractYouTubePlayerListener() {
override fun onReady(initializedYouTubePlayer: YouTubePlayer) {
youTubePlayer = initializedYouTubePlayer
currentVideoId?.let {
youTubePlayer!!.cueVideo(it, 0F)
}
}
})
}
}
}
有谁知道我怎样才能到达主页片段而不是离开应用程序?
当您将 app:popUpTo="@id/homeFragment", app:popUpToInclusive="true"
添加到您的导航操作时,这意味着您要从返回堆栈中删除 homeFragment
。本质上意味着当您按下后退时,homeFragment
将不再存在,如果您希望后退按钮将您带到 homeFragment
,您需要将操作更新为
<action
android:id="@+id/action_homeFragment_to_youtubeFragment"
app:destination="@id/youtubeFragment" />
我正在制作一个包含两个片段的应用程序,它们是 home-fragment 和 youtube-fragment。当我按下“搜索”按钮时,我可以正确地找到 youtube-fragment。但是,当我按下后退按钮(phone 上的后退按钮而不是工具栏中的后退箭头)时,我只是退出应用程序而没有收到任何错误或警告。我想在按下后退按钮后返回主页片段。
这是我的两个片段的代码:
homeFragment
package com.example.signlanguage_new
import android.os.Bundle
import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.GridLayout
import android.widget.Toast
import android.widget.Toast.LENGTH_SHORT
import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.GridLayoutManager
import com.example.signlanguage_new.databinding.FragmentHomeBinding
class HomeFragment : Fragment() {
private val viewModel: MyViewModel by activityViewModels {
MyViewModelFactory(
(activity?.application as SignLanguageApplication).database.VideoDao()
)
}
private var _binding: FragmentHomeBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentHomeBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
viewModel.result.observe(viewLifecycleOwner)
{
if(it==null) {
Toast.makeText(requireContext(), "查無資料", LENGTH_SHORT).show()
}
else
{
val action=HomeFragmentDirections.actionHomeFragmentToYoutubeFragment()
findNavController().navigate(action)
}
}
super.onViewCreated(view, savedInstanceState)
binding.apply {
searchBtn.setOnClickListener {
val search=binding.search.text.toString()
if(search=="")
{
Toast.makeText(requireContext(), "請輸入關鍵字", LENGTH_SHORT).show()
}
else
{
viewModel.searchVideo(search)
}
}
}
val adapter=homeButtonAdapter{
viewModel.category(it)
}
binding.recyclerView.adapter=adapter
binding.recyclerView.layoutManager=GridLayoutManager(this.context,2)
}
}
youtubeFragment
package com.example.signlanguage_new
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.activity.OnBackPressedCallback
import androidx.activity.addCallback
import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.signlanguage_new.data.Video
import com.example.signlanguage_new.databinding.FragmentYoutubeBinding
class youtubeFragment : Fragment() {
private val viewModel: MyViewModel by activityViewModels {
MyViewModelFactory(
(activity?.application as SignLanguageApplication).database.VideoDao()
)
}
private var _binding: FragmentYoutubeBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentYoutubeBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val Dataset= viewModel.result.value
binding.recyclerView.adapter= Dataset?.let {
VideoAdapter(requireContext(),
it,this.lifecycle)
}
binding.recyclerView.layoutManager = LinearLayoutManager(this.context)
}
}
这是 nav_graph 和我的 mainActivity:
nav_graph
<?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/homeFragment">
<fragment
android:id="@+id/homeFragment"
android:name="com.example.signlanguage_new.HomeFragment"
android:label="fragment_home"
tools:layout="@layout/fragment_home" >
<action
android:id="@+id/action_homeFragment_to_youtubeFragment"
app:destination="@id/youtubeFragment"
app:popUpTo="@id/homeFragment"
app:popUpToInclusive="true" />
</fragment>
<fragment
android:id="@+id/youtubeFragment"
android:name="com.example.signlanguage_new.youtubeFragment"
android:label="fragment_youtube"
tools:layout="@layout/fragment_youtube" />
</navigation>
MainActivity
package com.example.signlanguage_new
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.KeyEvent
import androidx.navigation.NavController
import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.ui.NavigationUI.setupActionBarWithNavController
class MainActivity : AppCompatActivity(R.layout.activity_main) {
private lateinit var navController: NavController
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Retrieve NavController from the NavHostFragment
val navHostFragment = supportFragmentManager
.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
navController = navHostFragment.navController
// Set up the action bar for use with the NavController
setupActionBarWithNavController(this, navController)
}
/**
* Handle navigation when the user chooses Up from the action bar.
*/
override fun onSupportNavigateUp(): Boolean {
return navController.navigateUp() || super.onSupportNavigateUp()
}
}
我想这可能与我在 youtube-fragment 中的 recyclerview 适配器有关,因为我提供了生命周期作为它的参数。
这里是:
视频适配器
package com.example.signlanguage_new
import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.example.signlanguage_new.data.Video
import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.YouTubePlayer
import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.listeners.AbstractYouTubePlayerListener
import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.views.YouTubePlayerView
class VideoAdapter (private val context: Context, private val dataset:List<Video>, private val lifecycle: Lifecycle) :RecyclerView.Adapter<VideoAdapter.ItemViewHolder>(){
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder {
val youTubePlayerView: YouTubePlayerView = LayoutInflater.from(parent.context).inflate(R.layout.videolistitem,parent,false) as YouTubePlayerView
lifecycle.addObserver(youTubePlayerView)
return ItemViewHolder(youTubePlayerView)
}
override fun onBindViewHolder(holder: ItemViewHolder, position: Int) {
val current=dataset[position]
holder.setIsRecyclable(false)
holder.loadVideo(current.ytId)
}
override fun getItemCount(): Int {
return dataset.size
}
class ItemViewHolder(playerView: YouTubePlayerView) :
RecyclerView.ViewHolder(playerView) {
val youTubePlayerView: YouTubePlayerView = playerView
var youTubePlayer: YouTubePlayer? = null
var currentVideoId: String? = null
fun loadVideo(videoId: String?) {
currentVideoId = videoId
if (youTubePlayer == null) return
if (videoId != null) {
youTubePlayer!!.cueVideo(videoId, 0F)
}
}
init {
youTubePlayerView.addYouTubePlayerListener(object : AbstractYouTubePlayerListener() {
override fun onReady(initializedYouTubePlayer: YouTubePlayer) {
youTubePlayer = initializedYouTubePlayer
currentVideoId?.let {
youTubePlayer!!.cueVideo(it, 0F)
}
}
})
}
}
}
有谁知道我怎样才能到达主页片段而不是离开应用程序?
当您将 app:popUpTo="@id/homeFragment", app:popUpToInclusive="true"
添加到您的导航操作时,这意味着您要从返回堆栈中删除 homeFragment
。本质上意味着当您按下后退时,homeFragment
将不再存在,如果您希望后退按钮将您带到 homeFragment
,您需要将操作更新为
<action
android:id="@+id/action_homeFragment_to_youtubeFragment"
app:destination="@id/youtubeFragment" />