RadioGroup Android 数据绑定 XML 与包含布局

问题描述 投票:0回答:1

我目前面临应用程序中单选按钮的问题。我的应用程序包含信息表单,其中包括带有其他视图的单选按钮,并且有多种表单。当我选择第一个和第二个单选按钮的选项 1 并选择片段中最后一个单选按钮的选项 2 并导航到另一个片段并返回到上一个片段时,所有单选按钮都选择了选项 2。无论我选择什么作为单选按钮的选项,无论选择最后一个单选选项,所有单选按钮都会选择该选项。当我导航到另一个片段并返回到上一个片段时,会发生这种情况。我想在导航回上一个片段时显示选择的正确选项。

注:

我正在使用 Hilt、DataBinding、ViewBinding、MVVM、HiltNavGraph

layout_textview_radiogroup.xml

<?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>

        <variable
            name="tvText"
            type="String" />

        <variable
            name="option1Text"
            type="String" />

        <variable
            name="option2Text"
            type="String" />

        <variable
            name="selectedOption"
            type="Integer" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:id="@+id/layout_textview"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@{tvText}"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            tools:text="Some Text"/>

        <RadioGroup
            android:id="@+id/radioGroup"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="7dp"
            app:layout_constraintTop_toBottomOf="@id/layout_textview">

            <RadioButton
                android:id="@+id/rb_option1"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginBottom="10dp"
                android:checked="@{selectedOption == @id/rb_option1 ? true : false}"
                android:text="@{option1Text}"
                tools:text="Option 1" />

            <RadioButton
                android:id="@+id/rb_option2"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:checked="@{selectedOption == @id/rb_option2 ? true : false}"
                android:text="@{option2Text}"
                tools:text="Option 2" />

        </RadioGroup>

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

fragment_some.xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <data>
        <variable
            name="fragment"
            type="com.yousuf.demo.radio.SomeFragment" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".radio.SomeFragment"
        android:gravity="center"
        android:orientation="vertical"
        android:padding="20dp">

        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Go Back"
            android:onClick="@{() -> fragment.goBack()}" />

    </LinearLayout>
</layout>

fragment_radio.xml

<?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>

        <variable
            name="viewModel"
            type="com.yousuf.demo.radio.RadioViewModel" />
        <variable
            name="fragment"
            type="com.yousuf.demo.radio.RadioFragment" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="20dp">

        <include
            android:id="@+id/layout_question1"
            layout="@layout/layout_textview_radiogroup"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:layout_constraintTop_toTopOf="parent"
            app:option1Text="@{`Option 1`}"
            app:option2Text="@{`Option 2`}"
            app:selectedOption="@={viewModel.selectedQuestion1OptionId}"
            app:tvText="@{`Question 1`}" />

        <include
            android:id="@+id/layout_question2"
            layout="@layout/layout_textview_radiogroup"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            app:layout_constraintTop_toBottomOf="@id/layout_question1"
            app:option1Text="@{`Option 1`}"
            app:option2Text="@{`Option 2`}"
            app:selectedOption="@={viewModel.selectedQuestion2OptionId}"
            app:tvText="@{`Question 2`}" />

        <include
            android:id="@+id/layout_question3"
            layout="@layout/layout_textview_radiogroup"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            app:layout_constraintTop_toBottomOf="@id/layout_question2"
            app:option1Text="@{`Option 1`}"
            app:option2Text="@{`Option 2`}"
            app:selectedOption="@={viewModel.selectedQuestion3OptionId}"
            app:tvText="@{`Question 3`}" />

        <Button
            android:id="@+id/btn_next"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:onClick="@{() -> fragment.navigateToSomeFragment()}"
            android:text="Next"
            app:layout_constraintTop_toBottomOf="@id/layout_question3"/>

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

nav_graph.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/nav_graph"
    app:startDestination="@id/radio_nav_graph">
    <navigation android:id="@+id/radio_nav_graph"
        app:startDestination="@id/radioFragment">
        <fragment
            android:id="@+id/radioFragment"
            android:name="com.yousuf.demo.radio.RadioFragment"
            android:label="RadioFragment">
            <action
                android:id="@+id/action_radioFragment_to_someFragment"
                app:destination="@id/someFragment" />
        </fragment>
        <fragment
            android:id="@+id/someFragment"
            android:name="com.yousuf.demo.radio.SomeFragment"
            android:label="SomeFragment" />
    </navigation>
</navigation>

BaseFragment.kt

import android.os.Bundle
import android.view.*
import androidx.annotation.DrawableRes
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.MenuProvider
import androidx.databinding.ViewDataBinding
import androidx.fragment.app.Fragment
import androidx.lifecycle.LifecycleOwner
import androidx.navigation.fragment.findNavController
import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.setupWithNavController
import com.google.android.material.appbar.MaterialToolbar

