Android搭建应用框架系列之StatusView

前言

前篇文章把每个页面的统一加载框写了下。在应用中,除了加载框,还有页面请求数据为空的时候,或者请求网络错误的时候需要统一处理,也就是根据不同的状态显示不同的页面StatusView

IStatusView

这里有四种显示状态,显示应用发生未知错误页面,显示网络错误页面,显示空页面,以及显示正常页面,所以定义的接口如下

interface IStateView {
    fun showErrorView()
    fun showNetErrorView()
    fun showEmptyView()
    fun dismissStatusView()
}

StatusViewController

接下来就是写一个帮助类实现上面接口,然后进行相应的切换操作

class StatusViewController(private var mContext: Context, private var mBindView:View) : IStateView {
    private var mParentView:ViewGroup? = null
    private var mCurrentIndex = 0
    private var mEmptyView: View? = null
    private var mErrorView:View? = null
    private var mNetErrorView:View? = null
    private var mBindViewParams:ViewGroup.LayoutParams? = null

    private var netErrorLayoutResId:Int = 0
    private var errorLayoutResId:Int = 0
    private var emptyLayoutResId:Int = 0
    private var mEmptyStatus:StatusInfo = StatusInfo(R.drawable.icon_empty,mContext.getString(R.string.LoadingController_empty),mContext.getString(R.string.LoadingController_empty_retry))
    private var mErrorStatus:StatusInfo = StatusInfo(R.drawable.icon_error,mContext.getString(R.string.LoadingController_error),mContext.getString(R.string.LoadingController_error_retry))
    private var mNetErrorStatus:StatusInfo = StatusInfo(R.drawable.icon_net_error,mContext.getString(R.string.LoadingController_net_error),mContext.getString(R.string.LoadingController_net_error_retry))
    private var mEmptyBtnRetryListener:BtnRetryListener? = null
    private var mNetErrorBtnRetryListener:BtnRetryListener? = null
    private var mErrorBtnRetryListener:BtnRetryListener? = null
    init {
        mBindViewParams = mBindView.layoutParams
        mParentView = if(mBindView.parent != null)
            mBindView.parent as ViewGroup
        else
            mBindView.rootView.find(android.R.id.content)
        val childCount = mParentView!!.childCount
        (0 until childCount)
                .filter { mParentView!!.getChildAt(it) == mBindView }
                .forEach { mCurrentIndex = it }
    }

    override fun showErrorView() {
        if(mErrorView!=null){
            showView(mErrorView!!)
            return
        }
        if(errorLayoutResId>0){
            mErrorView = mContext.layoutInflater.inflate(errorLayoutResId,mParentView,false)
        }else{
            mErrorView = mContext.layoutInflater.inflate(R.layout.error,mParentView,false)
            updateDefaultView(mErrorView!!,mErrorStatus,mErrorBtnRetryListener)
        }
        showView(mErrorView!!)
    }
    override fun showNetErrorView() {
        if(mNetErrorView!=null){
            showView(mNetErrorView!!)
            return
        }
        if(errorLayoutResId>0){
            mNetErrorView = mContext.layoutInflater.inflate(netErrorLayoutResId,mParentView,false)
        }else{
            mNetErrorView = mContext.layoutInflater.inflate(R.layout.error,mParentView,false)
            updateDefaultView(mNetErrorView!!,mNetErrorStatus,mNetErrorBtnRetryListener)
        }
        showView(mNetErrorView!!)
    }

    override fun showEmptyView() {
        if(mEmptyView!=null){
            showView(mEmptyView!!)
            return
        }
        if(emptyLayoutResId>0){
            mEmptyView = mContext.layoutInflater.inflate(emptyLayoutResId,mParentView,false)
        }else{
            mEmptyView = mContext.layoutInflater.inflate(R.layout.error,mParentView,false)
            updateDefaultView(mEmptyView!!,mEmptyStatus,mEmptyBtnRetryListener)
        }
        showView(mEmptyView!!)
    }

