Android StateLayout状态页

news2024/11/25 12:48:49

文章目录

  • Android StateLayout状态页
    • 概述
    • 源码
    • 使用
    • 源码下载

Android StateLayout状态页

概述

StateLayout(状态页)包含:加载中页面,错误页面,空页面,内含状态默认页面,支持自定义页面。

在这里插入图片描述

源码

全局配置:

package com.example.tools.state_layout.widgets

import android.view.View
import androidx.annotation.LayoutRes

/**
 * StateLayout全局配置
 */
object StateConfig {

    @LayoutRes
    @JvmStatic
    var emptyLayoutRes = View.NO_ID

    @LayoutRes
    @JvmStatic
    var errorLayoutRes = View.NO_ID

    @LayoutRes
    @JvmStatic
    var loadingLayoutRes = View.NO_ID

    @LayoutRes
    @JvmStatic
    var retryIds: IntArray? = null

    private var mOnStateChangeListener: OnStateChangeListener? = null

    fun setOnStateChangeListener(listener: OnStateChangeListener) {
        mOnStateChangeListener = listener
    }

    fun getOnStateChangeListener(): OnStateChangeListener? {
        return mOnStateChangeListener
    }
}

状态监听:

interface OnStateChangeListener {
    fun showState(status: Int)
}

属性:

<declare-styleable name="StateLayout">
    <attr name="empty_layout" format="reference" />
    <attr name="loading_layout" format="reference" />
    <attr name="error_layout" format="reference" />
</declare-styleable>

代码:

class StateLayout @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : FrameLayout(context, attrs, defStyleAttr) {

    companion object {
        const val STATE_LOADING = 0xA001
        const val STATE_EMPTY = 0xA002
        const val STATE_ERROR = 0xA003
        const val STATE_CONTENT = 0xA004
    }

    // empty布局资源
    @LayoutRes
    private var emptyLayoutRes = View.NO_ID
        get() = if (field == View.NO_ID) StateConfig.emptyLayoutRes else field

    // loading布局资源
    @LayoutRes
    private var loadingLayoutRes = View.NO_ID
        get() = if (field == View.NO_ID) StateConfig.loadingLayoutRes else field

    // error布局资源
    @LayoutRes
    private var errorLayoutRes = View.NO_ID
        get() = if (field == View.NO_ID) StateConfig.errorLayoutRes else field

    // 保存状态
    private val stateInfoMap = ArrayMap<Int, View>()

    // 当前状态
    private var currentState = STATE_CONTENT

    // 需要设置点击事件的id
    private var retryIds: IntArray? = null
        get() = field ?: StateConfig.retryIds

    private var mOnStateChangeListener: OnStateChangeListener? = null
        get() = field ?: StateConfig.getOnStateChangeListener()

    init {
        val a: TypedArray = context.obtainStyledAttributes(attrs, R.styleable.StateLayout)
        emptyLayoutRes = a.getResourceId(R.styleable.StateLayout_empty_layout, View.NO_ID)
        loadingLayoutRes = a.getResourceId(R.styleable.StateLayout_loading_layout, View.NO_ID)
        errorLayoutRes = a.getResourceId(R.styleable.StateLayout_error_layout, View.NO_ID)
        a.recycle()
    }

    override fun onFinishInflate() {
        super.onFinishInflate()
        if (childCount != 1) {
            throw IllegalStateException("StateLayout必须只能有一个子View")
        }
        if (stateInfoMap.size == 0) {
            val view = getChildAt(0)
            setContentView(view)
        }
    }

    /**
     * 设置内容布局
     */
    private fun setContentView(contentView: View) {
        stateInfoMap[STATE_CONTENT] = contentView
    }

    /**
     * 设置点击事件
     */
    fun setRetryIds(@IdRes vararg ids: Int) {
        retryIds = ids
    }

    /**
     * 设置状态变化监听
     */
    fun setOnStateChangeListener(listener: OnStateChangeListener) {
        mOnStateChangeListener = listener
    }

    /**
     * 显示内容布局
     */
    fun showContent() {
        showState(STATE_CONTENT)
    }

    /**
     * 显示加载布局
     */
    fun showLoading() {
        showState(STATE_LOADING)
    }

    /**
     * 显示失败布局
     */
    fun showError() {
        showState(STATE_ERROR)
    }