abstract class BaseFragment<Type : ViewDataBinding> : Fragment() {

    private var _binding: Type? = null
    protected val binding get() = _binding!!

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?,
    ): View? {
        _binding = inflateLayout(inflater)
        init()
        return binding.root
    }

    abstract fun inflateLayout(inflater: LayoutInflater): Type

    private fun init() {
        binding.lifecycleOwner = viewLifecycleOwner
    }

    override fun onDestroy() {
        super.onDestroy()
        _binding = null
    }

    fun setUpToolbar(
        toolbar: MaterialToolbar,
        @DrawableRes toolbarHomeIcon: Int,
        menuProviderCallback: MenuProvider,
        viewLifecycleOwner: LifecycleOwner,
    ) {
        toolbar.setupWithNavController(
            findNavController(),
            AppBarConfiguration(findNavController().graph)
        )
        (requireActivity() as AppCompatActivity).apply {
            setSupportActionBar(toolbar)
            supportActionBar?.setDisplayHomeAsUpEnabled(true)
            supportActionBar?.setHomeAsUpIndicator(toolbarHomeIcon)
        }
        requireActivity().addMenuProvider(menuProviderCallback, viewLifecycleOwner)
    }
}

SomeFragment.kt

import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.navigation.fragment.findNavController
import com.yousuf.demo.BaseFragment
import com.yousuf.demo.R
import com.yousuf.demo.databinding.FragmentSomeBinding

class SomeFragment : BaseFragment<FragmentSomeBinding>() {

    override fun inflateLayout(inflater: LayoutInflater): FragmentSomeBinding {
        return FragmentSomeBinding.inflate(inflater)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        binding.fragment = this@SomeFragment
    }

    fun goBack() {
        findNavController().navigateUp()
    }

}

RadioFragment.kt

import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.viewModels
import androidx.hilt.navigation.fragment.hiltNavGraphViewModels
import androidx.navigation.fragment.findNavController
import com.yousuf.demo.BaseFragment
import com.yousuf.demo.R
import com.yousuf.demo.databinding.FragmentRadioBinding
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
class RadioFragment : BaseFragment<FragmentRadioBinding>() {

    private val viewModel: RadioViewModel by hiltNavGraphViewModels(R.id.radio_nav_graph)

    override fun inflateLayout(inflater: LayoutInflater): FragmentRadioBinding {
        return FragmentRadioBinding.inflate(inflater)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        binding.viewModel = viewModel
        binding.fragment = this@RadioFragment

        setUpRadioClickListener()
    }

    private fun setUpRadioClickListener() {
        with(viewModel) {
            binding.layoutQuestion1.radioGroup.setOnCheckedChangeListener { radioGroup, _ ->
                selectedQuestion1OptionId.value = radioGroup.checkedRadioButtonId
            }
            binding.layoutQuestion2.radioGroup.setOnCheckedChangeListener { radioGroup, _ ->
                selectedQuestion2OptionId.value = radioGroup.checkedRadioButtonId
            }
            binding.layoutQuestion3.radioGroup.setOnCheckedChangeListener { radioGroup, _ ->
                selectedQuestion3OptionId.value = radioGroup.checkedRadioButtonId
            }
        }

    }

    fun navigateToSomeFragment() {
        findNavController().navigate(R.id.action_radioFragment_to_someFragment)
    }
}

RadioViewModel.kt

import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject

@HiltViewModel
class RadioViewModel @Inject constructor(): ViewModel() {

    var selectedQuestion1OptionId = MutableLiveData(-1)

    var selectedQuestion2OptionId = MutableLiveData(-1)

    var selectedQuestion3OptionId = MutableLiveData(-1)
}
android kotlin android-databinding android-radiogroup android-include
1个回答
0
投票

我通过玩了一下找到了答案

  1. 为我的 RadioGroup 添加了一个侦听器

变量名称=“onCheckedChangedListener” 类型=“android.widget.RadioGroup.OnCheckedChangeListener”/>

  1. 通过添加这两行修改了我的 RadioGroup

android:onCheckedChanged="@{onCheckedChangedListener}" android:checkedButton="@{selectedOption}"

  1. 从每个 RadioButton 中删除一行

android:checked="@{selectedOption == @id/rb_option1 ? true : false}"

  1. 在我的 viewModel 中为每个 RadioGroup 选择添加了函数
fun setQuestion1OptionId(id: Int) {
    selectedQuestion1OptionId.value = id
}

fun setQuestion2OptionId(id: Int) {
    selectedQuestion2OptionId.value = id
}

fun setQuestion3OptionId(id: Int) {
    selectedQuestion3OptionId.value = id
}
  1. 为fragment_radio.xml中每个包含的RadioGroup添加了侦听器

app:onCheckedChangedListener="@{(radioGroup, id) -> viewModel.setQuestion1OptionId(id)}"

  1. 从 RadioFragment 中删除了实现

