Я создаю вид, где у меня была какая-то форма регистрации, и я столкнулся со странной проблемой. Поэтому мне нужно создать форму, в которой будет 10 экранов, на каждом из которых пользователю будет предложено ввести конкретную информацию. Поэтому я решил использовать ViewPager
с FragmentPageAdapter
. Большинство представлений выглядят одинаково, поэтому я хотел использовать один файл макета во всех них. Код макета размещен ниже.
<?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">
<TextView
android:id="@+id/form_text"
style="@style/FormText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="@string/registration_experience_text" />
<com.TwoButtonsView
android:id="@+id/buttons_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/default_app_margin"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/form_text"
app:negative_button_text=""
app:positive_button_text="" />
</androidx.constraintlayout.widget.ConstraintLayout>
TwoButtonsView - это мой пользовательский вид, который выглядит следующим образом:
class TwoButtonsView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : ConstraintLayout(context, attrs, defStyleAttr) {
private lateinit var negativeButton: MaterialButton
private lateinit var positiveButton: MaterialButton
private var listener: TwoButtonsViewListener? = null
interface TwoButtonsViewListener {
fun onNegativeButtonClick()
fun onPositiveButtonClick()
}
init {
init(context, attrs)
}
private fun init(context: Context, attrs: AttributeSet?) {
val view = LayoutInflater.from(context).inflate(R.layout.two_buttons_layout, this, true)
negativeButton = view.findViewById(R.id.negative_button)
positiveButton = view.findViewById(R.id.positive_button)
negativeButton.setOnClickListener {
listener?.onNegativeButtonClick()
setButtonClicked(context, negativeButton)
setButtonDefault(context, positiveButton)
}
positiveButton.setOnClickListener {
listener?.onPositiveButtonClick()
setButtonClicked(context, positiveButton)
setButtonDefault(context, negativeButton)
}
if (attrs == null) {
return
}
val typedArray =
context.obtainStyledAttributes(attrs, R.styleable.TwoButtonsView)
try {
setNegativeButtonText(typedArray)
setPositiveButtonText(typedArray)
} catch (exception: Exception) {
Timber.e(exception)
} finally {
typedArray.recycle()
}
}
private fun setButtonClicked(context: Context, button: MaterialButton) {
button.backgroundTintList = ColorStateList.valueOf(Color.WHITE)
button.setTextColor(ContextCompat.getColor(context, R.color.colorPrimary))
}
private fun setButtonDefault(context: Context, button: MaterialButton) {
button.backgroundTintList =
ColorStateList.valueOf(ContextCompat.getColor(context, R.color.colorPrimary))
button.setTextColor(Color.WHITE)
}
private fun setNegativeButtonText(typedArray: TypedArray) {
negativeButton.text = typedArray.getString(R.styleable.TwoButtonsView_negative_button_text)
}
private fun setPositiveButtonText(typedArray: TypedArray) {
positiveButton.text = typedArray.getString(R.styleable.TwoButtonsView_positive_button_text)
}
Файл макета:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<com.google.android.material.button.MaterialButton
android:id="@+id/positive_button"
style="@style/TwoButtonsFormDefaultButton"
android:layout_width="0dp"
android:layout_height="120dp"
android:layout_marginTop="@dimen/default_app_margin"
android:layout_marginEnd="3dp"
app:layout_constraintEnd_toStartOf="@id/negative_button"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/form_text"
tools:text="@string/registration_experience_positive" />
<com.google.android.material.button.MaterialButton
android:id="@+id/negative_button"
style="@style/TwoButtonsFormDefaultButton"
android:layout_width="0dp"
android:layout_height="120dp"
android:layout_marginStart="3dp"
android:layout_marginTop="@dimen/default_app_margin"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/positive_button"
app:layout_constraintTop_toBottomOf="@id/form_text"
tools:text="@string/registration_experience_negative" />
</androidx.constraintlayout.widget.ConstraintLayout>
Мой адаптер для ViewPager
выглядит так:
class RegistrationPagerAdapter(
fragmentManager: FragmentManager
) : FragmentStatePagerAdapter(fragmentManager) {
override fun getItem(position: Int) =
when (position) {
0 -> RegistrationExperienceFragment()
1 -> RegistrationRoleFragment()
2 -> RegistrationNameFragment()
3 -> RegistrationLastNameFragment()
4 -> RegistrationBirthdayFragment()
5 -> RegistrationGenderFragment()
6 -> RegistrationCountryFragment()
7 -> RegistrationPhoneNumberFragment()
8 -> RegistrationNewsletterFragment()
else -> RegistrationOpportunitiesFragment()
}
override fun getCount(): Int = 10
}
И почти каждый Fragment
выглядит так:
class RegistrationExperienceFragment : BaseFragment(), TwoButtonsView.TwoButtonsViewListener {
override fun onNegativeButtonClick() {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun onPositiveButtonClick() {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View = inflater.inflate(R.layout.fragment_two_buttons_form, container, false)
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
setupUi()
}
private fun setupUi() {
form_text.text = getString(R.string.registration_experience_text)
}
companion object {
const val TAG = "RegistrationExperienceFragment"
fun newInstance() =
RegistrationExperienceFragment()
}
}
И что здесь не так, так это то, что когда я перехожу ко второму фрагменту (он выглядит точно так же, как первый), а затем я возвращаюсь к первому фрагменту, все события нажатия кнопки применяются ко второму фрагменту. Поэтому, когда я нажимаю кнопку на первом фрагменте, фактически цвет кнопки изменяется на втором фрагменте, а цвет на первом фрагменте не изменяется. Я хотел бы избежать создания каждого нового XML-файла для фрагмента, но я не знаю, возможно ли это на самом деле.
Любая помощь будет высоко оценена;)