    override fun dismissStatusView() {
        showView(mBindView)
    }
    private fun showView(statusView:View){
        if(mParentView!!.getChildAt(mCurrentIndex) != statusView){
            statusView.parent?:(statusView.parent as? ViewGroup)?.removeView(statusView)
            mParentView!!.removeViewAt(mCurrentIndex)
            mParentView!!.addView(statusView,mCurrentIndex,mBindViewParams)
        }
    }
    private fun updateDefaultView(updateView:View,statusInfo:StatusInfo,listener:BtnRetryListener?=null){
        val errorView = updateView.find(R.id.iv_error)
        val msgView = updateView.find(R.id.tv_errorMessage)
        val btnRetryView = updateView.find(R.id.btn_retry)
        if(statusInfo.icon>0){
            errorView.show()
            errorView.imageResource = statusInfo.icon
        }else errorView.hide()
        if(!statusInfo.msg.isNullOrEmpty()){
            msgView.show()
            msgView.text = statusInfo.msg
        }else msgView.hide()
        if(!statusInfo.btnText.isNullOrEmpty()){
            btnRetryView.show()
            btnRetryView.text = statusInfo.btnText
            btnRetryView.onClick {
                listener?.onRetryClick(btnRetryView)
            }
        }else btnRetryView.hide()
    }

    fun setErrorLayoutResId(resId: Int):StatusViewController{
        this.errorLayoutResId = resId
        return this
    }
    fun setNetErrorLayoutResId(resId: Int):StatusViewController{
        this.netErrorLayoutResId = resId
        return this
    }
    fun setEmptyLayoutResId(resId: Int):StatusViewController{
        this.emptyLayoutResId = resId
        return this
    }
    fun setEmptyStatusInfo(statusInfo:StatusInfo):StatusViewController{
        this.mEmptyStatus = statusInfo
        return this
    }
    fun setErrorStatusInfo(statusInfo:StatusInfo):StatusViewController{
        this.mErrorStatus = statusInfo
        return this
    }
    fun setNetErrorStatusInfo(statusInfo:StatusInfo):StatusViewController{
        this.mNetErrorStatus = statusInfo
        return this
    }
    fun setEmptyBtnClickListener(listener:BtnRetryListener):StatusViewController{
        this.mEmptyBtnRetryListener = listener
        return this
    }
    fun setErrorBtnClickListener(listener:BtnRetryListener):StatusViewController{
        this.mErrorBtnRetryListener = listener
        return this
    }
    fun setNetErrorBtnClickListener(listener:BtnRetryListener):StatusViewController{
        this.mNetErrorBtnRetryListener = listener
        return this
    }
    interface BtnRetryListener{
        fun onRetryClick(view:View)
    }
    class StatusInfo(val icon:Int,val msg:CharSequence?,val btnText:CharSequence?)
}

传入两个参数,一个是Context,另外一个是mBindView,这个参数意思是需要显示在哪个控件上面,比如RecyclerView。可以自定义对应显示的布局,也可以通过StatusInfo是传入信息,然后显示默认对应的布局

使用

最简单的使用如下
先获取StatusViewController实例

val mStatusView by lazy { StatusViewController(context,mRecyclerView)}

或者自定义对应的布局


Android搭建应用框架系列之StatusView_第1张图片
image.png

或者自定义点击事件


Android搭建应用框架系列之StatusView_第2张图片
image.png

显示网络错误

mStatusView.showNetErrorView()

显示未知错误页面

mStatusView.showErrorView()

显示空页面

mStatusView.showEmptyView()

最后显示如下

网络错误

Android搭建应用框架系列之StatusView_第3张图片
网络错误.png

未知错误

Android搭建应用框架系列之StatusView_第4张图片
未知错误.png

空页面

Android搭建应用框架系列之StatusView_第5张图片
空页面.png

你可能感兴趣的:(Android搭建应用框架系列之StatusView)