自定义 TextInputLayout 在后按时设置错误的值

Posted

技术标签:

【中文标题】自定义 TextInputLayout 在后按时设置错误的值【英文标题】:Custom TextInputLayout gets wrong values set on back pressed 【发布时间】:2021-03-13 00:01:51 【问题描述】:

在我的应用中,我正在使用包含 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_
    android:layout_>

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

        <com.google.android.material.textfield.TextInputEditText
            android:id="@+id/input_value"
            android:layout_
            android:layout_
            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()
        
    )

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

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

我对那里发生的事情有点不知所措。任何提示将不胜感激。

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

所有代码库已迁移到视图绑定according the latest changes

视图使用如下:

<?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_
        android:layout_
        android:background="@color/background">
        
        <androidx.cardview.widget.CardView
            android:id="@+id/rental_search_form"
            style="@style/WhiteCardView"
            android:layout_
            android:layout_
            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_
                android:layout_>

                <com.ubigo.ubicore.ui.TextInputView
                    android:id="@+id/pickup"
                    android:layout_
                    android:layout_
                    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_
                    android:layout_
                    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_
                    android:layout_
                    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_
            android:layout_
            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_
            android:layout_
            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_
                android:layout_>

                <com.ubigo.ubicore.ui.TextInputView
                    android:id="@+id/user_location"
                    android:layout_
                    android:layout_
                    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_
            android:layout_
            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>

以及Fragment的初始化:

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
    

【问题讨论】:

同样的问题,你找到解决办法了吗? 在 for 循环中动态添加 TextInputLayout 时出现类似问题。通过在 post 方法中调用 infalte 和 addView 来解决。 View.post //inflate //添加视图 您找到解决此问题的方法了吗? 【参考方案1】:

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

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

上面的链接详细介绍了如何实现这些功能。毫无疑问,您还可以找到无数其他资源来了解如何实现这个 android 范例。

【讨论】:

正如目前所写,您的答案尚不清楚。请edit 添加其他详细信息,以帮助其他人了解这如何解决所提出的问题。你可以找到更多关于如何写好答案的信息in the help center。 仅供参考,该评论已被看到您答案的人删除。只是软件没有显示分享反馈的人。别担心,它不是机器人自动丢弃 cmets! 虽然您编辑中的论点可能是有效的,但它是元评论,即它与问题或答案的技术内容无关,因此不适合在答案框中。请不要在答案中添加此类文本。此外,您回复的评论只是建议您扩展您的答案;是否要这样做完全取决于您。

以上是关于自定义 TextInputLayout 在后按时设置错误的值的主要内容,如果未能解决你的问题,请参考以下文章

Android:TextInputLayout - 自定义提示、底线和错误消息的颜色

登录界面AutoUtils 屏幕适配自定义Edittext(显示密码可见和一键清空)和 TextInputLayout的使用。

导航组件防止在后按时重新创建片段

自定义视图焦点区域

如何在后按时以编程方式关闭 SearchView?在片段中

卸载所有先前安装的屏幕以在后按时退出应用程序