Funinitpage (targetView: Any), this targetView can be set to the parent layout of your listView or the parent layout that surrounds your ListView

Project we often used to load data, after loading data display content, if there is no data display a blank page, this is if the network error display a network error page, a custom PageLayout.

DownLoad

fir.im/pagelayout

The introduction

Often use a blank page in the Android and network error page is used to improve the user experience, give users a better senses, if access to data is empty, then the data will show a blank page, if in the process of getting data network mistake, will show abnormal a web page, like a east more fire recently, see below. Online and also some of the open source components, most of them are custom inherit a layout in XML makes it as with the layout, then add your own content layout, the effect also is pretty good, but people always feel a bit of trouble, not so flexible, n multiple XML to define layout, written, and so have the protagonist of today.

thinking

The idea is exactly the same as above, but in a different way, we manually fetch the contentView, remove it from the DecorView, and hand it over to the PageLayout fetch management. At the time, we didn’t want to write the layout of page switching in every XML, so could we use Java code to control it? Take a look at it with the following questions.

  • 1. Customize a layout as a follow layout
  • 2. Provides the functions of switching loading, empty page, errror page, and content page
  • 3. How to let it take the management of the above four pages?
  • 4. How to add contentView?
  • 5. What if the layout I want to switch to is not an Activity or Fragment?
  • 6. Since the function of switching page state is generally unified in one APP, can it be configured with one button?

implementation

1. Code design

First we define PageLayout inherit FrameLayout or LinearLayou or any other layout. Then we need to provide the ability to switch between the four layouts. Of course, it would be better if we support customization. Therefore, the Builder mode is finally adopted to create, using the same way as the AlertDialog in Android, through Builder to build a PageLayout. The final look looks like this:

The default styles

PageLayout.Builder(this)
                .initPage(ll_default)
                .setOnRetryListener(object : PageLayout.OnRetryClickListener{
                    override fun onRetry() {
                        loadData()
                    }

                })
                .create()
Copy the code

Custom styles

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{
                    override fun onRetry() {
                        loadData()
                    }
                })
                .setEmptyDrawable(R.drawable.pic_empty)
                .setErrorDrawable(R.drawable.pic_error)
                .create()
Copy the code

2. Set the PageLayout

Now that we have the code design in mind, let’s start with 5 and 6 points above:

How do I add a contentView?

What if the layout I want to switch to is not an Activity or Fragment?

1.Activity

If we want to switch the layout of an Activity, we first need to look at the setContentView() method in Android. It’s the familiar one that exists by default in the lifecycle method onCreate() when we create a new Activity. So what does setContentView() do? Let’s start with a picture:

An Activity is created using an ActivityThread. Once created, the DecorView is added to the Window, the ViewRootImpl object is created, and the ViewRootImpl object is associated with the DecorView. SetContentView () is called by getWindow(), where window is actually initialized as PhoneWindow, That is, the Activity calls the PhoneWindow setContentView() to add a layout to the DecorView, which is the lowest level of the View. The layout is then loaded with layoutinfler.infalte () to generate a View object and added to the Window by the addView() method, so the Activity is not actually a display View; the Window is actually a display View.

DecorView is the actual layout of an interface. TitleView we can show hidden TitleView by setting the theme style. When we switch state layouts we don’t think about the TitleView, we just think about the ContentView, And ContentView, which is Android.R.D.C. Tent, now that we know that, let’s see how we can get contenView and give it to PageLayout to manage.

2. The fragments, and the View

If the layout we want to switch is a Fragment or View, we just need to get its parent

Funinitpage (targetView: Any), this targetView can be set to the parent layout of your listView or the parent layout that surrounds your ListView

3.PageLayout setting and layout

Once we’ve got the contentView and layout, we need to remove our own layout for displaying content and pass it to PageLayout. Let’s take a look at the code

/ * * *set target view forroot */ fun initPage(targetView: Any): Builder { var content: ViewGroup? = null when (targetView) {is Activity -> { Get Android.r.tent mContext = targetView Content = (mContext as Activity).findViewById(Android.r.D.C. Tent)} is Fragment -> {parent mContext = targetView.activity!! content = (targetView.view)? .parent as ViewGroup} is View -> { Parent mContext = targetView.context try {content = (targetview.parent) as ViewGroup} catch (e: TypeCastException) { } } } val childCount = content? .childCount var index = 0 val oldContent: Viewif(targetView is View) {oldContent = targetView childCount? (targetView is View) {oldContent = targetView childCount? .let {for (i in 0 until childCount) {
                        if(content!! .getChildAt(i) === oldContent) { index = ibreak}}}}else{// If it is an Activity or Fragment, fetch the View oldContent = content!! GetChildAt (0)} mPageLayout. MContent = oldContent / / to PageLayout set contentView mPageLayout. RemoveAllViews () the content? .removeView(oldContent) // Remove the original content and add PageLayout to the DecorView. Val lp = oldContent.layoutParams Content? .addView(mPageLayout, index, lp) mpagelayout.addView (oldContent) initDefault() // Sets the default state layoutreturn this
        }
Copy the code

So we solved the 5,6 problem up here.

4. Other

  • Since error layouts usually include a retry click function, if you need to customize the layout, you can setError layouts and click events before configuring PageLayout, then setError goes in, and also provides a default method
fun setError(errorView: Int, errorClickId: Int, onRetryClickListener: OnRetryClickListener)
Copy the code
  • Considering the APP unity of this function, there is not too much custom function provided. If you need it, you can set the View in advance and then set it
  • If you prefer to write in XML, you can change it. It is quite simple. XML is not provided at present
  • You can also initialize PageLayout in BaseActivity and BaseFragment. This is not used in the Demo

rendering

The code has been uploaded to the Githubgithub.com/Hankkin/Pag…

Reading: A good Material Desgin style Kotlin version of open source APP github.com/Hankkin/Rea…

Welcome to Follow, star, fork, thank you if there is any inappropriate place, please mention issues discussion and correct