Android原生实现控件选择背景变色方案(API28及以上)
Android控件点击/选择后控件背景变色的实现方式有很多种,例如使用selector的xml文件实现。这里介绍一下另一种Android原生的点击/选择实现方案(API28及以上),也就是ColorStateListDrawable
。
ColorStateListDrawable是一个可根据不同状态显示不同颜色的Drawable。
实现效果,选择前/选择后:
这里我们利用继承LinearLayoutCompat
的方式来实现:
属性
创建自定义属性:
<attr name="carbon_chipStyle" format="reference" /><declare-styleable name="Chip"><attr name="android:text"/><attr name="android:background" /><attr name="pressed_color" format="color"/><attr name="checked_color" format="color"/><attr name="un_enable_color" format="color"/><attr name="carbon_icon" /><attr name="carbon_removable" format="boolean" /><attr name="android:checked" /></declare-styleable>
布局
创建布局文件
<?xml version="1.0" encoding="utf-8"?>
<merge 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="wrap_content"android:layout_height="match_parent"android:orientation="horizontal"><FrameLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_vertical"><FrameLayoutandroid:id="@+id/carbon_chipContent"android:layout_width="@dimen/carbon_iconSize"android:layout_height="@dimen/carbon_iconSize"android:layout_margin="@dimen/carbon_chipCloseMargin"tools:visibility="gone" /><ImageViewandroid:id="@+id/carbon_chipCheck"android:layout_width="@dimen/carbon_iconSize"android:layout_height="@dimen/carbon_iconSize"android:layout_margin="@dimen/carbon_chipCloseMargin"android:visibility="gone"android:src="@drawable/carbon_check"tools:visibility="visible" /></FrameLayout><TextViewandroid:id="@+id/carbon_chipText"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:gravity="center_vertical"android:layout_marginHorizontal="@dimen/carbon_chipPadding"tools:text="text" /><ImageViewandroid:id="@+id/carbon_chipClose"android:layout_width="@dimen/carbon_iconSize"android:layout_height="@dimen/carbon_iconSize"android:layout_gravity="center_vertical"android:layout_margin="@dimen/carbon_chipCloseMargin"android:scaleType="center"android:src="@drawable/carbon_remove" /></merge>
public class Chip extends LinearLayoutCompat implements Checkable {/*** Interface definition for a callback to be invoked when the checked state of a chip* changed.*/public interface OnCheckedChangeListener {/*** Called when the checked state of a chip has changed.** @param chip The chip whose state has changed.* @param isChecked The new checked state of buttonView.*/void onCheckedChanged(Chip chip, boolean isChecked);}private FrameLayout content;private ImageView check;private TextView title;private ImageView close;private OnRemoveListener onRemoveListener;private boolean checkedState = false;private OnCheckedChangeListener onCheckedChangeListener;public interface OnRemoveListener {void onDismiss();}public Chip(Context context) {super(context, null, R.attr.carbon_chipStyle);initChip(null, R.attr.carbon_chipStyle, R.style.carbon_Chip);}public Chip(Context context, CharSequence text) {super(context, null, R.attr.carbon_chipStyle);initChip(null, R.attr.carbon_chipStyle, R.style.carbon_Chip);setText(text);}public Chip(Context context, AttributeSet attrs) {super(context, attrs, R.attr.carbon_chipStyle);initChip(attrs, R.attr.carbon_chipStyle, R.style.carbon_Chip);}public Chip(Context context, AttributeSet attrs, @AttrRes int defStyleAttr) {super(context, attrs, defStyleAttr);initChip(attrs, defStyleAttr, R.style.carbon_Chip);}private static int[] colorStateIds = new int[]{R.styleable.Chip_android_background,R.styleable.Chip_pressed_color,R.styleable.Chip_checked_color,R.styleable.Chip_un_enable_color};private void initChip(AttributeSet attrs, @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {inflate(getContext(), R.layout.carbon_chip, this);title = findViewById(R.id.carbon_chipText);content = findViewById(R.id.carbon_chipContent);check = findViewById(R.id.carbon_chipCheck);close = findViewById(R.id.carbon_chipClose);close.setOnClickListener(v -> {if (onRemoveListener != null)onRemoveListener.onDismiss();});TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.Chip, defStyleAttr, defStyleRes);// 初始化背景Carbon.initDefaultBackground(this, a, colorStateIds);// 初始化相关自定义属性setText(a.getString(R.styleable.Chip_android_text));setIcon(Carbon.getDrawable(this, a, R.styleable.Chip_carbon_icon, 0));setRemovable(a.getBoolean(R.styleable.Chip_carbon_removable, false));a.recycle();}@Deprecatedpublic void setText(String text) {setText((CharSequence) text);}public void setText(CharSequence text) {if (text != null) {title.setText(text);title.setVisibility(View.VISIBLE);} else {title.setVisibility(View.GONE);}}public void setText(int resId) {setText(getResources().getString(resId));}public String getText() {return (String) title.getText();}public View getTitleView() {return title;}public void setIcon(int iconRes) {content.removeAllViews();if (iconRes == 0) {content.setVisibility(GONE);return;}content.setVisibility(VISIBLE);ImageView icon = new ImageView(getContext());content.addView(icon);icon.setImageResource(iconRes);}public void setIcon(Drawable drawable) {content.removeAllViews();if (drawable == null) {content.setVisibility(GONE);return;}content.setVisibility(VISIBLE);ImageView icon = new ImageView(getContext());content.addView(icon);icon.setImageDrawable(drawable);}public void setIcon(Bitmap bitmap) {content.removeAllViews();if (bitmap == null) {content.setVisibility(GONE);return;}content.setVisibility(VISIBLE);ImageView icon = new ImageView(getContext());content.addView(icon);icon.setImageBitmap(bitmap);}@Deprecatedpublic Drawable getIcon() {if (content.getChildCount() > 0 && content.getChildAt(0) instanceof ImageView)return ((ImageView) content.getChildAt(0)).getDrawable();return null;}@Deprecatedpublic View getIconView() {if (content.getChildCount() > 0 && content.getChildAt(0) instanceof ImageView)return content.getChildAt(0);return null;}public View getContentView() {if (content.getChildCount() > 0)return content.getChildAt(0);return null;}public void setContentView(View view) {content.removeAllViews();if (view != null) {content.setVisibility(VISIBLE);content.addView(view);} else {content.setVisibility(GONE);}}public void setRemovable(boolean removable) {close.setVisibility(removable ? VISIBLE : GONE);}public boolean isRemovable() {return close.getVisibility() == VISIBLE;}public void setOnRemoveListener(OnRemoveListener onRemoveListener) {this.onRemoveListener = onRemoveListener;}}
重点在于为控件手动设置一个ColorListDrawable充当背景图片:
// 为控件设置一个背景图片public static void initDefaultBackground(View view, TypedArray a, int[] ids) {Drawable d = getDefaultColorDrawable(view, a, ids);if (d != null)view.setBackgroundDrawable(d);}// 根据我们提供的android:background,pressed_color,checked_color,un_enable_color的值生成一个ColorStateListDrawablepublic static Drawable getDefaultColorDrawable(View view, TypedArray a, int[] ids) {ColorStateList color = getDefaultColorStateList(view, a, ids);if (color != null) {Drawable d = null;if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {d = new ColorStateListDrawable(color);}return d;}return null;}public static ColorStateList getDefaultColorStateList(View view, TypedArray a, int[] ids) {Context context = view.getContext();int chip_bg = ids[0];int chip_pressed_bg = ids[1];int chip_checked_bg = ids[2];int chip_un_enable_bg = ids[3];if (!a.hasValue(chip_bg))return null;int backgroundColor = a.getColor(chip_bg, 0);int pressedBgColor = a.getColor(chip_pressed_bg,ContextCompat.getColor(context, R.color.carbon_colorControlPressed));int checkedBgColor = a.getColor(chip_checked_bg,ContextCompat.getColor(context,R.color.carbon_colorControlActivated));int unEnableBgColor = a.getColor(chip_un_enable_bg,ContextCompat.getColor(context,R.color.carbon_colorControlDisabled));return ColorStateListFactory.getInstance().make(context,backgroundColor,pressedBgColor,checkedBgColor,unEnableBgColor,getThemeColor(context,com.google.android.material.R.attr.colorError));}
ColorStateListFactory
状态和颜色一一对应
public ColorStateList make(Context context,int defaultColor,int pressed,int activated,int disabled,int invalid){return new ColorStateList(new int[][]{new int[]{-android.R.attr.state_enabled}, // unenablenew int[]{android.R.attr.state_pressed}, // pressednew int[]{android.R.attr.state_checked}, //checkednew int[]{android.R.attr.state_activated},//activatednew int[]{android.R.attr.state_selected},//selectednew int[]{android.R.attr.state_focused},//focusednew int[]{}},new int[]{disabled,pressed,activated,activated,activated,activated,defaultColor});}
这样,我们就实现了按下控件,控件的背景颜色就会改变。
但是,LinearCompact本身是没有check状态的,因此这就需要我们为它添加check状态。
Checkable接口
Chip实现Checkable接口:
public class Chip extends LinearLayoutCompat implements Checkable {// 定义状态集private static final int[] CHECKED_STATE_SET = {android.R.attr.state_checked};public interface OnCheckedChangeListener {/*** Called when the checked state of a chip has changed.** @param chip The chip whose state has changed.* @param isChecked The new checked state of buttonView.*/void onCheckedChanged(Chip chip, boolean isChecked);}...public void toggle() {setChecked(!isChecked());}@Overridepublic boolean performClick() {toggle();if (onCheckedChangeListener != null)onCheckedChangeListener.onCheckedChanged(this, isChecked());final boolean handled = super.performClick();if (!handled) {// View only makes a sound effect if the onClickListener was// called, so we'll need to make one here instead.playSoundEffect(SoundEffectConstants.CLICK);}return handled;}@ViewDebug.ExportedPropertypublic boolean isChecked() {return checkedState;}/*** <p>Changes the checked state of this chip.</p>* 第二步* 在设置状态时却没有触发到这个状态。所以我们需要自己去触发这个check状态。* @param checked true to check the chip, false to uncheck it*/public void setChecked(boolean checked) {if (this.checkedState != checked) {checkedState = checked;check.setVisibility(checked ? VISIBLE : GONE);// 在状态改变时,调用refreshDrawableState()刷新状态。refreshDrawableState();}}// 第一步,我们要把状态给加进去。我们需要重写protected int[] onCreateDrawableState(int extraSpace)方法;/*** 先调用父类的onCreateDrawableState方法得到状态数组对象drawableState,但是参数extraSpace要加上1,因为我们要往里面增加一个状态。* 然后判断在代码逻辑中,是否为选中状态,如果是的话,调用mergeDrawableStates(drawableState, CHECKED_STATE_SET)方法把我们的状态值给加进去,* 最终返回drawableState。* @param extraSpace if non-zero, this is the number of extra entries you* would like in the returned array in which you can place your own* states.** @return*/@Overrideprotected int[] onCreateDrawableState(int extraSpace) {final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);if (isChecked()) {mergeDrawableStates(drawableState, CHECKED_STATE_SET);}return drawableState;}/*** Register a callback to be invoked when the checked state of this chip changes.** @param listener the callback to call on checked state change*/public void setOnCheckedChangeListener(OnCheckedChangeListener listener) {onCheckedChangeListener = listener;}}
怎么使用
<com.chinatsp.shapebutton.chip.Chipandroid:id="@+id/chip"android:layout_width="100dp"android:layout_height="@dimen/carbon_chipHeight"android:layout_margin="16dp"android:text="HELLO"android:background="@color/carbon_defaultColorControl"android:clickable="true"android:checked="false"app:checked_color="@color/carbon_red_700"app:un_enable_color="@color/carbon_grey_700"/>
相关文章:
Android原生实现控件选择背景变色方案(API28及以上)
Android控件点击/选择后控件背景变色的实现方式有很多种,例如使用selector的xml文件实现。这里介绍一下另一种Android原生的点击/选择实现方案(API28及以上),也就是ColorStateListDrawable。 ColorStateListDrawable是一个可根据不…...
为什么要学C语言及C语言存在的意义
为什么要学C语言及C语言存在的意义 汇编生C,C生万物。linus说自己最喜欢的语言就是C语言,因为看到写出的代码就能想到对应的汇编码。一方面说明C语言足够简洁,没有像C中一样的复杂概念封装,另一方面也说明C语言足够的底层…...
数据结构——空间复杂度
空间复杂度,与算法运行时所需的内存空间有关。 默认问题规模为n。 举例案例,具体分析。 1.全是普通变量 2.一维数组 3.二维数组 4.递归--变量 不递归的时候空间复杂度是O(1),递归的话递归n次,乘以n,所以空间复杂度…...
uniapp:swiper-demo效果
单元格轮播 <swiper class"swiper1" :circular"true" :autoplay"true" interval"3000" previous-margin"195rpx" next-margin"195rpx"><swiper-item v-for"(item,index) in 5" :key"inde…...
Graphviz 作图工具
选择 Graphviz 作为作图工具,主要是想通过代码创建图标,按照 Graphviz 的代码规范就可以生成 svg 的图片。当然,这样的工具也有很多,有些 markdown 编辑器也做了集成,比如: flowchart.jsMermaid 了解 Gra…...
vue、vuex状态管理、vuex的核心概念state状态
每一个 Vuex 应用的核心就是 store(仓库)。“store”基本上就是一个容器,它包含着你的应用中大部分的状态 (state)。Vuex 和单纯的全局对象有以下两点不同: Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候&…...
【QT】Qt Application Manager启动应用源码分析
Qt Application Manager启动应用源码分析 Qt Application Manager(以下简称QTAM)是QT推出的一款应用管理程序,可以把它简单理解成Android的LauncherSystemUI。但是,QTAM又集成了Wayland功能,并且自身实现了一套Compos…...
MyBatisPlus(十)判空查询
说明 判空查询,对应SQL语句中的 IS NULL语句,查询对应字段为 NULL 的数据。 isNull /*** 查询用户列表, 查询条件:电子邮箱为 null 。*/Testvoid isNull() {LambdaQueryWrapper<User> wrapper new LambdaQueryWrapper<…...
AIGC(生成式AI)试用 8 -- 曾经的难题
长假,远离电脑、远离手机、远离社交。 阴雨连绵,望着窗外发呆,AIGC为何物?有什么问题要问AIGC?AIGC可以代替我来发呆,还是可是为我空出时间发呆? 如果可以替代我发呆,要我何…...
文化主题公园旅游景点3d全景VR交互体验加深了他们对历史文化的认知和印象
如今,沉浸式体验被广泛应用于文旅行业,尤其是在旅游演艺活动中。在许多城市,沉浸式旅游演艺活动已成为游客“必打卡”项目之一。因其独特体验和强互动性,这类演艺活动不仅吸引了外地游客,也吸引了本地观众。 随着信息化…...
京东数据分析平台:2023年8月京东奶粉行业品牌销售排行榜
鲸参谋监测的京东平台8月份奶粉市场销售数据已出炉! 鲸参谋数据显示,8月份京东平台上奶粉的销售量将近700万件,环比增长约15%,同比则下滑约19%;销售额将近23亿元,环比增长约4%,同比则下滑约3%。…...
Java 21:虚拟线程介绍
Java 21 版本更新中最重要的功能之一就是虚拟线程 (JEP 444)。这些轻量级线程减少了编写、维护和观察高吞吐量并发应用程序所需的工作量。 正如我的许多其他文章一样,在推出新功能之前,让我们先看看 Java 21 版本更新前的现状,以便更好地了解…...
Redis-缓存穿透,缓存击穿,缓存雪崩
缓存穿透,缓存击穿,缓存雪崩 缓存穿透处理方案解决方案1 缓存空数据解决方案2 布隆过滤器 缓存击穿处理方案解决方案 1 互斥锁解决方案2 逻辑过期 缓存雪崩处理方案解决方案 1 给不同的key的过期时间设置添加一个随机值,降低同一个时段大量ke…...
如何使用Docker实现分布式Web自动化!
01、前言 顺着docker的发展,很多测试的同学也已经在测试工作上使用docker作为环境基础去进行一些自动化测试,这篇文章主要讲述在docker中使用浏览器进行自动化测试如果可以实现可视化,同时可以对浏览器进行相关的操作。 02、开篇 首先我们…...
从零开始:制作出色的产品原型图的详细教程
在设计产品的初始版本或模型时,产品原型起着非常重要的作用,可以帮助设计师和团队更好地了解产品需求和用户需求,优化和改进设计,确保设计最终满足用户的需求和期望。如果你不知道如何绘制产品原型图,绘制产品原型图的…...
美国访问学者签证如何申请加急办理?
许多中国学者梦想着前往美国深造,积累更多的学术经验和知识。然而,签证申请过程可能会变得复杂和繁琐,特别是如果你需要在紧急情况下前往美国。但别担心,本文知识人网小编将为您介绍美国访问学者签证加急办理的一些建议和步骤。 首…...
33 WEB漏洞-逻辑越权之水平垂直越权全解
目录 前言水平,垂直越权,未授权访问Pikachu-本地水平垂直越权演示(漏洞成因)墨者水平-身份认证失效漏洞实战(漏洞成因)原理越权检测-Burpsuite插件Authz安装测试(插件使用)修复防御方案 前言 越权漏洞文章分享:https://www.cnblogs.com/zhen…...
【FreeRTOS】【STM32】02 FreeRTOS 移植
基于 [野火]《FreeRTOS%20内核实现与应用开发实战—基于STM32》 正点原子《STM32F429FreeRTOS开发手册_V1.2》 准备 基础工程,例如点灯 FreeRTOS 系统源码 FreeRTOS 移植 上一章节已经说明了Free RTOS的源码文件在移植时所需要的,FreeRTOS 为我们提供…...
STM32F4X 内部FLASH使用
STM32F4X 内部FLASH使用 STM32F4X 内部FLASHSTM32F4X内部FLASH结构STM32F40X和STM32F41X内部FLASH结构STM32F42X和STM32F43X内部FLASH结构 STM32F4X内部FLASH操作例程internal_flash.hinternal_flash.cmain.c 在嵌入式开发中,经常需要实时保存一些数据。如果工程的代…...
减小windows或linux虚拟机导出ova体积大小
减小windows或linux虚拟机导出ova体积大小 删除无用的文件,比如日志或者命令,程序等;去除磁盘碎片将不用的内存空间填充为0,便于vmdk压缩。 例子: 日志文件置空: 批量置空 /sf/data/log/ 目录下的日志文…...
WPF livecharts 折线图遮挡数字问题
在WPF里使用livecharts,如果折线图或者柱状图有多个的时候,可能会出现两个数字遮挡问题,这时候要设置DataLabelsTemplate 属性。 如LineSeries设置代码如下: 第一个折线图的DataLabelsTemplate var stackPanelFactory new Fra…...
电力系统数字化升级改造之配电室无人值守
随着科技的不断进步,电力系统的数字化升级改造已成为必然趋势。其中,配电室的无人值守是其中重要的一环。 配电室是电力系统的重要组成部分,其运行状态直接影响到电力系统的稳定性和可靠性。然而,传统的配电室存在很多问题&am…...
集合Set
目录 一、去重问题 一、去重问题 题目描述: 小明想在学校中请一些同学一起做一项问卷调查,为了实验的客观性他先用计算机生成了N个1~1000之间的随机整数(N<1000),N是用户输入的,对于其中重复的数字,只保留一个&am…...
TCP/IP(二)导论
一 知识铺垫 以下内容参照 <<电子科技大学TCPIP协议原理>>全 ① 协议和标准 一组规则: 交通规则、学生上学的学生守则等;数据通信的规则,有一个专门的名称叫作协议 protocol语义:具体描述在通信当中,每一个信息的具体含义. 二进制bit流…...
Java之UDP,TCP的详细解析
练习四:文件名重复 public class UUIDTest { public static void main(String[] args) { String str UUID.randomUUID().toString().replace("-", ""); System.out.println(str);//9f15b8c356c54f55bfcb0ee3023fce8a } } public class Client…...
【总结】kubernates crd client-java 关于自定义资源的增删改查
Java model 准备 首先使用 crd.yml 和 kubernetes CRD 自动生成 Java model 类,这是一切的前提,之前在这个地方也卡了很久。如何生成在另外一个文章中已经有所记录。 使用 crd.yml 和 kubernetes CRD 自动生成 Java model 类 CustomObjectsApi 文档学习…...
蓝牙主要知识,一文概览
蓝牙知识相关 文章目录 蓝牙知识相关1.蓝牙版本的发展简史2.低功耗BLE PHY2.1 频段**2.2 BLE调制方案—GFSK**2.3 **蓝牙 LE 传输速度、功率和接收器灵敏度**2.4 **BLE 时分双工 (TDD)**3.BT主从连接过程3.1 主设备工作模式3.1.1 积木编程控制台3.2 从设备工作模式3.2.1 蓝牙遥…...
Linux 守护进程
一 何为守护进程 守护进程( Daemon )也称为精灵进程,是运行在后台的一种特殊进程,它独立于控制终端并且周期性 地执行某种任务或等待处理某些事情的发生,主要表现为以下两个特点: 长期运行。守护进程是一…...
自动驾驶技术的基础知识
自动驾驶技术是现代汽车工业中的一项革命性发展,它正在改变着我们对交通和出行的理解。本文将介绍自动驾驶技术的基础知识,包括其概念、历史发展、分类以及关键技术要素。 1. 自动驾驶概念 自动驾驶是一种先进的交通技术,它允许汽车在没有人…...
解决:yarn 无法加载文件 “C:\Users\XXXXX\AppData\Roaming\npm\yarn.ps1,因为在此系统上禁止运行脚本“ 的问题
1、问题描述: 报错的整体代码为: yarn : 无法加载文件 C:\Users\admin\AppData\Roaming\npm\yarn.ps1,因为在此系统上禁止运行脚本 // 整体的报错代码为 : yarn : 无法加载文件 C:\Users\admin\AppData\Roaming\npm\yarn.ps1&…...
自己做的网站如何制作后台/免费推广的途径与原因
环境: Microsoft SQL Server Management Studio 10.0.1600.22 ((SQL_PreRelease).080709-1414 服务端、客户端)① 使用客户端用超级管理员sa登录后选择数据库备份(源数据库ShopERP_New)。 ② 还原数据库(目标数据库ShopERP)...
联系昆明网站建设/网站seo优化运营
学数字IC的同学都知道的经典问题。延时/时序,是数字电路的核心概念。 时序约束,是保证门级电路正常工作的延迟约束,就好像高速公路上行驶的汽车,对其车速和安全车距的要求。速度过快,车距过近,就很容易发生…...
做雕塑网站/河北网站seo地址
前文回顾 《Linux驱动开发(一)—环境搭建与hello world》 《Linux驱动开发(二)—驱动与设备的分离设计》 《Linux驱动开发(三)—设备树》 《Linux驱动开发(四)—树莓派内核编译》 《…...
只做域名跳转和关停网站/网站ip查询站长工具
618剁手党们熬夜蹲点“买买买”的“战争”刚结束,物流运输就紧随其后拉起了战线。面对每逢“佳节”必“爆仓”的快递包裹,依旧准时准点的送达到我们每个人手中,这背后的运输环节离不开一群默默付出的“骑士”——卡车司机。 作为中国公路货运…...
图片网站源码asp/基本营销策略有哪些
本文会提到52条SQL语句性能优化策略。 1、对查询进行优化,应尽量避免全表扫描,首先应考虑在where及order by涉及的列上建立索引。 2、应尽量避免在where子句中对字段进行null值判断,创建表时NULL是默认值,但大多数时候应该使用N…...
太原网站建设-中国互联/营销培训课程2022
-- Tips:聚合和排序-- 一、对表进行聚合查询 -- 1.聚合函数-- (1)5 个常用函数:-- ①COUNT:计算表中的记录(行)数。-- ②SUM:计算表中数值…...