Android开发首页底部tab切换图标有动画效果
Android开发首页底部tab切换图标有动画效果
主页tab切换很正常,但往往加上写动画更好看
一、思路:
用属性动画,并且事先准备多张图片,用于切换后播放动画
二、效果图:
单纯图看不出来,看下视频效果
Android开发教程实战案例源码分享-首页底部tab切换图标有动画效果
三、关键代码:
public class TabButtonGroup extends LinearLayout implements View.OnClickListener {private TabButton[] mTabButtons;private ViewPager mViewPager;private int mCurPosition;public TabButtonGroup(Context context) {this(context, null);}public TabButtonGroup(Context context, @Nullable AttributeSet attrs) {this(context, attrs, 0);}public TabButtonGroup(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}@Overrideprotected void onFinishInflate() {super.onFinishInflate();int childCount = getChildCount();if (childCount > 0) {mTabButtons = new TabButton[childCount];for (int i = 0; i < childCount; i++) {View v = getChildAt(i);v.setTag(i);v.setOnClickListener(this);mTabButtons[i] = (TabButton) v;}}}public void setCurPosition(int position) {if (position == mCurPosition) {return;}if (mClickIntercepter != null && mClickIntercepter.needIntercept(position)) {return;}mTabButtons[mCurPosition].setChecked(false);mTabButtons[position].setChecked(true);mCurPosition = position;if (mViewPager != null) {mViewPager.setCurrentItem(position, false);}}@Overridepublic void onClick(View v) {Object tag = v.getTag();if (tag != null) {setCurPosition((int) tag);}}public void setViewPager(ViewPager viewPager) {mViewPager = viewPager;}public void cancelAnim() {if (mTabButtons != null) {for (TabButton tbn : mTabButtons) {if (tbn != null) {tbn.cancelAnim();}}}}public ClickIntercepter mClickIntercepter;public void setClickIntercepter(ClickIntercepter intercepter) {mClickIntercepter = intercepter;}public interface ClickIntercepter {boolean needIntercept(int position);}public void btnPerformClick(int position){if (mTabButtons != null&&mTabButtons[position]!=null) {mTabButtons[position].performClick();}}
}
public class TabButton extends LinearLayout {private Context mContext;private float mScale;private String mTip;private int mIconSize;private int mTextSize;private int mTextColorChecked;private int mTextColorUnChecked;private boolean mChecked;private ImageView mImg;private TextView mText;private Drawable[] mDrawables;private int mDrawaleArrayLength;private ValueAnimator mAnimator;private int mDrawableIndex;public TabButton(Context context) {this(context, null);}public TabButton(Context context, AttributeSet attrs) {this(context, attrs, 0);}public TabButton(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);mContext = context;mScale = context.getResources().getDisplayMetrics().density;TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.TabButton);int iconArrayId = ta.getResourceId(R.styleable.TabButton_tbn_icon_array_id, 0);mTip = ta.getString(R.styleable.TabButton_tbn_tip);mIconSize = (int) ta.getDimension(R.styleable.TabButton_tbn_icon_size, 0);mTextSize = (int) ta.getDimension(R.styleable.TabButton_tbn_text_size, 0);mTextColorChecked = ta.getColor(R.styleable.TabButton_tbn_text_color_checked, 0);mTextColorUnChecked = ta.getColor(R.styleable.TabButton_tbn_text_color_unchecked, 0);mChecked = ta.getBoolean(R.styleable.TabButton_tbn_checked, false);ta.recycle();if (iconArrayId != 0) {TypedArray arr = getResources().obtainTypedArray(iconArrayId);int len = arr.length();int[] iconResArray = new int[len];for (int i = 0; i < len; i++) {iconResArray[i] = arr.getResourceId(i, 0);}arr.recycle();mDrawaleArrayLength = iconResArray.length;if (mDrawaleArrayLength > 0) {mDrawables = new Drawable[mDrawaleArrayLength];for (int i = 0; i < mDrawaleArrayLength; i++) {mDrawables[i] = ContextCompat.getDrawable(context, iconResArray[i]);}}}mAnimator = ValueAnimator.ofFloat(1, mDrawaleArrayLength - 1);mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {float v = (float) animation.getAnimatedValue();int index = (int) v;if (mDrawableIndex != index) {mDrawableIndex = index;if (mImg != null) {mImg.setImageDrawable(mDrawables[index]);}}}});mAnimator.setDuration(500);mAnimator.setInterpolator(new LinearInterpolator());}@Overrideprotected void onFinishInflate() {super.onFinishInflate();setOrientation(VERTICAL);setGravity(Gravity.CENTER_HORIZONTAL);mImg = new ImageView(mContext);LayoutParams params1 = new LayoutParams(mIconSize, mIconSize);params1.setMargins(0, dp2px(4), 0, 0);mImg.setLayoutParams(params1);if (mDrawables != null && mDrawaleArrayLength > 0) {if (mChecked) {mImg.setImageDrawable(mDrawables[mDrawaleArrayLength - 1]);} else {mImg.setImageDrawable(mDrawables[0]);}}mText = new TextView(mContext);LayoutParams params2 = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);mText.setLayoutParams(params2);mText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextSize);mText.setText(mTip);mText.setTextColor(mChecked ? mTextColorChecked : mTextColorUnChecked);addView(mImg);addView(mText);}public void setChecked(boolean checked) {mChecked = checked;if (mDrawables != null && mDrawaleArrayLength > 0) {if (mChecked) {if (mText != null) {mText.setTextColor(mTextColorChecked);}if (mAnimator != null) {mAnimator.start();}} else {if (mAnimator != null) {mAnimator.cancel();}if (mImg != null) {mImg.setImageDrawable(mDrawables[0]);}if (mText != null) {mText.setTextColor(mTextColorUnChecked);}}}}private int dp2px(int dpVal) {return (int) (mScale * dpVal + 0.5f);}public void cancelAnim() {if (mAnimator != null) {mAnimator.cancel();mAnimator.removeAllUpdateListeners();}}}
四、项目demo源码结构图:

