首页 > 解决方案 > 自定义 TextInputLayout 在后按时设置错误的值

问题描述

在我的应用程序中,我使用包含TextInputLayout以下代码的自定义视图:

    <?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <com.google.android.material.textfield.TextInputLayout
        android:id="@+id/input_layout"
        style="@style/UbiInput2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="-"
        android:orientation="horizontal"
        app:boxBackgroundColor="@color/white">

        <com.google.android.material.textfield.TextInputEditText
            android:id="@+id/input_value"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:inputType="textPersonName" />

    </com.google.android.material.textfield.TextInputLayout>
</androidx.appcompat.widget.LinearLayoutCompat>

和科特林

      class TextInputView(context: Context, attrs: AttributeSet?) : LinearLayout(context, attrs) {
        
            var errorMessage: String? = ""
        
            init {
                inflate(context, R.layout.text_input_view, this)
                val attributes = context.obtainStyledAttributes(attrs, R.styleable.TextInputView)
                val inputLayout = findViewById<TextInputLayout>(R.id.input_layout)
                val inputValue = findViewById<TextInputEditText>(R.id.input_value)
                inputLayout.hint = attributes.getString(R.styleable.TextInputView_hint)
                inputValue.hint = attributes.getString(R.styleable.TextInputView_placeholderText)
                inputLayout.isExpandedHintEnabled =
                    attributes.getBoolean(R.styleable.TextInputView_expandedHintEnabled, true)
                errorMessage = attributes.getString(R.styleable.TextInputView_errorMessage)
                inputLayout.isHelperTextEnabled = false
                inputValue.inputType =
                    attributes.getInt(
                        R.styleable.TextInputView_android_inputType,
                        InputType.TYPE_CLASS_TEXT
                    )
                if (attributes.hasValue(R.styleable.TextInputView_android_maxLength)) {
                    inputValue.filters += InputFilter.LengthFilter(
                        attributes.getInt(
                            R.styleable.TextInputView_android_maxLength,
                            100
                        )
                    )
                }
                inputValue.gravity =
                    attributes.getInt(R.styleable.TextInputView_android_gravity, Gravity.START)
                if (attributes.getBoolean(R.styleable.TextInputView_android_gravity, false)) {
                    inputLayout.helperText = attributes.getString(R.styleable.TextInputView_helperText)
                }
                if (attributes.getBoolean(R.styleable.TextInputView_helperTextEnabled, false)) {
                    inputLayout.isHelperTextEnabled = true
                    inputLayout.helperText = attributes.getString(R.styleable.TextInputView_helperText)
                }
        
                inputLayout.startIconDrawable =
                    attributes.getDrawable(R.styleable.TextInputView_startIconDrawable)
                 attributes.recycle()
            }
    }

@BindingAdapter("textValue")
fun TextInputView.setTextValue(value: String?) {
    value?.let {
        setValue(value)
    }
}

@InverseBindingAdapter(attribute = "textValue")
fun TextInputView.getTextValue(): String {
    return value()
}

@BindingAdapter("textValueAttrChanged")
fun TextInputView.setListener(textAttrChanged: InverseBindingListener) {
    val inputValue = findViewById<TextInputEditText>(R.id.input_value)

    inputValue.addTextChangedListener(object : TextWatcher {
        override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
        }

        override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
        }

        override fun afterTextChanged(s: Editable?) {
            textAttrChanged.onChange()
        }
    })
}

我有以下屏幕,点击按钮会转到下一个片段。使用导航组件。

在此处输入图像描述

但是在下一个屏幕上,当我按下返回按钮返回搜索表单时,和的TextInputLayout值都是相同的。我设置这些的唯一地方是在自定义视图中。从调试中我可以看到当时设置了所有正确的值。hinthelperText

在此处输入图像描述

我有点不知道那里发生了什么。任何提示将不胜感激。

使用的材料库版本:1.3.0-alpha04

所有代码库已根据最新更改迁移到视图绑定

