首页 > 解决方案 > Recyclerview Item onclick 覆盖下一个片段而不是替换它

问题描述

我有这些活动、片段、它的视图模型和它们的适配器。我已经可以在单击 recyclerview 项目时调用下一个片段,但是新片段覆盖在第一个片段上。

请参阅下面的屏幕截图: 新片段覆盖在旧片段上的屏幕截图 下一个屏幕截图是旧片段视图: 家庭片段

至于主要活动:

class MainActivity : AppCompatActivity(), RecyclerViewClickListener {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val navView: BottomNavigationView = findViewById(R.id.nav_view)

        val navController = findNavController(R.id.nav_host_fragment)
        // Passing each menu ID as a set of Ids because each
        // menu should be considered as top level destinations.
        val appBarConfiguration = AppBarConfiguration(
            setOf(
                R.id.navigation_home,
                R.id.navigation_messages,
                R.id.navigation_notifications,
                R.id.navigation_account
            )
        )
        setupActionBarWithNavController(navController, appBarConfiguration)
        navView.setupWithNavController(navController)

        if (savedInstanceState == null) {
            supportFragmentManager
                .beginTransaction()
                .add(R.id.fragment_home, HomeFragment.newInstance(), "dormList")
                .commit()
        }
    }

    override fun onRecyclerViewItemClick(view: View, dorms: Dorms) {
        val detailsFragment = dormDetailsFragment.newInstance(dorms)
        supportFragmentManager
            .beginTransaction()
            .replace(R.id.fragment_home, detailsFragment, "Dorm Details")
            .addToBackStack(null)
            .commit()
    }
}

首页片段:

class HomeFragment : Fragment(), RecyclerViewClickListener {

    private lateinit var factory: HomeViewModelFactory
    private lateinit var viewModel: HomeViewModel
    private var callback : RecyclerViewClickListener? = null

    companion object {
        fun newInstance(): HomeFragment {
            return HomeFragment()
        }
    }

    override fun onAttach(context: Context) {
        super.onAttach(context)

        if(context is RecyclerViewClickListener) callback = context
        else throw ClassCastException("$context must implement Callback")
    }

    override fun onDetach() {
        super.onDetach()
        callback = null
    }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        return inflater.inflate(R.layout.fragment_home, container, false)
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)

        val api = DormsAPI()
        val repository = DormRepository(api)

        factory = HomeViewModelFactory(repository)
        viewModel = ViewModelProviders.of(this, factory).get(HomeViewModel::class.java)

        viewModel.getDorms()

        viewModel.dorms.observe(viewLifecycleOwner, Observer { dorms ->
            recyclerViewDorms.also{
                it.layoutManager = LinearLayoutManager(requireContext())
                it.setHasFixedSize(true)
                it.adapter = dormAdapter(dorms, this)
            }
        })
    }

    override fun onRecyclerViewItemClick(view: View, dorms: Dorms) {
        when(view.id){
            R.id.button_reserve -> {
                // TODO: Go to new account if not signed up, etc...
                Toast.makeText(requireContext(), "Reserve button clicked", Toast.LENGTH_LONG).show()
            }
            R.id.layoutBox -> {
                // TODO: Go to Dorm Details
                callback?.onRecyclerViewItemClick(view, dorms)
            }
        }
    }
}

主视图模型

class HomeViewModel(private val repository: DormRepository) : ViewModel() {

    private lateinit var job: Job

    private val _dorms = MutableLiveData<List<Dorms>>()
    val dorms: LiveData<List<Dorms>>
        get() = _dorms

    fun getDorms() {
        job = Coroutines.ioThenMain(
            { repository.getDorms() },
            { _dorms.value = it }
        )
    }

    override fun onCleared() {
        super.onCleared()
        if(::job.isInitialized) job.cancel()
    }
}

界面:

interface RecyclerViewClickListener {
    fun onRecyclerViewItemClick(view: View, dorms: Dorms)
}

细节片段:

class dormDetailsFragment : Fragment() {

    companion object {

        private const val DORMS = "model"
        fun newInstance(dorms: Dorms): dormDetailsFragment{
            val args = Bundle()
            args.putSerializable(DORMS, dorms)
            val fragment = dormDetailsFragment()
            fragment.arguments = args
            return fragment
        }
    }

    private lateinit var viewModel: DormDetailsViewModel

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        val fragmentDormDetailsBinding =
            FragmentDormDetailsBinding.inflate(inflater,container,false)

        val model = arguments!!.getSerializable(DORMS) as Dorms
        fragmentDormDetailsBinding.dormDetails = model

