【问题标题】:Recyclerview Item onclick overlays the next fragment instead of replacing itRecyclerview Item onclick 覆盖下一个片段而不是替换它
【发布时间】:2020-01-20 02:04:52
【问题描述】:

我有这些活动、片段、它的视图模型和它们的适配器。我已经可以在单击 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()
    }
}

HomeFragment:

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>

其他需要的内容将在以后编辑。

【问题讨论】:

    标签: android android-fragments kotlin android-recyclerview


    【解决方案1】:

    删除这些行:

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

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

    您还应该按照Navigate to a destination documentation 更新您的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))
    }
    

    查看 Pass data between destinations documentation 以了解如何在图形中为 Dorms 对象创建 &lt;argument&gt; 以及如何设置 Safe Args 来为您生成 Directions 类,您可能会发现这很有帮助。

    【讨论】:

    • 我确实发现这些对我有用,但我得到 this cast will never succeed 在目的地之间传递(在目的地,dormDetailsFragment),这导致我的应用程序到达宿舍细节时崩溃。我确实对宿舍细节使用相同的代码。
    • 如果你正确设置了参数,你就不应该在任何地方强制转换任何东西(这就是 Safe Args 的重点——类型安全)。您可以使用您尝试设置的代码和参数来编辑您的问题吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多