这是我修改后的代码

layout_textview_radiogroup.xml

<?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>

        <variable
            name="tvText"
            type="String" />

        <variable
            name="option1Text"
            type="String" />

        <variable
            name="option2Text"
            type="String" />

        <variable
            name="selectedOption"
            type="Integer" />

        <!--Modification-->
        <variable
            name="onCheckedChangedListener"
            type="android.widget.RadioGroup.OnCheckedChangeListener" />

    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:id="@+id/layout_textview"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@{tvText}"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            tools:text="Some Text"/>

        <!--Modification-->
        <RadioGroup
            android:id="@+id/radioGroup"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="7dp"
            android:onCheckedChanged="@{onCheckedChangedListener}"
            android:checkedButton="@{selectedOption}"
            app:layout_constraintTop_toBottomOf="@id/layout_textview">

            <!--Modification-->
            <RadioButton
                android:id="@+id/rb_option1"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginBottom="10dp"
                android:text="@{option1Text}"
                tools:text="Option 1" />

            <!--Modification-->
            <RadioButton
                android:id="@+id/rb_option2"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="@{option2Text}"
                tools:text="Option 2" />

        </RadioGroup>

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

fragment_radio.kt

<?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>

        <variable
            name="viewModel"
            type="com.yousuf.demo.radio.RadioViewModel" />

        <variable
            name="fragment"
            type="com.yousuf.demo.radio.RadioFragment" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="20dp">

        <!--Modification-->
        <include
            android:id="@+id/layout_question1"
            layout="@layout/layout_textview_radiogroup"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:layout_constraintTop_toTopOf="parent"
            app:onCheckedChangedListener="@{(radioGroup, id) -> viewModel.setQuestion1OptionId(id)}"
            app:option1Text="@{`Option 1`}"
            app:option2Text="@{`Option 2`}"
            app:selectedOption="@{viewModel.selectedQuestion1OptionId}"
            app:tvText="@{`Question 1`}" />

        <!--Modification-->
        <include
            android:id="@+id/layout_question2"
            layout="@layout/layout_textview_radiogroup"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            app:layout_constraintTop_toBottomOf="@id/layout_question1"
            app:onCheckedChangedListener="@{(radioGroup, id) -> viewModel.setQuestion2OptionId(id)}"
            app:option1Text="@{`Option 1`}"
            app:option2Text="@{`Option 2`}"
            app:selectedOption="@{viewModel.selectedQuestion2OptionId}"
            app:tvText="@{`Question 2`}" />

        <!--Modification-->
        <include
            android:id="@+id/layout_question3"
            layout="@layout/layout_textview_radiogroup"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            app:layout_constraintTop_toBottomOf="@id/layout_question2"
            app:onCheckedChangedListener="@{(radioGroup, id) -> viewModel.setQuestion3OptionId(id)}"
            app:option1Text="@{`Option 1`}"
            app:option2Text="@{`Option 2`}"
            app:selectedOption="@{viewModel.selectedQuestion3OptionId}"
            app:tvText="@{`Question 3`}" />

        <Button
            android:id="@+id/btn_next"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:onClick="@{() -> fragment.navigateToSomeFragment()}"
            android:text="Next"
            app:layout_constraintTop_toBottomOf="@id/layout_question3" />

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

RadioFragment.kt

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import androidx.hilt.navigation.fragment.hiltNavGraphViewModels
import androidx.navigation.fragment.findNavController
import com.yousuf.demo.BaseFragment
import com.yousuf.demo.R
import com.yousuf.demo.databinding.FragmentRadioBinding
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
class RadioFragment : BaseFragment<FragmentRadioBinding>() {

    private val viewModel: RadioViewModel by hiltNavGraphViewModels(R.id.radio_nav_graph)

    override fun inflateLayout(inflater: LayoutInflater): FragmentRadioBinding {
        return FragmentRadioBinding.inflate(inflater)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        binding.viewModel = viewModel
        binding.fragment = this@RadioFragment
    }

    fun navigateToSomeFragment() {
        findNavController().navigate(R.id.action_radioFragment_to_someFragment)
    }
}

RadioViewModel.kt

import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject

@HiltViewModel
class RadioViewModel @Inject constructor(): ViewModel() {


    var selectedQuestion1OptionId = MutableLiveData(-1)

    var selectedQuestion2OptionId = MutableLiveData(-1)

    var selectedQuestion3OptionId = MutableLiveData(-1)

    // Modification
    fun setQuestion1OptionId(id: Int) {
        selectedQuestion1OptionId.value = id
    }

    fun setQuestion2OptionId(id: Int) {
        selectedQuestion2OptionId.value = id
    }

    fun setQuestion3OptionId(id: Int) {
        selectedQuestion3OptionId.value = id
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.