一款优雅的,无需改动布局的界面状态切换方案

前言

项目中的页面,只要不是纯静态数据的页面,都有进行状态展现和切换的需求。好比一个列表页面正在请求数据,须要展现Loading的效果;若是请求失败还须要展现失败的界面;若是数据未空,还须要展现空数据的页面。php

这种状态页面的需求会涵盖项目中大部分的页面,若是实现的不优雅,写起来会很是的棘手。android

硬编码方案

我最先见过的一种是硬编码方案,就是将全部的状态布局代码都写在每一个页面中,默认都gone掉,就算你独立抽取一个布局,经过include引入也是属于这种方案。而后在代码中提供几个showLoading(), showEmpty(),showError()之类的方法来控制布局的隐藏和可见。git

布局的代码大概相似于这样:github

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity">

    <!--界面原有布局 -->
    <FrameLayout/>

    <!--请求Loading布局 -->
    <FrameLayout android:visibility="gone"/>

    <!--请求失败布局 -->
    <FrameLayout android:visibility="gone"/>
    
    <!--请求数据为空的布局 -->
    <FrameLayout android:visibility="gone"/>
</LinearLayout>
复制代码

这种方案直接侵入了每个界面的布局,下降了布局的可读性,不可取。app

上面这种方案能够经过重构减小代码,好比在基类中抽取出showLoading(), showEmpty(),showError()之类的方法,子类调用便可。布局

细节处的状态切换

上面的硬编码方案只适用于总体界面须要状态切换的场景,但有时候咱们须要对按钮进行状态切换,好比一个登陆按钮,收藏按钮,关注按钮。这是基于用户体验的考虑,用户须要知道软件的运行状态,软件须要在逻辑上给用户交互反馈,某种意义上和Material Design的触摸反馈理念是一致的。this

当用户点击关注时,按钮应该有关注中的状态效果,关注中的状态下不可进行交互。效果以下:编码

若是是这种需求的话,那上面的硬编码方案就很难写了。固然若是你愿意的话,你能够给全部须要状态切换的按钮外面包裹一些布局,也不是不能作。spa

我所指望的效果是,能够动态给咱们的界面或者某个具体的按钮加上状态切换的功能,而写布局的时候咱们不须要编写一行状态相关的东西。code

实现

基于个人指望,我实现了一个StateLayout,它是一个自定义的布局,代码并不复杂。它能作到的效果是这样:

我不打算贴代码了,由于没有什么难的东西。它用起来很是简单,对现有的布局零侵入,经过动态的给目标View包裹一些状态布局来实现。

对Activity/Fragment使用:

val stateLayout = StateLayout(this)
            .wrap(this)
            .showLoading()
复制代码

对指定View使用:

val layout2 = StateLayout(this)
            .wrap(view)
            .showLoading()
复制代码

默认状况下是显示内容布局,改变状态的方法:

stateLayout.showLoading() //default state
stateLayout.showContent()
stateLayout.showError()
stateLayout.showEmpty()
复制代码

你还能够自定义每种状态对应的布局,毕竟默认的状态布局是有点丑的:

StateLayout(this)
    .config(loadingLayoutId = R.layout.custom_loading, //自定义加载中布局
            errorLayoutId = R.layout.custom_error, //自定义加载失败布局
            emptyLayoutId = R.layout.custom_empty, //自定义数据位为空的布局
            useContentBgWhenLoading = true, //加载过程当中是否使用内容的背景
            enableLoadingShadow = true, //加载过程当中是否启用半透明阴影盖在内容上面
            retryAction = { //点击errorView的回调
                Toast.makeText(this, "点击了重试", Toast.LENGTH_SHORT).show()
            })
    .wrap(view)
    .showLoading()
复制代码

类库的地址在这里:github.com/li-xiaojun/…

最后

我致力于构建现代化的Android开发技术栈,用兼顾优雅和效率的代码,来开发高质量的Android应用。

相关文章
相关标签/搜索