Skip to content

nontravis/view-group-savedstate-example

Repository files navigation

ViewGroup savedstate EXAMPLE

Build Status

Read my medium blog [en] Read my medium blog [th]

[UPDATE]

  • fix bug
  • kotlin CustomView example :)

If you want to test savedstate Enable Developer mode

Go to Developer Options -> and check ** Don't Keep Activities **

View savedstate ViewGroup savedstate


BaseViewGroup.java

BaseViewGroup.kt

abstract class BaseViewGroup : FrameLayout {

    @JvmOverloads
    constructor(
            context: Context,
            attrs: AttributeSet? = null,
            defStyleAttr: Int = 0)
            : super(context, attrs, defStyleAttr) {
        setup(attrs, defStyleAttr, 0)
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int)
            : super(context, attrs, defStyleAttr, defStyleRes) {
        setup(attrs, defStyleAttr, defStyleRes)
    }


    private fun setup(attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) {
        if (attrs != null) setupStyleables(attrs, defStyleAttr, defStyleRes)
        inflateLayout()
        bindView()
        setupInstance()
        setupView()
    }

    /**
     * Custom handle SavedState child to "fix restore state in same resource id"
     * when use ViewGroup more than one.
     *
     *
     * the method must be call in subclass.
     */
    protected fun onSaveChildInstanceState(ss: ChildSavedState): Parcelable {
        ss.childrenStates = SparseArray()
        for (i in 0 until childCount) {
            val id = getChildAt(i).id
            if (id != 0) {
                val childrenState = SparseArray<Parcelable>()
                getChildAt(i).saveHierarchyState(childrenState)
                ss.childrenStates?.put(id, childrenState)
            }

        }
        return ss
    }

    override
    fun onRestoreInstanceState(state: Parcelable) {
        if (state !is ChildSavedState) {
            super.onRestoreInstanceState(state)
            return
        }
        super.onRestoreInstanceState(state.superState)
        onRestoreChildInstanceState(state)
    }



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

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

    private fun inflateLayout() {
        View.inflate(context, getLayoutRes(), this)
    }

    @Suppress("UNCHECKED_CAST")
    private fun onRestoreChildInstanceState(ss: ChildSavedState) {
        for (i in 0 until childCount) {
            val id = getChildAt(i).id
            if (id != 0) {
                if (ss.childrenStates?.get(id) != null) {
                    val childrenState = ss.childrenStates?.get(id) as SparseArray<Parcelable?>
                    getChildAt(i).restoreHierarchyState(childrenState)
                }
            }
        }
    }


    protected abstract fun getLayoutRes(): Int

    protected abstract fun setupView()

    protected open fun setupStyleables(attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) {}

    protected open fun bindView() {}

    protected open fun setupInstance() {}



    abstract class ChildSavedState : View.BaseSavedState {
        internal var childrenStates: SparseArray<Any>? = null

        constructor(superState: Parcelable) : super(superState)

        constructor(`in`: Parcel, classLoader: ClassLoader) : super(`in`) {
            childrenStates = `in`.readSparseArray(classLoader)
        }

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



}

SwitchViewGroup.java

SwitchViewGroup.kt

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

    private var editText: EditText? = null
    private var toggle: CustomSwitch? = null
    private val checkChangeListener: UserAdapter.OnCheckedChangeListener? = null
    private val textChangedListener: UserAdapter.OnTextChangeListener? = null


    override
    fun getLayoutRes(): Int = R.layout.switch_custom_view_group

    override
    fun setupStyleables(attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) {
    }

    override
    fun bindView() {
        editText = findViewById(R.id.editText)
        toggle = findViewById(R.id.toggle)
    }

    override
    fun setupView() {
    }

    fun setTextToEditText(message: String?) {
        editText?.setText(message)
    }

    fun setTextChangedListener(listener: TextWatcher) {
        editText?.addTextChangedListener(listener)
    }

    fun setOnCheckChangeListener(listener: CompoundButton.OnCheckedChangeListener) {
        toggle?.setOnCheckedChangeListener(listener)
    }

    fun setCheck(check: Boolean) {
        toggle?.isChecked = check
    }

    public override fun onSaveInstanceState(): Parcelable? {
        val superState = super.onSaveInstanceState()
        // Must call
        val ss = onSaveChildInstanceState(SavedState(superState)) as SavedState
        // save data here
        return ss
    }


    public override fun onRestoreInstanceState(state: Parcelable) {
        if (state !is SavedState) {
            super.onRestoreInstanceState(state)
            return
        }
        super.onRestoreInstanceState(state)
        // restore data here
    }


    internal class SavedState : BaseViewGroup.ChildSavedState {

        constructor(superState: Parcelable) : super(superState) {}

        constructor(`in`: Parcel, classLoader: ClassLoader) : super(`in`, classLoader) {
            // save data here
        }

        override
        fun writeToParcel(out: Parcel, flags: Int) {
            super.writeToParcel(out, flags)
            // restore data here
        }

        companion object {
            @JvmField
            val CREATOR: Parcelable.ClassLoaderCreator<SavedState> = object : Parcelable.ClassLoaderCreator<SavedState> {
                override
                fun createFromParcel(source: Parcel, loader: ClassLoader): SavedState = SavedState(source, loader)

                override
                fun createFromParcel(`in`: Parcel): SavedState? = null

                override
                fun newArray(size: Int): Array<SavedState?> = arrayOfNulls(size)
            }
        }
    }

}

CustomSwitch.java

CustomSwitch.kt

class CustomSwitch
    : Switch {

    private var customState: Int = 0

    constructor(context: Context) : super(context) {}

    constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {}

    constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {}

    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) {
    }

    fun setCustomState(customState: Int) {
        this.customState = customState
    }

    override
    fun onSaveInstanceState(): Parcelable? {
        val superState = super.onSaveInstanceState()
        val ss = SavedState(superState)
        ss.state = customState
        return ss
    }


    override
    fun onRestoreInstanceState(state: Parcelable) {
        if (state !is SavedState) {
            super.onRestoreInstanceState(state)
            return
        }
        super.onRestoreInstanceState(state.superState)
        setCustomState(state.state)
    }


    internal class SavedState : ViewSavedState {
        var state: Int = 0

        constructor(superState: Parcelable) : super(superState)

        constructor(`in`: Parcel) : super(`in`) {
            state = `in`.readInt()
        }

        override
        fun writeToParcel(out: Parcel, flags: Int) = with(out) {
            super.writeToParcel(out, flags)
            out.writeInt(state)
        }

        companion object {
            @JvmField
            val CREATOR: Parcelable.Creator<SavedState> = object : Parcelable.Creator<SavedState> {

                override
                fun createFromParcel(`in`: Parcel): SavedState? = SavedState(`in`)

                override
                fun newArray(size: Int): Array<SavedState?> = arrayOfNulls(size)
            }
        }
    }
}

Developed By Thai android developer.

TheKhaeng

Follow facebook.com/thekhaeng.io on Facebook page. or @nonthawit at my Medium blog. :)

For contact, shoot me an email at nonthawit.thekhaeng@gmail.com

Releases

No releases published

Packages

No packages published