Android 嵌套包含布局、函数传递和通过 DataBinding 实现

Android Nested Include Layouts Function Passing and Implementation Via DataBinding

提问人:Muhammad Yousuf 提问时间:8/31/2023 更新时间:8/31/2023 访问量:26

问:

我使用 TextInputLayout 和 MaterialAutoCompleteTextView 制作了一个自定义下拉列表,我在同一片段和多个片段中多次使用它们作为包含的布局。我正在使用 DataBinding 在包含的布局之间传递数据。现在问题是下拉列表的点击事件,我如何在包含的布局中传递setOnItemClickListener并在下拉列表中使用它。我尝试使用 BindingAdapters 和其他笨拙的东西,但无法通过布局实现这一点。

下拉列表.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="dropDownHint"
            type="String" />

        <variable
            name="dropDownList"
            type="java.util.List&lt;String&gt;" />
    </data>

    <com.google.android.material.textfield.TextInputLayout
        android:id="@+id/textInputLayout"
        style="@style/Theme.TextInputLayout.DropDown.Common"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <com.google.android.material.textfield.MaterialAutoCompleteTextView
            android:id="@+id/dropDown"
            style="@style/Theme.MaterialAutoCompleteTextView.DropDown"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:dropDownSelector="@drawable/background_dropdown"
            android:hint="@{dropDownHint}"
            android:inputType="none"
            app:setDropDownBackground="@{@drawable/background_dropdown}"
            app:setDropDownItems="@{dropDownList}"
            tools:hint="Some Hint" />

    </com.google.android.material.textfield.TextInputLayout>
</layout>

layout_textview_dropdown.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="dropDownHint"
            type="String" />

        <variable
            name="dropDownList"
            type="java.util.List&lt;String&gt;" />
    </data>

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

        <include
            android:id="@+id/layout_textview"
            layout="@layout/textview_heading"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:tvText="@{tvText}" />

        <include
            android:id="@+id/layout_dd_surgical"
            layout="@layout/dropdown"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="7dp"
            app:dropDownHint="@{dropDownHint}"
            app:dropDownList="@{dropDownList}"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@id/layout_textview" />

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

fragment_step1.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="SomeViewModel" />

    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="@dimen/overall_padding"
        tools:context=".ui.patient_scan.step1.Step1Fragment">

        <include
            android:id="@+id/layout_fc"
            layout="@layout/layout_textview_dropdown"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            app:dropDownHint="@{@string/dd_hint_fc}"
            app:dropDownList="@{viewModel.fcList}"
            app:layout_constraintBottom_toTopOf="@id/layout_healthFacility"
            app:layout_constraintTop_toTopOf="parent"
            app:tvText="@{@string/tv_text_fc}" />

        <include
            android:id="@+id/layout_healthFacility"
            layout="@layout/layout_textview_dropdown"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="@dimen/overall_spacing"
            app:dropDownHint="@{@string/dd_hint_healthFacility}"
            app:dropDownList="@{viewModel.healthFacility}"
            app:layout_constraintBottom_toTopOf="@id/cl_date"
            app:layout_constraintTop_toBottomOf="@id/layout_fc"
            app:tvText="@{@string/tv_text_healthFacility}" />

        ...

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

材料AutoCompleteTextViewExt.kt

import android.graphics.drawable.Drawable
import androidx.databinding.BindingAdapter
import com.google.android.material.textfield.MaterialAutoCompleteTextView
import com.merisehat.clinicapp.ui.patient_scan.step1.DropDownAdapter

@BindingAdapter("setDropDownBackground")
fun MaterialAutoCompleteTextView.setDropDownBackground(drawable: Drawable) {
    setDropDownBackgroundDrawable(drawable)
}

@BindingAdapter("setDropDownItems")
fun MaterialAutoCompleteTextView.setDropDownItems(list: List<String>?) {
    if (list.isNullOrEmpty()) return
    val adapter = DropDownAdapter(context, list)
    setAdapter(adapter)
    setOnItemClickListener { _, _, position, _ ->
        adapter.setSelectedItem(position)
    }
}

DropDownAdapter.kt

import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ArrayAdapter
import androidx.databinding.DataBindingUtil
import com.merisehat.clinicapp.data.models.api.dropdown.Country
import com.merisehat.clinicapp.databinding.ItemDropdownBinding

class DropDownAdapter(context: Context, list: List<String>):
    ArrayAdapter<String>(context, 0, list) {

    private var selectedItemPosition = -1

    override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
        val item = getItem(position)
        val binding: ItemDropdownBinding = if (convertView == null) {
            val inflater = LayoutInflater.from(context)
            ItemDropdownBinding.inflate(inflater, parent, false)
        } else {
            DataBindingUtil.getBinding(convertView)!!
        }

        binding.item = item
        binding.isSelected = position == selectedItemPosition

        return binding.root
    }

    override fun getDropDownView(position: Int, convertView: View?, parent: ViewGroup): View {
        return getView(position, convertView, parent)
    }

    fun setSelectedItem(position: Int) {
        selectedItemPosition = position
        notifyDataSetChanged()
    }

}

我有一个解决方案,通过它我可以通过 Fragment 实现 setOnItemClickListener,但我正在寻找一个干净的解决方案,我可以通过数据绑定布局实现,这样我就不必使用 Fragments

android kotlin android-layout android-xml android-databinding

评论


答: 暂无答案