Android StateLayout状态页
文章目录
- Android StateLayout状态页
- 概述
- 源码
- 使用
- 源码下载
Android StateLayout状态页
概述
StateLayout(状态页)包含:加载中页面,错误页面,空页面,内含状态默认页面,支持自定义页面。

源码
全局配置:
package com.example.tools.state_layout.widgetsimport android.view.View
import androidx.annotation.LayoutRes/*** StateLayout全局配置*/
object StateConfig {@LayoutRes@JvmStaticvar emptyLayoutRes = View.NO_ID@LayoutRes@JvmStaticvar errorLayoutRes = View.NO_ID@LayoutRes@JvmStaticvar loadingLayoutRes = View.NO_ID@LayoutRes@JvmStaticvar retryIds: IntArray? = nullprivate var mOnStateChangeListener: OnStateChangeListener? = nullfun 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 = 0xA001const val STATE_EMPTY = 0xA002const val STATE_ERROR = 0xA003const val STATE_CONTENT = 0xA004}// empty布局资源@LayoutResprivate var emptyLayoutRes = View.NO_IDget() = if (field == View.NO_ID) StateConfig.emptyLayoutRes else field// loading布局资源@LayoutResprivate var loadingLayoutRes = View.NO_IDget() = if (field == View.NO_ID) StateConfig.loadingLayoutRes else field// error布局资源@LayoutResprivate var errorLayoutRes = View.NO_IDget() = if (field == View.NO_ID) StateConfig.errorLayoutRes else field// 保存状态private val stateInfoMap = ArrayMap<Int, View>()// 当前状态private var currentState = STATE_CONTENT// 需要设置点击事件的idprivate var retryIds: IntArray? = nullget() = field ?: StateConfig.retryIdsprivate var mOnStateChangeListener: OnStateChangeListener? = nullget() = 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.valuehideStateView(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 -> emptyLayoutResSTATE_ERROR -> errorLayoutResSTATE_LOADING -> loadingLayoutResSTATE_CONTENT -> View.NO_IDelse -> 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] = viewreturn 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.StateLayoutandroid:id="@+id/state_layout"android:layout_width="match_parent"android:layout_height="match_parent"><TextViewandroid: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.StateLayoutandroid: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"><TextViewandroid: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", "显示空页")}}}
})
源码下载
相关文章:
Android StateLayout状态页
文章目录 Android StateLayout状态页概述源码使用源码下载 Android StateLayout状态页 概述 StateLayout(状态页)包含:加载中页面,错误页面,空页面,内含状态默认页面,支持自定义页面。 源码 …...
JetBrains数据库驱动下载失败解决方法
本方法可通用于解决PyCharm等JetBrains家的IDE下载数据库驱动问题。 在Jet家IDE内连接数据库时,mysql、sqlite等的驱动有部分在 https://download.jetbrains.com 网站上,可能由于网络问题无法访问。 解决方法是修改 JetBrains 路径下的 jdbc.drivers.xm…...
【vim 学习系列文章 16 -- vim 自动保存设置】
文章目录 vim 自动保存设置 vim 自动保存设置 在 Vim 编辑器中,你可以通过设置 updatetime 选项来控制自动保存的时间间隔。updatetime 的默认值是 4000 毫秒(4 秒),但你可以将其设置为 5000 毫秒(5 秒)以…...
python的O2O生鲜食品订购flask-django-nodejs-php
用户只能通过一些类似软件进行查看生鲜超市,这样的管理方式仍然是比较机械传统的,本文通过对市面上常见的线上管理系统与现实生活中结合问题的讨论,从一个微信小程序的O2O生鲜食品订购角度进行需求分析,提供一些新的思路ÿ…...
六、大模型-Prompt-API介绍
GPT-3.5 API 提供了一个名为 openai.ChatCompletion.create() 的端点,您可以使用该端点来与 ChatGPT 进行交互。以下是 openai.ChatCompletion.create() 的详细 API 说明: 请求参数: messages:一个数组,包含对话中的消…...
嵌入式安全性基础知识-计算机系统安全知识+信息安全基础+网络安全协议-嵌入式系统设计师备考笔记
0、前言 本专栏为个人备考软考嵌入式系统设计师的复习笔记,未经本人许可,请勿转载,如发现本笔记内容的错误还望各位不吝赐教(笔记内容可能有误怕产生错误引导)。 本章的主要内容见下图: 1、计算机系统系统…...
基于javaSpringboot+mybatis+layui的装修验收管理系统设计和实现
基于javaSpringbootmybatislayui的装修验收管理系统设计和实现 博主介绍:多年java开发经验,专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 央顺技术团队 Java毕设项目精品实战案例《1000套》 欢迎点赞 收藏 ⭐留…...
jenkins构建完成后部署到本机,无法读取容器外文件夹
项目背景: Dockerjenkins 构建完成后,要把打包的dist文件夹内容移动到网站目录 /www/wwwroot/xxxxxx 文件夹下;但是获取不到jenkins容器外的文件夹。 解决办法: 在容器中,添加挂载/映射本机目录,把网站…...
如何使用 Elasticsearch 作为向量数据库
在今天的文章中,我们将很快地通过 Docker 来快速地设置 Elasticsearch 及 Kibana,并设置 Elasticsearch 为向量搜索。 拉取 Docker 镜像 docker pull docker.elastic.co/elasticsearch/elasticsearch:8.12.2 docker pull docker.elastic.co/kibana/kiba…...
高精度AI火灾烟雾检测算法,助力打造更加安全的楼宇环境
一、方案背景 近日,南京居民楼火灾事故导致15人死亡的新闻闹得沸沸扬扬,这一事件又激起了大家对楼宇火灾隐患的进一步担忧。事后我们除了思考政府、消防及物业部门应对此事的解决办法,我们还应该思考如何利用现有的技术帮助人们减少此类事情的…...
node和npm yarn包管理工具
node和包管理工具 今日目标: 1.dos常用指令 2.node的模块化 3.npm包管理工具 4.yarn的常用指令 5.node的内置模块 00-回顾 # Promose:作用:解决ajax请求响应顺序不可控的问题特性:1. Promise是一个构造函数,需要通过new关…...
鸿蒙Harmony应用开发—ArkTS(@Link装饰器:父子双向同步)
子组件中被Link装饰的变量与其父组件中对应的数据源建立双向数据绑定。 说明: 从API version 9开始,该装饰器支持在ArkTS卡片中使用。 概述 Link装饰的变量与其父组件中的数据源共享相同的值。 限制条件 Link装饰器不能在Entry装饰的自定义组件中使用…...
【数据结构】猛猛干7道链表OJ
前言知识点 链表的调试技巧 int main() {struct ListNode* n1(struct ListNode*)malloc(sizeof(struct ListNode));assert(n1);struct ListNode* n2(struct ListNode*)malloc(sizeof(struct ListNode));assert(n2);struct ListNode* n3(struct ListNode*)malloc(sizeof(struc…...
记录C++中,子类同名属性并不能完全覆盖父类属性的问题
问题代码: 首先看一段代码:很简单,就是BBB继承自AAA,然后BBB重写定义了同名属性,然后调用父类AAA的打印函数: #include <iostream> using namespace std;class AAA { public:AAA() {}~AAA() {}void …...
使用 ONLYOFFICE API 构建 Java 转换器,在 Word 和 PDF 之间进行转换
文章作者:ajun 随着文档处理需求的增加,格式转换成为了一个重要的需求点。由于PDF格式具有跨平台、不易被篡改的特性,将Word格式(.docx)转换为PDF格式(.pdf)的需求尤为强烈。ONLYOFFICE作为一个强大的办公套件,提供了这样的转换功…...
SpringCloudAlibaba Nacos配置及应用
Nacos搭建及配置 nacos本机服务搭建 windows上搭建单机nacos: Releases alibaba/nacos GitHub 下载安装包 下载本地,解压,直接运行(保证安装包的绝度路径只有英文字符,有中文会导致运行失败)ÿ…...
#Linux(权限管理)
(一)发行版:Ubuntu16.04.7 (二)记录: (1) (2)-开头代表普通文件 划分为三组: rw- rw- r-- rw-: 文件拥有…...
easyExcel复杂表头导出
代码 import com.alibaba.excel.EasyExcel; import com.alibaba.excel.write.style.column.AbstractColumnWidthStyleStrategy; import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;import java.util.ArrayList; import java.util.Arrays; imp…...
【大数据】五、yarn基础
Yarn Yarn 是用来做分布式系统中的资源协调技术 MapReduce 1.x 对于 MapReduce 1.x 的版本上: 由 Client 发起计算请求,Job Tracker 接收请求之后分发给各个TaskTrack进行执行 在这个阶段,资源的管理与请求的计算是集成在 mapreduce 上的…...
语义分割实战项目(从原理到代码环境配置)
语义分割(Semantic Segmentation) 先看结果: 是计算机视觉和深度学习领域的一项核心任务,它主要致力于对图像中的每一个像素进行分类,赋予每个像素一个类别标签,以达到理解图像内容的目的。换句话说&#…...
Lixie数码管驱动库深度解析:WS2812B嵌入式显示控制实践
1. Lixie 数码管驱动库技术解析:面向嵌入式工程师的深度实践指南Lixie 是一款专为驱动“Lixie 边缘导光数码管”(Edge-Lit Digit Display)设计的 Arduino 兼容库。它并非传统真空管或七段 LED,而是一种融合光学设计与现代 LED 控制…...
C# 13主构造函数到底怎么用:从语法糖到IL底层,3步写出零反射、零冗余的生产级代码
第一章:C# 13主构造函数到底怎么用:从语法糖到IL底层,3步写出零反射、零冗余的生产级代码 C# 13 的主构造函数(Primary Constructors)并非简单的语法糖,而是编译器在类型声明阶段就完成参数绑定与字段初始化…...
YOLOv12解决方案实战:智能安防、交通监控、工业检测三大场景应用
YOLOv12解决方案实战:智能安防、交通监控、工业检测三大场景应用 【免费下载链接】yolov12 [NeurIPS 2025] YOLOv12: Attention-Centric Real-Time Object Detectors 项目地址: https://gitcode.com/gh_mirrors/yo/yolov12 YOLOv12作为NeurIPS 2025最新发布的…...
Python拉取视频流的性能优化实战
一、背景与挑战在安防监控、直播推流、视频分析等场景中,我们经常需要使用Python拉取网络视频流(RTSP、HLS、HTTP-FLV等)。然而Python并非以高性能著称,面对高码率、多路视频流时,容易遇到:延迟累积&#x…...
CherryStudio+Obsidian组合拳:打造自动更新的个人AI知识中枢
CherryStudioObsidian组合拳:打造自动更新的个人AI知识中枢 在信息爆炸的时代,科研人员和专业写作者面临的最大挑战不是获取知识,而是如何高效管理和持续更新个人知识体系。传统笔记工具虽然能帮助我们收集信息,但当知识量达到数千…...
InfinitePCA9685:嵌入式多PCA9685芯片PWM统一控制库
1. InfinitePCA9685库概述:面向嵌入式多设备PWM控制的工程化抽象InfinitePCA9685是一个专为Arduino平台设计的轻量级C库,其核心目标是解决嵌入式系统中多PCA9685芯片协同控制这一典型工程痛点。在机器人关节驱动、LED矩阵调光、工业IO扩展等实际场景中&a…...
GCC优化禁用指南:精准控制编译行为的5种方法
1. 为什么需要禁用GCC优化? 在嵌入式开发或者调试过程中,我们经常会遇到一些奇怪的bug:明明代码逻辑没有问题,但程序运行时却出现异常。这时候很可能就是编译器优化在"捣鬼"。GCC作为最常用的开源编译器,它的…...
Docker镜像拉取超时?5分钟搞定国内镜像源加速配置(附最新可用镜像列表)
Docker镜像加速全攻略:2024国内镜像源配置与疑难排解 每次在终端输入docker pull后盯着进度条卡住不动,是不是感觉血压都在飙升?作为国内开发者,Docker官方镜像源的访问问题就像一场永远打不完的"拉锯战"。但别急着摔键…...
小红书合规引流新姿势:聚光平台落地页卡片制作全流程指南
小红书聚光平台合规引流实战手册:从落地页设计到高效转化全解析 在小红书这个日活超过2亿的内容社区里,企业营销人员和个体创业者最关心的莫过于如何在不触碰平台红线的前提下实现精准引流。聚光平台作为小红书官方推出的商业工具,其落地页卡…...
D435i多传感器标定全流程:从驱动安装到生成标定板的完整Checklist
D435i多传感器标定全流程:从驱动安装到生成标定板的完整Checklist 第一次接触D435i多传感器标定时,我被各种驱动安装、参数配置和标定工具搞得晕头转向。作为一款集成了RGB摄像头、双目视觉和IMU的深度相机,D435i在机器人导航、三维重建等领域…...
