preface

In Android page development, we often encounter the situation of multi-state layout switch, often loading, loading failure, loading empty, loading success and other states. For example, there are a lot of examples of how compose is packaged using XML. In this project, you will learn how to compose a simple and easy-to-use MutiStateLayout

features

  1. Provides global default layout, such as default loading, default success failure
  2. Support custom default style copywriting, images
  3. Fully custom styles are supported if you do not want to use the layout provided by the framework by default
  4. Supports custom handling of click retry events
  5. Fully data-driven

use

Access to the

Download project engineering, will ComposeMultiStateLayout kt copy to the project

Simple to use

Defining global styles

There are no default styles specified in the framework, so you need to customize your own default page styles for loading, failure, etc

At the same time, you need to customize the data structure type to customize the style to facilitate data driven

sealed class PageState(
    var tipTex: String,
    var tipImg: Int
) {
    object Loading : PageState(
        tipTex = "Loading",
        tipImg = R.mipmap.ic_launcher
    )

    object Empty : PageState(
        tipTex = "Data is empty",
        tipImg = R.mipmap.ic_launcher
    )

    object Error : PageState(
        tipTex = "Data error",
        tipImg = R.mipmap.ic_launcher
    )

    object Custom : PageState("".0)
    object Content : PageState("".0)}data class LayoutData(val pageStateData: PageState, val reload: () -> Unit = {})

@Composable
fun ComposeMultiStateStateLayout(
    modifier: Modifier = Modifier,
    pageState: PageState,
    onReLoad: () -> Unit = { },
    loading: @Composable (LayoutData) - >Unit = {},
    empty: @Composable (LayoutData) - >Unit = {},
    error: @Composable (LayoutData) - >Unit = {},
    custom: @Composable (LayoutData) - >Unit = {},
    content: @Composable() - >Unit= {}) {

    val stateLayoutData = LayoutData(pageState, onReLoad)
    Box(modifier = modifier) {
        when(pageState) { PageState.Loading -> loading(stateLayoutData) PageState.Empty -> empty(stateLayoutData) PageState.Error ->  error(stateLayoutData) PageState.Custom -> custom(stateLayoutData) PageState.Content -> content() } } }Copy the code

As shown above, the main things we need to do during initialization are the following

  1. Custom default load, load failure, load as empty style
  2. The customPageStateThat is, to pass the default style of the data structure, such as copy, image, etc., so that it can be changed later when neededPageStateCan be

Direct use of

If we use the default style, we can use it as follows

   var pageState: PageState by remember {
        mutableStateOf(PageState.Content)
    }
    Column(modifier = Modifier.fillMaxSize()) {
       
        DefaultMultiStateLayout(modifier = Modifier.fillMaxSize(),
            pageState = pageState,
            onReLoad = {
                pageState = PageState.Loading
            },
            content = {
                Box(modifier = Modifier.fillMaxSize()) {

                    Text(
                        text = Content page,
                        modifier = Modifier.align(Alignment.Center),
                        style = MaterialTheme.typography.h3
                    )
                }
            })
    }
Copy the code

As shown above, you can use it directly. If you need to change the status, modify pageStateData

Switch layout state and custom copywriting

If we need to switch the layout state and custom copy or image and other details, you can simply modify the pageState, do not set the default copy, image


    var pageState: PageState by remember {
        mutableStateOf(PageState.Content)
    }
   ButtonSimple(onClick = {
                pageState = PageState.Error.apply {
                    tipTex = "Oops, that's a mistake."
                    tipImg = R.mipmap.ic_launcher
                }
            }, "Error")

Copy the code

Custom layout

Sometimes the page loads in a different style than the global one, which requires a custom layout style

       DefaultMultiStateLayout(modifier = Modifier.fillMaxSize(),
            pageState = pageState,
            onReLoad = {
                pageState = PageState.Loading
            },
            content = {
                Box(modifier = Modifier.fillMaxSize()) {

                    Text(
                        text = Content page,
                        modifier = Modifier.align(Alignment.Center),
                        style = MaterialTheme.typography.h3
                    )
                }
            }, loading = {
                // Write loading layout
            }, error = {
                // Write the error layout
            }, empty = {
                / / the empty layout

            }, custom = {
                Box(modifier = Modifier.fillMaxSize()) {
                    Text(
                        text = "Customize the page (if prompted to login)",
                        modifier = Modifier.align(Alignment.Center),
                        style = MaterialTheme.typography.h3
                    )
                }
            })
Copy the code

Reload in custom layout

error = {
                Box(modifier = Modifier.fillMaxSize()) {
                    Text(
                        text = "Reload",
                        modifier = Modifier
                            .align(Alignment.Center)
                            .clickable {
                                it.reload.invoke()
                            },
                        style = MaterialTheme.typography.h3
                    )
                }
            }
            
Copy the code

The code is very simple and familiar with the Scaffold scaffolding principle. We can quickly define a page with multi-state controls