Skip to content

提供业务需求中常见状态切换 Widget 容器实现抽象。可用于需要 Loading/Empty/Error 等状态切换的 UI 业务。

Notifications You must be signed in to change notification settings

tiiime/StateLayout

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Sep 16, 2023
90d8f7b · Sep 16, 2023

History

5 Commits
Sep 16, 2023
Sep 16, 2023
Sep 16, 2023
Sep 16, 2023
Sep 16, 2023
Sep 16, 2023
Sep 16, 2023
Sep 16, 2023
Sep 16, 2023

Repository files navigation

StateLayout

提供业务需求中常见状态切换 Widget 容器实现抽象。可用于需要 Loading/Empty/Error 等状态切换的 UI 业务。

以一个常见 case 为例,进入页面,展示 loading 状态,数据加载失败后,展示异常 UI,并提供刷新 UI。用户点击刷新后,触发数据重新加载。

IState

提供 IState,将 UI 状态切换抽象为两个 enterexit 回调时机。
Loading/Error/Content 等状态实现自己的 State, 在自己的生命周期内设置 UI 状态(也可以设置点击事件等对外回调)。

interface IState<LIMIT> where LIMIT : IState<LIMIT> {
    fun enter(stateContainer: StateContainer<LIMIT>)
    fun exit(stateContainer: StateContainer<LIMIT>)
}

State 实现可以使用 stateContainer.getContainer() 获取 ViewGroup。
类似 VisibilityChangeState,去操作 ViewGroup 内容。

open class VisibilityChangeState<T>(@IdRes private val containerId: Int) :
    IState<T> where T : IState<T> {
    override fun enter(stateContainer: StateContainer<T>) {
        stateContainer.getContainer().findViewById<View>(containerId)?.visibility = View.VISIBLE
    }

    override fun exit(stateContainer: StateContainer<T>) {
        stateContainer.getContainer().findViewById<View>(containerId)?.visibility = View.GONE
    }
}

实现好的通用 IState 逻辑,可以方便的给其他 StateContainer 复用,参考 LoadingState 复用 VisibilityChangeState 的方式。

StateContainer

容器 Layout 需要实现 StateContainer,里面维护了一个 currentState,并提供 StateContainer#setState 方法供外部使用。
需要注意,实现 StateContainer<LimitState : IState<LimitState>> 需要指定 IState,限制自己 setState 方法接收的 IState 范围。避免用户传入预期外 State。

interface StateContainer<LimitState : IState<LimitState>> {

    fun setState(newState: LimitState) 
    
    ...
}

class EmptyLayout : FrameLayout, StateContainer<EmptyLayout.State> {
    ...
    
    // 默认实现
    // override fun setState(newState: EmptyLayout.State) {
    //     super.setState(newState)
    // }

    interface State : IState<State>
}

EmptyLayout

EmptyLayout.State 限制了 EmptyLayout#setState 参数范围,保证逻辑安全。
LoadingState 等 State 复用了 VisibilityChangeState 实现。

// 

class EmptyLayout : FrameLayout, StateContainer<EmptyLayout.State> {
    ...

    /**
    * EmptyLayout.State 首先限制了 EmptyLayout#setState 方法接收的参数类型
    * 所有加入 EmptyLayout 的 state 都要实现这个接口
    * 使用方在实现 State 时,就要考虑好如何使用 Layout 
    *
    * 查看实现,可以确认有多少使用 EmptyLayout 的状态
    */
    interface State : IState<State>

    /**
    * 展示 Loading 状态
    */
    object LoadingState : VisibilityChangeState<State>(R.id.loading), State

    /**
    * 展示空视图
    */
    object EmptyState : VisibilityChangeState<State>(R.id.empty_hint), State

    /**
    * 展示 Error,提供重试回调
    */
    class ErrorState(private val callback: Callback) :
        VisibilityChangeState<State>(R.id.error_retry), State {
        interface Callback {
            fun retryClick()
        }

        override fun enter(stateContainer: StateContainer<State>) {
            super.enter(stateContainer)
            stateContainer.getContainer().findViewById<View>(R.id.error_retry).setOnClickListener {
                callback.retryClick()
            }
        }
    }
}

实现 StateContainer 参考 EmptyLayout

使用 EmptyLayout 参考 MainActivity

About

提供业务需求中常见状态切换 Widget 容器实现抽象。可用于需要 Loading/Empty/Error 等状态切换的 UI 业务。

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages