自定义视图:配置更改时的奇怪行为

时间:2018-09-27 12:38:47

标签: android android-layout

我有一个带有edittext和imageview的自定义视图。我在同一布局中多次使用此视图。但是,它表现得很奇怪。每当我旋转设备时,来自xml的最后一个声明视图的值就会放入布局中的所有其他视图中,而我只是无法弄清楚哪里出了问题。

我的观点:

class InputView(context: Context, attrs: AttributeSet?, @AttrRes defStyleAttr: Int) : ConstraintLayout(context, attrs, defStyleAttr) {

    private var textInputLayout: TextInputLayout
    private var textView: TextInputEditText
    private var imageView: ImageView

    constructor(context: Context) : this(context, null)
    constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)

    init {
        val view = LayoutInflater.from(context).inflate(R.layout.custom_inputview, this, true)

        textInputLayout = view.custom_inputview_text_input_layout
        textView = view.custom_inputview_text_input_edit_text
        imageView = view.custom_inputview_image_view

        attrs.let {
            context.theme.obtainStyledAttributes(
                it,
                R.styleable.InputView,
                defStyleAttr, 0).apply {

                try {
                    textView.textSize = getDimension(R.styleable.InputView_android_textSize, 16.0f)
                    textView.text = SpannableStringBuilder(getString(R.styleable.InputView_android_text) ?: "")
                    textInputLayout.hint = getText(R.styleable.InputView_android_hint)
                    if (getDrawable(R.styleable.InputView_android_src) == null) {
                        imageView.isVisible = false
                    } else {
                        imageView.setImageDrawable(getDrawable(R.styleable.InputView_android_src))
                        imageView.setColorFilter(getColorOrThrow(R.styleable.InputView_android_tint))
                    }
                    textView.maxLines = getInteger(R.styleable.InputView_android_maxLines, 1)
                    textView.minLines = getInteger(R.styleable.InputView_android_minLines, 0)
                    textView.setLines(getInteger(R.styleable.InputView_android_lines, 1))
                    textView.inputType = getInteger(R.styleable.InputView_android_inputType, EditorInfo.IME_NULL)
                    textView.setCompoundDrawablesWithIntrinsicBounds(
                        getDrawable(R.styleable.InputView_android_drawableStart),
                        getDrawable(R.styleable.InputView_android_drawableTop),
                        getDrawable(R.styleable.InputView_android_drawableEnd),
                        getDrawable(R.styleable.InputView_android_drawableBottom))
                } finally {
                    recycle()
                }
            }
        }
    }

    override fun onSaveInstanceState(): Parcelable {
        // 1
        val bundle = Bundle()
        // 2
        bundle.putString("text", textView.text.toString())
        // 3
        Log.d("InputView", "Saving state text: ${textView.text.toString()}")
        bundle.putParcelable("superState", super.onSaveInstanceState())
        return bundle
    }

    override fun onRestoreInstanceState(state: Parcelable) {
        // 4
        var viewState = state
        if (viewState is Bundle) {
            // 5
            Log.d("InputView", "Textview text: ${viewState.getString("text")}")

            textView.text = SpannableStringBuilder(viewState.getString("text"))
            // 6
            viewState = viewState.getParcelable("superState")
        }
        super.onRestoreInstanceState(viewState)
    }

}

我尝试覆盖onSaveIntanceState()和onRestoreInstanceState(),但它没有任何改变。

旋转前的屏幕截图:

enter image description here

旋转后的屏幕截图:

enter image description here

1 个答案:

答案 0 :(得分:0)

将此添加到我的自定义视图中,问题消失了:

class InputView(context: Context, attrs: AttributeSet?, @AttrRes defStyleAttr: Int) : ConstraintLayout(context, attrs, defStyleAttr) {

...
    @Suppress("UNCHECKED_CAST")
    public override fun onSaveInstanceState(): Parcelable? {
        val superState = super.onSaveInstanceState()
        val ss = SavedState(superState)
        ss.childrenStates = SparseArray()
        for (i in 0 until childCount) {
            getChildAt(i).saveHierarchyState(ss.childrenStates as SparseArray<Parcelable>)
        }
        return ss
    }

    @Suppress("UNCHECKED_CAST")
    public override fun onRestoreInstanceState(state: Parcelable) {
        val ss = state as SavedState
        super.onRestoreInstanceState(ss.superState)
        for (i in 0 until childCount) {
            getChildAt(i).restoreHierarchyState(ss.childrenStates as SparseArray<Parcelable>)
        }
    }

    override fun dispatchSaveInstanceState(container: SparseArray<Parcelable>) {
        dispatchFreezeSelfOnly(container)
    }

    override fun dispatchRestoreInstanceState(container: SparseArray<Parcelable>) {
        dispatchThawSelfOnly(container)
    }

    class SavedState(superState: Parcelable?) : BaseSavedState(superState) {
        var childrenStates: SparseArray<Any>? = null

        override fun writeToParcel(out: Parcel, flags: Int) {
            super.writeToParcel(out, flags)
            childrenStates?.let {
                out.writeSparseArray(it)
            }
        }
    }
}