android 统一空白页错误页,PageLayout状态页切换 加载中-空数据-错误页

3

实现

1.代码设计

首先我们定义PageLayout继承FrameLayout或者LinearLayou或者其他的布局都可以,然后我们需要提供切换四个布局的功能,当然如果支持自定义就更好了,还有状态布局里面的一些属性,还方便一键配置,所以最后采用了Builder模式来创建,使用方式就和Android里面的AlertDialog一样,通过Builder去构建一个PageLayout。

最后的样子是长这样的:

默认样式

PageLayout.Builder( this)

.initPage(ll_default)

.setOnRetryListener( object: PageLayout.OnRetryClickListener{

overridefunonRetry(){

loadData()

}

})

.create()

自定义样式

PageLayout.Builder( this)

.initPage(ll_demo)

.setLoading(R.layout.layout_loading_demo)

.setEmpty(R.layout.layout_empty_demo)

.setError(R.layout.layout_error_demo,R.id.tv_page_error_demo, object: PageLayout.OnRetryClickListener{

overridefunonRetry(){

loadData()

}

})

.setEmptyDrawable(R.drawable.pic_empty)

.setErrorDrawable(R.drawable.pic_error)

.create()

2.设置PageLayout

考虑好了代码设计方式之后,我们来具体实现功能,首先需要考虑上面的5,6点:

contentView怎么添加?

如果我想切换的跟布局不是个Activity或者Fragment怎么办?

1.Activity

如果我们要切换的跟布局是个Activity时,首先我们需要了解一下Android中的setContentView()方法,很熟悉,是我们新建完Activity后默认会在生命周期方法onCreate()中默认存在的,那么setContentView()做了些什么呢?我们先看一张图:

e671397d085c6f2d7c1ea6cd16d28bc8.png

一个Activity是通过ActivityThread创建出来的,创建完毕后,会将DecorView添加到Window中,同时会创建ViewRootImpl对象,并将ViewRootImpl对象和DecorView建立关联,setContentView()是通过getWindow()调用的,这里的window实际初始化的时候初始化为PhoneWindow,也就是说Activity会调用PhoneWindow的setContentView()将layout布局添加到DecorView上,而此时的DecorView就是那个最底层的View。然后通过LayoutInflater.infalte()方法加载布局生成View对象并通过addView()方法添加到Window上,(一层一层的叠加到Window上)所以,Activity其实不是显示视图,Window才是真正的显示视图。

再来看上面的那张图,可以说DecorView是一个界面的真正跟布局,TitleView我们可以通过设置theme样式显示隐藏的,状态布局切换时我们不考虑TitleView,我们只需要考虑ContentView,而ContentView也就是android.R.id.content,知道了这些我们来看看怎么获取将contenView交给PageLayout管理。

2.Fragment、View

如果我们要切换的跟布局是个Fragment、View时,我们只需要获取到它的parent

该功能是支持单独为某个布局设置状态改变的,比如很多同学提到的我一个listview的数据没有获取到,fun initPage(targetView: Any),这个targetView你只需要设置成你的listview或者包裹你listview的parent布局就OK了,具体原理可以看下面的代码解析啊,遍历获取索引,然后记录索引值....3.PageLayout设置跟布局

获取到了contentView跟布局后,我们要移除自己的显示内容的布局,并把这个布局交给PageLayout,下面看一下代码,注释的很详细了:

/**

* set target view for root

*/

funinitPage(targetView: Any): Builder {

varcontent: ViewGroup? = null

when(targetView) {

//如果是Activity,获取到android.R.content

isActivity -> {

mContext = targetView

content = (mContext asActivity).findViewById(android.R.id.content)

}

//如果是Fragment获取到parent

isFragment -> {

mContext = targetView.activity!!

content = (targetView.view)?.parent asViewGroup

}

//如果是View,也取到parent

isView -> {

mContext = targetView.context

try{

content = (targetView.parent) asViewGroup

} catch(e: TypeCastException) {

}

}

}

valchildCount = content?.childCount

varindex = 0

valoldContent: View

//如果是某个线性布局或者相对布局时,遍历它的孩子,找到对应的索引,记录下来

if(targetView isView) {

oldContent = targetView

childCount?.let {

for(i in0until childCount) {

if(content!!.getChildAt(i) === oldContent) {

index = i

break

}

}

}

} else{

//如果是Activity或者Fragment时,取到索引为第一个的View

oldContent = content!!.getChildAt( 0)

}

//给PageLayout设置contentView

mPageLayout.mContent = oldContent

mPageLayout.removeAllViews()

content?.removeView(oldContent)

//将本身content移除,并且把PageLayout添加到DecorView中去

vallp = oldContent.layoutParams

content?.addView(mPageLayout, index, lp)

mPageLayout.addView(oldContent)

//设置默认状态布局

initDefault()

returnthis

}

这样我们就解决了上面的5,6的问题。

4.其他

因为错误布局中一般都包括一个点击重试的功能,如果你需要自定义布局,你可以在配置PageLayout之前,设置好错误布局和点击事件,然后setError进去,同时也提供了一个默认方式的方法:

funsetError(errorView: Int, errorClickId: Int, onRetryClickListener: OnRetryClickListener)

考虑到此功能的APP统一性,所以并没有提供过多的自定义功能,如果你需要的话,你都可以提前设置好View,然后进行set

之前和同事讨论,xml形式和代码形式哪个更方便更灵活,这些都属于个人喜好吧,如果你更喜欢在xml里写的话,你可以进行改造,也挺简单,目前没提供xml方式,PageLayout的初衷就是模仿AlertDialog方式,随时随地使用状态布局切换

你也可以在BaseActivity和BaseFragment中进行PageLayout的初始化,Demo中未使用,自行解决;

效果图

3815ea790af54a789cd667126057586a.gif

代码已经上传到Github

https://github.com/Hankkin/PageLayoutDemo

Reading:一款不错的Material Desgin风格的Kotlin版本的开源

https://github.com/Hankkin/Reading

欢迎大家Follow、star、fork,谢谢 如果有不合适的地方,请提issues讨论指正返回搜狐,查看更多

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值