    /**
     * 显示空布局
     */
    fun showEmpty() {
        showState(STATE_EMPTY)
    }

    /**
     * 显示视图
     */
    private fun showState(status: Int) {
        if (currentState == status) {
            return
        }
        val stateView = getStateView(status)
        for (i in stateInfoMap) {
            if (i.key != status) {
                val view = i.value
                hideStateView(view)
            }
        }
        showStateView(this, stateView, status)
        mOnStateChangeListener?.showState(status)
        currentState = status
    }

    /**
     * 获取状态视图
     */
    private fun getStateView(status: Int): View {
        val view = stateInfoMap[status]
        if (view != null) {
            return view
        } else {
            val layoutRes = when (status) {
                STATE_EMPTY -> emptyLayoutRes
                STATE_ERROR -> errorLayoutRes
                STATE_LOADING -> loadingLayoutRes
                STATE_CONTENT -> View.NO_ID
                else -> View.NO_ID
            }
            if (layoutRes == View.NO_ID) {
                when (status) {
                    STATE_ERROR -> throw Resources.NotFoundException("请设置errorLayout")
                    STATE_EMPTY -> throw Resources.NotFoundException("请设置emptyLayout")
                    STATE_LOADING -> throw Resources.NotFoundException("请设置loadingLayout")
                    STATE_CONTENT -> throw Resources.NotFoundException("请设置contentView")
                }
            }
            val view = LayoutInflater.from(context).inflate(layoutRes, this, false)
            stateInfoMap[status] = view
            return view
        }
    }

    /**
     * 隐藏视图
     */
    private fun hideStateView(view: View) {
        view.visibility = View.GONE
    }

    /**
     * 显示视图
     */
    private fun showStateView(container: StateLayout, view: View, status: Int) {
        if (container.indexOfChild(view) != -1) {
            view.visibility = View.VISIBLE
        } else {
            if (status == STATE_EMPTY || status == STATE_ERROR) {
                if (retryIds != null) {
                    for (id in retryIds!!) {
                        view.findViewById<View>(id).setOnClickListener {
                            showLoading()
                        }
                    }
                }
            }
            container.addView(view)
        }
    }
}

使用

使用全局配置:

<com.example.tools.state_layout.widgets.StateLayout
    android:id="@+id/state_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:text="加载成功" />
</com.example.tools.state_layout.widgets.StateLayout>
StateConfig.emptyLayoutRes = R.layout.state_empty
StateConfig.errorLayoutRes = R.layout.state_error
StateConfig.loadingLayoutRes = R.layout.state_loading
StateConfig.retryIds = intArrayOf(R.id.state_msg, R.id.state_iv)

StateConfig.setOnStateChangeListener(object : OnStateChangeListener {
    override fun showState(status: Int) {
        when (status) {
            StateLayout.STATE_LOADING -> {
                LogUtils.e("StateLayout", "显示加载页")
                postDelayed({
                    stateLayout.showContent()
                }, 2000L)
            }
            StateLayout.STATE_CONTENT -> {
                LogUtils.e("StateLayout", "显示内容页")
            }
            StateLayout.STATE_ERROR -> {
                LogUtils.e("StateLayout", "显示失败页")
            }
            StateLayout.STATE_EMPTY -> {
                LogUtils.e("StateLayout", "显示空页")
            }
        }
    }
})

使用局部配置:

<com.example.tools.state_layout.widgets.StateLayout
    android:id="@+id/state_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:empty_layout="@layout/state_empty"
    app:error_layout="@layout/state_error"
    app:loading_layout="@layout/state_loading">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:text="加载成功" />
</com.example.tools.state_layout.widgets.StateLayout>
stateLayout.setRetryIds(R.id.state_msg, R.id.state_iv)
stateLayout.setOnStateChangeListener(object : OnStateChangeListener {
    override fun showState(status: Int) {
        when (status) {
            StateLayout.STATE_LOADING -> {
                LogUtils.e("StateLayout", "显示加载页")
                postDelayed({
                    stateLayout.showContent()
                }, 2000L)
            }
            StateLayout.STATE_CONTENT -> {
                LogUtils.e("StateLayout", "显示内容页")
            }
            StateLayout.STATE_ERROR -> {
                LogUtils.e("StateLayout", "显示失败页")
            }
            StateLayout.STATE_EMPTY -> {
                LogUtils.e("StateLayout", "显示空页")
            }
        }
    }
})

