前言
前篇文章把每个页面的统一加载框写了下。在应用中,除了加载框,还有页面请求数据为空的时候,或者请求网络错误的时候需要统一处理,也就是根据不同的状态显示不同的页面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<ImageView>(R.id.iv_error)
val msgView = updateView.find<TextView>(R.id.tv_errorMessage)
val btnRetryView = updateView.find<TextView>(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)}
或者自定义对应的布局
image.png
或者自定义点击事件
image.png
显示网络错误
mStatusView.showNetErrorView()
显示未知错误页面
mStatusView.showErrorView()
显示空页面
mStatusView.showEmptyView()
最后显示如下
网络错误
网络错误.png未知错误
未知错误.png空页面
空页面.png
网友评论