多个自定义ViewGroup中EditText的ID相同导致的问题

问题描述

最近写项目时,遇到两个自定义ViewGroup中EditText的ID相同而导致冲突的问题,描述如下。

  1. 我自定义了一个继承FrameLayout名为ClearableEditText的控件,里面包括一个AutoCompleteTextView(EditText的一种) 和一个ImageView。
  2. 我在LoginFragment(继承Fragment)里使用了两个ClearableEditText,并输入了值分别为123456789和abc。
  3. 我从LoginFragment里使用FragmentTransaction.replace方法跳转到另外一个Fragment,当回退到LoginFragment时,两个ClearableEditText都显示了abc。

图示如下


多个自定义ViewGroup中EditText的ID相同导致的问题_第1张图片
输入值并点击“注册”
多个自定义ViewGroup中EditText的ID相同导致的问题_第2张图片
点击回退
多个自定义ViewGroup中EditText的ID相同导致的问题_第3张图片
回退后两个EditText值变为一样

这应该是两个ClearableEditText中AutoCompleteTextView的id值相同的导致的。系统会在View的onSaveInstanceState中缓存View的状态,但应该是根据id来辨别View的,因此相同id的View只保存最后一个的状态,之前的会被覆盖,所以最后都显示为同一个值。

相关代码

自定义的ClearableEditText

class ClearableEditText @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0, defStyleRes: Int = 0)
    : FrameLayout(context, attrs, defStyleAttr, defStyleRes) {

    init {
        initView(context, attrs, defStyleAttr, defStyleRes)
    }

    lateinit var input: AutoCompleteTextView
    private lateinit var clearImage: ImageView

    private fun initView(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) {
        // init view
        val view = LayoutInflater.from(context).inflate(R.layout.view_clearable_edit_text, this, true)
        input = view.findViewById(R.id.et_clearable)
        clearImage = view.findViewById(R.id.iv_clearable)

        // init attr ......
    }

    override fun onSaveInstanceState(): Parcelable {
        Logger.d("view life -> onSaveInstanceState")
        return super.onSaveInstanceState()
    }

    override fun onRestoreInstanceState(state: Parcelable?) {
        Logger.d("view life -> onRestoreInstanceState")
        super.onRestoreInstanceState(state)
    }
}

view_clearable_edit_text布局




    

    

LoginFragment

class LoginFragment : BaseFragment() {
    override fun getFragmentID(): FragmentID {
        return FragmentID.LOGIN
    }

    companion object {
        val TAG = this::class.java.simpleName!!
    }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        Logger.d("fragment life circle---->onCreateView")
        return inflater.inflate(R.layout.fragment_login, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
   
        // 注册
        tv_register.setOnClickListener { toRegister() }

        // .....
    }

    private fun toRegister() {
        val ba = activity as BaseActivity
        ba.navigateReplace(RegistrationFragment(), getString(R.string.auth_register), true)
    }
}

fragment_login 布局



    

    

    

    

        

        
    

    

解决方法

可为每个ClearableEditText中的AutoCompleteTextView动态分配一个id,做法如下

  1. 在ClearableEditText的属性文件中加入id属性,如

    
        
        
    

  1. 在ClearableEditText中获取并添加id
private fun initView(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) {

        // init view
        val view = LayoutInflater.from(context).inflate(R.layout.view_clearable_edit_text, this, true)
        input = view.findViewById(R.id.et_clearable)
        clearImage = view.findViewById(R.id.iv_clearable)

        // init attr
        val ta = context.theme.obtainStyledAttributes(attrs, R.styleable.ClearableEditText, defStyleAttr, defStyleRes)
        try {
            val inputId = ta.getResourceId(R.styleable.ClearableEditText_inputId, 0x50)
            input.id = inputId
        } finally {
            ta.recycle()
        }
    }
  1. 在res/value/ids.xml(没有这个文件的话,创建一个)中,加入各种类型的ClearableEditText需要的id.注意这里的值如0x51、0x52等其实可以不需要,因为应用为每个资源自动生成一个资源id,上面的代码中获取的就是资源id


    
    0x51
    0x52
    0x53
    0x54

  1. 在布局中引用资源id
    
   

    
    

你可能感兴趣的:(多个自定义ViewGroup中EditText的ID相同导致的问题)