源码下载

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1531319.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何在SpringCloud2023中快速集成注册中心

你好&#xff0c;这里是codetrend专栏“SpringCloud2023实战”。欢迎点击关注查看往期文章。 注册中心在前文提到有很多选型&#xff0c;在这里以Spring Cloud Zookeeper为例说明注册中心的集成和使用。 选择Spring Cloud Zookeeper作为注册中心原因如下&#xff1a; 依赖更少…

水电能源智能化监控系统

水电能源智能化监控系统是利用现代信息技术&#xff0c;对水电站的运行状态、设备性能、环境参数等进行实时监测和管理的一种智能化系统。随着我国水电能源事业的快速发展&#xff0c;水电能源智能化监控系统在水电能源行业中的应用越来越广泛&#xff0c;为我国水电能源事业的…

用Python的turtle库绘制皮卡丘

turtle库的简介 turtle(海龟)库是turtle绘图体系的python实现&#xff0c;turtle库是一种标准库&#xff0c;是python自带的。 turtle(海龟)是一种真实的存在&#xff0c;有一个海龟在窗口的正中心&#xff0c;在画布上游走&#xff0c;走过的轨迹形成了绘制的图形&#xff0…

如何快速搭建一个完整的vue2+element-ui的项目-二

技术细节-继续配置 提示&#xff1a;你以为这样就完了吗,其实还有很多东西需要我们自己手写的 例如&#xff1a; element-ui的配置样式重置配置src使用的配置elinst配置axios异步请求的二次封转配置语言国际化配置(这个看需求,我这里就不用配置了)vuex的配置mixins的配置开发环…

改进YOLOv8注意力系列六:结合SEAttention轻量通道注意力、ShuffleAttention重排特征注意力模块、SimAM无参数化注意力

改进YOLOv8注意力系列五:结合ParNetAttention注意力、高效的金字塔切分注意力模块PSA、跨领域基于多层感知器(MLP)S2Attention注意力 代码SEAttention轻量通道注意力ShuffleAttention重排特征注意力模块SimAM无参数化注意力加入方法各种yaml加入结构本文提供了改进 YOLOv8注…

vulnhub-----SickOS靶机

文章目录 1.信息收集2.curl命令反弹shell提权利用POC 1.信息收集 ┌──(root㉿kali)-[~/kali/vulnhub/sockos] └─# arp-scan -l Interface: eth0, type: EN10MB, MAC: 00:0c:29:10:3c:9b, IPv4: 10.10.10.10 Starting arp-scan 1.9.8 with 256…

【数据库基础增删改查】修改与删除

系列文章目录 &#x1f308;座右铭&#x1f308;&#xff1a;人的一生这么长、你凭什么用短短的几年去衡量自己的一生&#xff01; &#x1f495;个人主页:清灵白羽 漾情天殇_计算机底层原理,深度解析C,自顶向下看Java-CSDN博客 ❤️相关文章❤️&#xff1a;清灵白羽 漾情天…

cocos 3.8开发 微信小游戏分包技巧压缩主包

Creator 版本&#xff1a; 3.8.2 目标平台&#xff1a;小游戏开发 压缩后 我不知道别人压缩几百kb是怎么做到的。不过哪个要钱。 我这个技巧不用花钱。 论坛有教程但是没有教详细怎么做。 开整&#xff01; 做一个空白的场景。然后写一个load脚本。load主场景。 从代码可…

初代编译器实验

此文章用于记录第一次编译器实验的实践心得以及一些知识记录。 次实验主要目的是将C语言代码转换成对应的汇编代码&#xff0c;这就涉及到对与表达式的处理。 我们一般使用的表达式是中缀表达式&#xff0c;这对于我们人来说是比较好识别并且计算的。但对于机器&#xff0c;内部…

ES 8.x的全程编译实践与问题解决

摘要 本文整理和记录ES 8.x的编译过程问题与解决方案&#xff0c;主要解决gradle下载问题以及国内源、Hadoop环境设置与hadoop附件缺失、编译时jdk版本指定、esql的compute超时报错、编译时警告导致编译失败等问题&#xff01; 本地目录结构 . ├── build.sh ├── hadoo…

交叉注意力融合时域、频域特征的FFT + CNN -BiLSTM-CrossAttention电能质量扰动识别模型