        return fragmentDormDetailsBinding.root
    }
}

首页片段布局

<?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"
    android:id="@+id/fragment_home">

    <TextView
        android:id="@+id/text_home"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        android:textAlignment="center"
        android:textSize="20sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/refreshLayout">

        <androidx.recyclerview.widget.RecyclerView
            tools:listitem="@layout/layout_home"
            android:id="@+id/recyclerViewDorms"
            android:layout_width="0dp"
            android:layout_height="0dp"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintBottom_toBottomOf="parent" />

    </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

详细布局

<?xml version="1.0" encoding="utf-8"?>
<layout 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">

    <data>
        <import type="android.view.View" />
        <variable
            name="dormDetails"
            type="com.pptt.roomy.data.models.Dorms" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="com.pptt.roomy.ui.home.dormDetails.DormDetailsFragment"
        android:id="@+id/DormDetailsFrag">

        <ImageView
            app:image="@{dormDetails.image}"
            android:id="@+id/image"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            app:layout_constraintDimensionRatio="1:1"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            android:background="@drawable/propertysample"
            />

        <TextView
            android:text="@{String.valueOf(dormDetails.dormPrice)}"
            tools:text="Php 2500"
            android:id="@+id/textViewPrice"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:paddingTop="6dp"
            android:layout_marginStart="10dp"
            android:textSize="20sp"
            android:textStyle="normal"
            android:textColor="#000000"
            app:layout_constraintTop_toBottomOf="@id/image"
            app:layout_constraintLeft_toLeftOf="parent" />

        <TextView
            android:text="@{dormDetails.dormName}"
            tools:text="Dorm ni Jupa"
            android:id="@+id/textViewPropertyName"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:paddingTop="1dp"
            android:layout_marginStart="10dp"
            android:textSize="24sp"
            android:textStyle="bold"
            android:textColor="#000000"
            app:layout_constraintTop_toBottomOf="@id/textViewPrice"
            app:layout_constraintLeft_toLeftOf="parent" />

        <TextView
            android:text="@{dormDetails.dormType}"
            tools:text="1 BR with Dining and Kitchen"
            android:id="@+id/textViewRoomType"
            android:layout_below="@id/textViewPropertyName"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:paddingTop="5dp"
            android:layout_marginLeft="40dp"
            android:textSize="16sp"
            app:layout_constraintTop_toBottomOf="@+id/textViewPropertyName"
            app:layout_constraintLeft_toLeftOf="parent"/>

        <TextView
            android:text="@{dormDetails.dormAddress}"
            android:id="@+id/textViewAddress"
            android:layout_marginBottom="5dp"
            tools:text="455 San Jose II St., Brgy. 425, Sampaloc, Manila"
            android:textAppearance="@style/Base.TextAppearance.AppCompat.Small"
            android:padding="5dp"
            android:layout_marginLeft="40dp"
            android:layout_width="wrap_content"
            android:textAlignment="center"
            android:layout_height="wrap_content"
            app:layout_constraintTop_toBottomOf="@+id/textViewRoomType"
            app:layout_constraintLeft_toLeftOf="parent"/>

        <TextView
            android:text="@{dormDetails.dormDetails}"
            android:id="@+id/textViewDescription"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            tools:text="A very long textarea to contain dorm description. Should be multiline"
            android:padding="5dp"
            android:layout_marginLeft="20dp"
            app:layout_constraintTop_toBottomOf="@id/textViewAddress"
            app:layout_constraintLeft_toLeftOf="parent"/>

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

需要的任何其他内容将在以后进行编辑。

标签: androidandroid-fragmentskotlinandroid-recyclerview

解决方案


删除这些行:

if (savedInstanceState == null) {
    supportFragmentManager
        .beginTransaction()
        .add(R.id.fragment_home, HomeFragment.newInstance(), "dormList")
        .commit()
}

您正在HomeFragment通过NavHostFragment手动添加一个和另一个。使用 Navigation 时无需手动添加 Fragment。

您还应该根据导航到目标文档onRecyclerViewItemClick更新您的使用:navigate()

override fun onRecyclerViewItemClick(view: View, dorms: Dorms) {
    val navController = findNavController(R.id.nav_host_fragment)
    // If you're using Safe Args, use the ID generated from
    // the navigation graph and make sure you have
    // an argument of the correct type
    navController.navigate(
        HomeFragmentDirections.actionHomeToDetails(dorms))
}

您可能会发现查看目的地之间的传递数据文档以了解如何<argument>在图形中为您的Dorms对象创建一个以及如何设置 Safe Args 来为您生成 Directions 类会很有帮助。


推荐阅读