有问题或者需要完整源码的私信我
相关文章:
Android开发首页底部tab切换图标有动画效果
Android开发首页底部tab切换图标有动画效果 主页tab切换很正常,但往往加上写动画更好看 一、思路: 用属性动画,并且事先准备多张图片,用于切换后播放动画 二、效果图: 单纯图看不出来,看下视频效果 An…...
Web前端高级工程师培训:异步处理专题
异步处理专题 课前准备 工具 编辑器 VSCode浏览器 Chorme 前置知识 ES6基础语法 课堂主题 同步及异步概念方块运动的实现promise的用法then的返还值Async 函数 和 await 课堂目标 理解并学会使用promise使用方式以及async 、await的使用 同步异步概念 js是单线程 单线程…...
ESP32-C3实现热点并在浏览器中输入域名访问网页
源代码 #include <WiFi.h> // 引入 WiFi 库,用于处理网络连接 #include <WebServer.h> // 引入 WebServer 库,用于创建 HTTP 服务器 #include <DNSServer.h> // 引入 DNSServer 库,用于处理 DNS 请…...
基于Python的自然语言处理系列(32):spaCy属性扩展
1. 介绍 在 spaCy 中,自定义扩展属性让我们能够为 Doc、Token 和 Span 对象添加元数据。通过这些扩展属性,开发者可以根据需要存储额外的上下文信息,或者动态计算属性值。 自定义属性通过点下划线(dot-underscore)属性访问,例如 token._.is_color。这种命名方式确保这些属…...
STM32 输入捕获模式详解:PWM 输入捕获与 PWI 模式(续篇)
在前两篇文章中,我们探讨了 STM32 输入捕获的基础和 PWI 模式的工作原理,特别是定时器的两个通道如何协同工作以捕获 PWM 信号。本文将进一步结合 STM32 标准库函数中的 TIM_PWMIConfig(),来讲解如何通过库函数配置定时器实现 PWI 模式。 我…...
【C++】set/map(重点解析)
目录 一、关联式容器和序列式容器 二、C中的键值对——pair 1.概念 2.定义 3.构造pair 三.set 1.construct构造 2.iterator迭代器 3.insert插入 4.erase删除 5.find查找 6.lower_bound和upper_bound 7.count 四.multiset 五.map 1.insert 2.operator[] 一、…...
【算法篇】动态规划类(1)(笔记)
目录 一、理论基础 1. 大纲 2. 动态规划的解题步骤 二、LeetCode 题目 1. 斐波那契数 2. 爬楼梯 3. 使用最小花费爬楼梯 4. 不同路径 5. 不同路径 II 6. 整数拆分 7. 不同的二叉搜索树 一、理论基础 1. 大纲 动态规划,英文:Dynamic Programm…...
mysql学习教程,从入门到精通,SQL 约束(Constraints)(41)
在数据库设计中,约束(Constraints)用于确保数据的准确性和完整性。它们通过限制可以插入到数据库表中的数据类型来防止无效数据。SQL 中有几种常见的约束类型,包括主键约束(Primary Key)、外键约束…...
使用CSS3与JavaScript实现炫酷的3D旋转魔方及九宫格交换动效
文章目录 前言一、项目需求背景二、CSS3 3D基础知识介绍2.1 什么是CSS3 3D?2.2 主要使用的CSS属性 三、使用HTML和CSS搭建魔方结构四、让魔方动起来:CSS3动画五、九宫格数字交换的JavaScript实现5.1 九宫格布局5.2 随机交换数字 六、随机交换与相邻格子的…...
springboot项目通过maven的profile功能实现通过不同文件夹的方式来组织不同环境配置文件
写在前面 本文看下springboot项目如何通过文件夹的方式来组织不同环境配置文件。 1:正文 一般的我们写springboot项目时配置文件是这个样子的: appliction.yaml --> 通过spring.profiles.activexxx来激活某个指定后缀的配置文件 application-evn1…...
GAN(Generative Adversarial Nets)
GAN(Generative Adversarial Nets) 引言 GAN由Ian J. Goodfellow等人提出,是Ian J. Goodfellow的代表作之一,他还出版了大家耳熟能详的花书(Deep Learning深度学习),GAN主要的思想是同时训练两个模型,生成…...
linux下使用mpi求自然数和
搭建MPI并行计算环境,编写 MPI程序,求和 1 23....1 0000。 要求: 1.使用100个进程; 2.进程0计算1 2...100, 进程1计算101 102... 200, ..... 进程99计算9901 9902... 10000; 3.调用计时函数,分别输出每个进程的计算时间; 4.需使用MPI集群通信函数和同…...
WebGl学习使用attribute变量绘制一个水平移动的点
在WebGL编程中,attribute变量是一种特殊类型的变量,用于从客户端传递数据到顶点着色器。这些数据通常包括顶点的位置、颜色、纹理坐标等,它们是与每个顶点直接相关的信息。attribute变量在顶点着色器中声明,并且对于每个顶点来说都…...
机器学习四大框架详解及实战应用:PyTorch、TensorFlow、Keras、Scikit-learn
目录 框架概述PyTorch:灵活性与研究首选TensorFlow:谷歌加持的强大生态系统Keras:简洁明了的高层 APIScikit-learn:传统机器学习的必备工具实战案例 图像分类实战自然语言处理实战回归问题实战 各框架的对比总结选择合适的框架 1…...
linux源码安装slurm以及mung和openssl
一、源码安装munge 1、编译安装munge (1)下载munge地址:https://github.com/dun/munge/releases (2)解压编译安装: 1 2 3 4 5 6 7 8 创建/data目录 复制文件munge-0.5.15.tar.xz 到/data目录下 tar -Jx…...
分享蓝牙耳机A2DP音频卡顿原因及解决思路
背景 最近一直在更新博客,我觉得写博客有三个好处,一是很多东西时间久了就会忘,记下来方便自己以后回忆和总结,二是记下来可以加深自己对知识的理解,三是可以知识分享,方便他人。 言归正传,今天…...
Mac 下编译 libaom 源码教程
AV1 AV1是一种开放、免版税的视频编码格式,由开放媒体联盟(AOMedia)开发,旨在提供高压缩效率和优秀的视频质量。AV1支持多种分辨率,包括SD、HD、4K和8K,并适用于视频点播(VOD)、直播…...
【成品设计】基于Arduino平台的物联网智能灯
《基于Arduino平台的物联网智能灯》 整体功能: 这个任务中要求实现一个物联网智能灯。实际测试环境中要求设备能够自己创建一个热点,连接这个热点后能自动弹出控制界面(强制门户)。 功能点 基础功能 (60分) 要求作品至少有2个灯…...
安装和配置k8s可视化UI界面dashboard-1.20.6
安装和配置k8s可视化UI界面dashboard-1.20.6 1.环境规划2.初始化服务器1)配置主机名2)设置IP为静态IP3)关闭selinux4)配置主机hosts文件5)配置服务器之间免密登录6)关闭交换分区swap,提升性能7&…...
VLAN:虚拟局域网
VLAN:虚拟局域网 交换机和路由器协同工作后,将原先的一个广播域,逻辑上,切分为多个广播域。 第一步:创建VLAN [SW1]dispaly vlan 查询vlan VID(VLAN ID):用来区分和标定不同的vlan 由12位二进制构成 范围: 0-4…...
PowerBI进阶技巧:利用SWITCH函数实现动态自定义排序
1. 为什么需要自定义排序? 在PowerBI报表设计中,数据排序是最基础却最容易被忽视的功能。系统默认提供的升序和降序排列,就像餐厅里只有"辣"和"不辣"两种选项,而实际业务场景往往需要"微辣""中…...
从一次存储故障复盘说起:深入理解FC SAN中WWN、WWPN、WWNN的区别与实战应用
从一次存储故障复盘说起:深入理解FC SAN中WWN、WWPN、WWNN的区别与实战应用 那天凌晨三点,我被一阵急促的电话铃声惊醒。客户的核心数据库集群突然失去存储连接,业务完全停滞。当我赶到现场时,运维团队已经尝试了重启服务器、更换…...
Comsol 锂枝晶模型 “五合一”:探索枝晶生长的多元奥秘
comsol 锂枝晶模型 五合一 单枝晶定向生长、多枝晶定向生长、多枝晶 随机生长只 无序生长随机形核以及雪花枝晶,包含相场、浓度场和电场三种物理场在锂电领域,锂枝晶的生长一直是研究的重点,因为它严重影响电池的安全性与性能。今天咱就来唠唠…...
如何为Unity游戏添加自定义功能:BepInEx插件框架的全方位实战指南
如何为Unity游戏添加自定义功能:BepInEx插件框架的全方位实战指南 【免费下载链接】BepInEx Unity / XNA game patcher and plugin framework 项目地址: https://gitcode.com/GitHub_Trending/be/BepInEx BepInEx是一款专为Unity Mono、IL2CPP和.NET框架游戏…...
LIN Switch Method:从硬件革新到软件流程,揭秘车内氛围灯自动寻址的完整闭环
1. 为什么车内氛围灯需要自动寻址技术 十年前的车内照明还停留在基础功能阶段,而现在的高端车型已经将氛围灯玩出了新花样。想象一下,当你打开车门时,迎宾灯像流水一样从车头滑向车尾;调节空调温度时,出风口周围的灯光…...
电子课本下载终极指南:三步完成国家教育平台PDF高效获取
电子课本下载终极指南:三步完成国家教育平台PDF高效获取 【免费下载链接】tchMaterial-parser 国家中小学智慧教育平台 电子课本下载工具 项目地址: https://gitcode.com/GitHub_Trending/tc/tchMaterial-parser 在数字化教育浪潮中,教师和学生面…...
学术符号的生产与思想的停滞——评童世骏《“来往”与“交往”如何形成良性循环》
学术符号的生产与思想的停滞——评童世骏《“来往”与“交往”如何形成良性循环》摘要:本文以岐金兰对童世骏文章的批判为切入点,系统分析童文在学术生产体制中的位置与局限。研究发现,童文虽以哈贝马斯“交往理性”为理论资源,但…...
BiLSTM时间序列预测实战:用Python搞定股票价格预测(附完整代码)
BiLSTM金融时间序列预测:从理论到实战的Python完整指南 金融市场如同汹涌的海浪,价格波动背后隐藏着无数投资者的决策与情绪。对于量化分析师和算法交易者而言,准确预测这些波动意味着巨大的商业价值。传统的时间序列分析方法如ARIMA在面对非…...
10个libxev实战技巧:从定时器到TCP服务器的完整实现
10个libxev实战技巧:从定时器到TCP服务器的完整实现 【免费下载链接】libxev libxev is a cross-platform, high-performance event loop that provides abstractions for non-blocking IO, timers, events, and more and works on Linux (io_uring or epoll), macO…...
IDC行业专家交流纪要
Q:字节 2026 年 IDC 招标的总需求、国内需求、当前招标进度分别是怎样的?此次招标呈现出怎样的特点,背后又有哪些原因?A:字节跳动 2026 年 IDC 招标整体规划总需求约 1.8GW,剔除海外需求削减的部分后&#…...