往期精彩内容&#xff1a; 电能质量扰动信号数据介绍与分类-Python实现-CSDN博客 Python电能质量扰动信号分类(一)基于LSTM模型的一维信号分类-CSDN博客 Python电能质量扰动信号分类(二)基于CNN模型的一维信号分类-CSDN博客 Python电能质量扰动信号分类(三)基于Transformer…

大模型第一讲笔记

目录 1、人工智能基础概念全景介绍... 2 1.1 人工智能全景图... 2 1.2 人工智能历史... 2 1.3 人工智能——机器学习... 3 监督学习、非监督学习、强化学习、机器学习之间的关系... 3 监督学习... 4 无监督学习... 5 强化学习... 5 深度学习... 6 2、语言模型的发展及…

MySQL 多表查询强化练习

环境准备 create table dept(id int PRIMARY KEY,dname VARCHAR(50),loc VARCHAR(50) ); insert into dept values (10,研发部,北京), (20,学工部, 上海), (30,销售部,广州 ), (40,财务部,深圳);create table job(id int PRIMARY KEY,jname VARCHAR(20),descripition VARCHAR(…

小米汽车定价较预期下调3万至5万,发布之前仍有可能微调

跨界造车的新势力小米汽车正逐渐揭开其神秘面纱。最新爆料显示&#xff0c;小米汽车内部对车辆的定价进行了讨论&#xff0c;较之前的预期下调了3万至5万的幅度。然而&#xff0c;在正式发布之前&#xff0c;这一价格仍有可能进行微调。 历经三年的精心筹备&#xff0c;小米汽车…

5G网络架构与组网部署03--5G网络组网部署

1. SA组网与NSA组网 &#xff08;1&#xff09;NSA 非独立组网&#xff1a;终端同时接入4G基站和5G基站&#xff0c;只能实现5G部分功能 &#xff08;2&#xff09;SA组网【最终目标】&#xff1a;5G基站可以单独提供服务&#xff0c;接入的是5G核心网 区别&#xff1a;同一时间…

双轨模式的优势、弊端与未来发展:私域分销的考量

在多元化的商业环境中&#xff0c;双轨模式作为一种独特的经营策略&#xff0c;已经逐渐引起了广泛关注。这种模式通过并行运行两个或多个互补的轨道&#xff0c;旨在实现资源整合、风险分散和灵活性增强。然而&#xff0c;与此同时&#xff0c;双轨模式也伴随着一些弊端和挑战…

FPGA高端项目:FPGA基于GS2971+GS2972架构的SDI视频收发+HLS图像缩放+多路视频拼接,提供4套工程源码和技术支持

目录 1、前言免责声明 2、相关方案推荐本博主所有FPGA工程项目-->汇总目录本博已有的 SDI 编解码方案本方案的SDI接收发送本方案的SDI接收图像缩放应用本方案的SDI接收纯verilog图像缩放纯verilog多路视频拼接应用本方案的SDI接收OSD动态字符叠加输出应用本方案的SDI接收HLS…

【LeetCode每日一题】1793. 好子数组的最大分数

文章目录 [1793. 好子数组的最大分数](https://leetcode.cn/problems/maximum-score-of-a-good-subarray/)思路&#xff1a;单调栈代码&#xff1a; 1793. 好子数组的最大分数 思路&#xff1a;单调栈 1遍历数组&#xff0c;用单调栈来找到该位置左边比该位置小的数&#xff0…

Linux/Monitored

Enumeration nmap 用 nmap 扫描了常见的端口&#xff0c;发现对外开放了 22,80,389,443,5667 端口&#xff0c;端口详细信息如下 ┌──(kali㉿kali)-[~/vegetable/HTB/Monitored] └─$ nmap -sC -sV -p 22,80,389,443,5667 10.10.11.248 Starting Nmap 7.93 ( https://nm…

印度金融公司数据遭泄露,泄露数据超过3TB

近期&#xff0c;印度非银行金融公司 IKF Finance 泄露了超过 3 TB 的敏感客户和员工数据&#xff0c;可能会暴露其整个用户群。 Cybernews 研究团队发现&#xff0c;一个配置错误的 MongoDB 实例导致超过 400 万份 IKF Finance 文档被公开。 企业通常使用 MongoDB 来组织和存…