Read my medium blog [en] Read my medium blog [th]
- fix bug
- kotlin CustomView example :)
If you want to test savedstate Enable Developer mode
Go to Developer Options -> and check ** Don't Keep Activities **
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)
}
}
}
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)
}
}
}
}
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)
}
}
}
}
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