视图使用如下:

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

    <data>
        <variable
            name="viewModel"
            type="com.ubigo.features.v2.products.taxi.SearchViewModel" />

        <variable
            name="dateFormat"
            type="com.ubigo.ubicore.date.UbiDate" />
    </data>
    
    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/rental_search_root"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/background">
        
        <androidx.cardview.widget.CardView
            android:id="@+id/rental_search_form"
            style="@style/WhiteCardView"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginTop="16dp"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/textView10">

            <androidx.constraintlayout.widget.ConstraintLayout
                android:id="@+id/constraintLayout3"
                android:layout_width="match_parent"
                android:layout_height="wrap_content">

                <com.ubigo.ubicore.ui.TextInputView
                    android:id="@+id/pickup"
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_marginStart="8dp"
                    android:layout_marginTop="8dp"
                    android:layout_marginEnd="8dp"
                    app:hint="@string/product_start"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintHorizontal_bias="0.0"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toTopOf="parent"
                    app:startIconDrawable="@drawable/ic_calendar"
                    app:textValue="@{dateFormat.getPrettyDate(viewModel.pickupDateTime)}" />

                <View
                    android:id="@+id/divider6"
                    android:layout_width="0dp"
                    android:layout_height="1dp"
                    android:layout_marginStart="8dp"
                    android:layout_marginTop="8dp"
                    android:layout_marginEnd="8dp"
                    android:background="?android:attr/listDivider"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toBottomOf="@+id/pickup" />

                <com.ubigo.ubicore.ui.TextInputView
                    android:id="@+id/dropoff"
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_marginStart="8dp"
                    android:layout_marginTop="8dp"
                    android:layout_marginEnd="8dp"
                    android:layout_marginBottom="8dp"
                    app:hint="@string/product_end"
                    app:layout_constraintBottom_toBottomOf="parent"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toBottomOf="@+id/divider6"
                    app:startIconDrawable="@drawable/ic_calendar"
                    app:textValue="@{dateFormat.getPrettyDate(viewModel.destinationDatetime)}" />
            </androidx.constraintlayout.widget.ConstraintLayout>
        </androidx.cardview.widget.CardView>

        <com.ubigo.ubicore.ui.LoaderButton
            android:id="@+id/rental_search_button"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginStart="16dp"
            android:layout_marginTop="32dp"
            android:layout_marginEnd="16dp"
            android:text="@string/product_rental_show_car"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/rental_search_location" />

        <androidx.cardview.widget.CardView
            android:id="@+id/rental_search_location"
            style="@style/WhiteCardView"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginTop="32dp"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/rental_search_form">

            <androidx.constraintlayout.widget.ConstraintLayout
                android:id="@+id/constraintLayout4"
                android:layout_width="match_parent"
                android:layout_height="wrap_content">

                <com.ubigo.ubicore.ui.TextInputView
                    android:id="@+id/user_location"
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_marginStart="8dp"
                    android:layout_marginTop="8dp"
                    android:layout_marginEnd="8dp"
                    android:layout_marginBottom="8dp"
                    app:helperText="@string/product_rental_location"
                    app:helperTextEnabled="true"
                    app:hint="@string/product_pickup_location"
                    app:layout_constraintBottom_toBottomOf="parent"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toTopOf="parent"
                    app:startIconDrawable="@drawable/ic_location_on_black_24dp"
                    app:textValue="@{viewModel.depAddress}" />
            </androidx.constraintlayout.widget.ConstraintLayout>
        </androidx.cardview.widget.CardView>
        
        <TextView
            android:id="@+id/textView10"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginStart="32dp"
            android:layout_marginTop="16dp"
            android:layout_marginEnd="32dp"
            android:text="@string/product_rental_weekend"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

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

以及片段的初始化:

class RentalSearchFragment : Fragment() {

    val viewModel: SearchViewModel by viewModel()

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

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        if (_binding == null) {
            _binding = FragmentRentalSearchBinding.inflate(inflater, container, false)
            binding.lifecycleOwner = viewLifecycleOwner
            binding.viewModel = viewModel
            binding.dateFormat = UbiDate()
        }

        return binding.root
    }

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

标签: androidandroid-layoutmaterial-components-androidandroid-viewbinding

解决方案


我能够通过实现 onSaveInstanceState、onRestoreInstanceState、dispatchSaveInstanceState、dispatchRestoreInstanceState 和 setValues 来解决这个确切的问题,如此处所述

http://www.devexchanges.info/2016/03/custom-compound-view-in-android.html

上面的链接介绍了有关如何实现这些功能的所有必要细节。毫无疑问,您还可以找到无数其他有关如何实现此 android 范例的资源。


推荐阅读