当前位置: 首页 > news >正文

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切换很正常&#xff0c;但往往加上写动画更好看 一、思路&#xff1a; 用属性动画&#xff0c;并且事先准备多张图片&#xff0c;用于切换后播放动画 二、效果图&#xff1a; 单纯图看不出来&#xff0c;看下视频效果 An…...

Web前端高级工程师培训:异步处理专题

异步处理专题 课前准备 工具 编辑器 VSCode浏览器 Chorme 前置知识 ES6基础语法 课堂主题 同步及异步概念方块运动的实现promise的用法then的返还值Async 函数 和 await 课堂目标 理解并学会使用promise使用方式以及async 、await的使用 同步异步概念 js是单线程 单线程…...

ESP32-C3实现热点并在浏览器中输入域名访问网页

源代码 #include <WiFi.h> // 引入 WiFi 库&#xff0c;用于处理网络连接 #include <WebServer.h> // 引入 WebServer 库&#xff0c;用于创建 HTTP 服务器 #include <DNSServer.h> // 引入 DNSServer 库&#xff0c;用于处理 DNS 请…...

基于Python的自然语言处理系列(32):spaCy属性扩展

1. 介绍 在 spaCy 中,自定义扩展属性让我们能够为 Doc、Token 和 Span 对象添加元数据。通过这些扩展属性,开发者可以根据需要存储额外的上下文信息,或者动态计算属性值。 自定义属性通过点下划线(dot-underscore)属性访问,例如 token._.is_color。这种命名方式确保这些属…...

STM32 输入捕获模式详解:PWM 输入捕获与 PWI 模式(续篇)

在前两篇文章中&#xff0c;我们探讨了 STM32 输入捕获的基础和 PWI 模式的工作原理&#xff0c;特别是定时器的两个通道如何协同工作以捕获 PWM 信号。本文将进一步结合 STM32 标准库函数中的 TIM_PWMIConfig()&#xff0c;来讲解如何通过库函数配置定时器实现 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. 大纲 动态规划&#xff0c;英文&#xff1a;Dynamic Programm…...

mysql学习教程,从入门到精通,SQL 约束(Constraints)(41)

在数据库设计中&#xff0c;约束&#xff08;Constraints&#xff09;用于确保数据的准确性和完整性。它们通过限制可以插入到数据库表中的数据类型来防止无效数据。SQL 中有几种常见的约束类型&#xff0c;包括主键约束&#xff08;Primary Key&#xff09;、外键约束&#xf…...

使用CSS3与JavaScript实现炫酷的3D旋转魔方及九宫格交换动效

文章目录 前言一、项目需求背景二、CSS3 3D基础知识介绍2.1 什么是CSS3 3D&#xff1f;2.2 主要使用的CSS属性 三、使用HTML和CSS搭建魔方结构四、让魔方动起来&#xff1a;CSS3动画五、九宫格数字交换的JavaScript实现5.1 九宫格布局5.2 随机交换数字 六、随机交换与相邻格子的…...

springboot项目通过maven的profile功能实现通过不同文件夹的方式来组织不同环境配置文件

写在前面 本文看下springboot项目如何通过文件夹的方式来组织不同环境配置文件。 1&#xff1a;正文 一般的我们写springboot项目时配置文件是这个样子的&#xff1a; appliction.yaml --> 通过spring.profiles.activexxx来激活某个指定后缀的配置文件 application-evn1…...

GAN(Generative Adversarial Nets)

GAN(Generative Adversarial Nets) 引言 GAN由Ian J. Goodfellow等人提出&#xff0c;是Ian J. Goodfellow的代表作之一&#xff0c;他还出版了大家耳熟能详的花书&#xff08;Deep Learning深度学习&#xff09;&#xff0c;GAN主要的思想是同时训练两个模型&#xff0c;生成…...

linux下使用mpi求自然数和

搭建MPI并行计算环境&#xff0c;编写 MPI程序&#xff0c;求和 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编程中&#xff0c;attribute变量是一种特殊类型的变量&#xff0c;用于从客户端传递数据到顶点着色器。这些数据通常包括顶点的位置、颜色、纹理坐标等&#xff0c;它们是与每个顶点直接相关的信息。attribute变量在顶点着色器中声明&#xff0c;并且对于每个顶点来说都…...

机器学习四大框架详解及实战应用:PyTorch、TensorFlow、Keras、Scikit-learn

目录 框架概述PyTorch&#xff1a;灵活性与研究首选TensorFlow&#xff1a;谷歌加持的强大生态系统Keras&#xff1a;简洁明了的高层 APIScikit-learn&#xff1a;传统机器学习的必备工具实战案例 图像分类实战自然语言处理实战回归问题实战 各框架的对比总结选择合适的框架 1…...

linux源码安装slurm以及mung和openssl

一、源码安装munge 1、编译安装munge &#xff08;1&#xff09;下载munge地址&#xff1a;https://github.com/dun/munge/releases &#xff08;2&#xff09;解压编译安装&#xff1a; 1 2 3 4 5 6 7 8 创建/data目录 复制文件munge-0.5.15.tar.xz 到/data目录下 tar -Jx…...

分享蓝牙耳机A2DP音频卡顿原因及解决思路

背景 最近一直在更新博客&#xff0c;我觉得写博客有三个好处&#xff0c;一是很多东西时间久了就会忘&#xff0c;记下来方便自己以后回忆和总结&#xff0c;二是记下来可以加深自己对知识的理解&#xff0c;三是可以知识分享&#xff0c;方便他人。 言归正传&#xff0c;今天…...

Mac 下编译 libaom 源码教程

AV1 AV1是一种开放、免版税的视频编码格式&#xff0c;由开放媒体联盟&#xff08;AOMedia&#xff09;开发&#xff0c;旨在提供高压缩效率和优秀的视频质量。AV1支持多种分辨率&#xff0c;包括SD、HD、4K和8K&#xff0c;并适用于视频点播&#xff08;VOD&#xff09;、直播…...

【成品设计】基于Arduino平台的物联网智能灯

《基于Arduino平台的物联网智能灯》 整体功能&#xff1a; 这个任务中要求实现一个物联网智能灯。实际测试环境中要求设备能够自己创建一个热点&#xff0c;连接这个热点后能自动弹出控制界面&#xff08;强制门户&#xff09;。 功能点 基础功能 (60分) 要求作品至少有2个灯…...

安装和配置k8s可视化UI界面dashboard-1.20.6

安装和配置k8s可视化UI界面dashboard-1.20.6 1.环境规划2.初始化服务器1&#xff09;配置主机名2&#xff09;设置IP为静态IP3&#xff09;关闭selinux4&#xff09;配置主机hosts文件5&#xff09;配置服务器之间免密登录6&#xff09;关闭交换分区swap&#xff0c;提升性能7&…...

VLAN:虚拟局域网

VLAN:虚拟局域网 交换机和路由器协同工作后&#xff0c;将原先的一个广播域&#xff0c;逻辑上&#xff0c;切分为多个广播域。 第一步:创建VLAN [SW1]dispaly vlan 查询vlan VID&#xff08;VLAN ID&#xff09;:用来区分和标定不同的vlan 由12位二进制构成 范围: 0-4…...

PowerBI进阶技巧:利用SWITCH函数实现动态自定义排序

1. 为什么需要自定义排序&#xff1f; 在PowerBI报表设计中&#xff0c;数据排序是最基础却最容易被忽视的功能。系统默认提供的升序和降序排列&#xff0c;就像餐厅里只有"辣"和"不辣"两种选项&#xff0c;而实际业务场景往往需要"微辣""中…...

从一次存储故障复盘说起:深入理解FC SAN中WWN、WWPN、WWNN的区别与实战应用

从一次存储故障复盘说起&#xff1a;深入理解FC SAN中WWN、WWPN、WWNN的区别与实战应用 那天凌晨三点&#xff0c;我被一阵急促的电话铃声惊醒。客户的核心数据库集群突然失去存储连接&#xff0c;业务完全停滞。当我赶到现场时&#xff0c;运维团队已经尝试了重启服务器、更换…...

Comsol 锂枝晶模型 “五合一”:探索枝晶生长的多元奥秘

comsol 锂枝晶模型 五合一 单枝晶定向生长、多枝晶定向生长、多枝晶 随机生长只 无序生长随机形核以及雪花枝晶&#xff0c;包含相场、浓度场和电场三种物理场在锂电领域&#xff0c;锂枝晶的生长一直是研究的重点&#xff0c;因为它严重影响电池的安全性与性能。今天咱就来唠唠…...

如何为Unity游戏添加自定义功能:BepInEx插件框架的全方位实战指南

如何为Unity游戏添加自定义功能&#xff1a;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. 为什么车内氛围灯需要自动寻址技术 十年前的车内照明还停留在基础功能阶段&#xff0c;而现在的高端车型已经将氛围灯玩出了新花样。想象一下&#xff0c;当你打开车门时&#xff0c;迎宾灯像流水一样从车头滑向车尾&#xff1b;调节空调温度时&#xff0c;出风口周围的灯光…...

电子课本下载终极指南:三步完成国家教育平台PDF高效获取

电子课本下载终极指南&#xff1a;三步完成国家教育平台PDF高效获取 【免费下载链接】tchMaterial-parser 国家中小学智慧教育平台 电子课本下载工具 项目地址: https://gitcode.com/GitHub_Trending/tc/tchMaterial-parser 在数字化教育浪潮中&#xff0c;教师和学生面…...

学术符号的生产与思想的停滞——评童世骏《“来往”与“交往”如何形成良性循环》

学术符号的生产与思想的停滞——评童世骏《“来往”与“交往”如何形成良性循环》摘要&#xff1a;本文以岐金兰对童世骏文章的批判为切入点&#xff0c;系统分析童文在学术生产体制中的位置与局限。研究发现&#xff0c;童文虽以哈贝马斯“交往理性”为理论资源&#xff0c;但…...

BiLSTM时间序列预测实战:用Python搞定股票价格预测(附完整代码)

BiLSTM金融时间序列预测&#xff1a;从理论到实战的Python完整指南 金融市场如同汹涌的海浪&#xff0c;价格波动背后隐藏着无数投资者的决策与情绪。对于量化分析师和算法交易者而言&#xff0c;准确预测这些波动意味着巨大的商业价值。传统的时间序列分析方法如ARIMA在面对非…...

10个libxev实战技巧:从定时器到TCP服务器的完整实现

10个libxev实战技巧&#xff1a;从定时器到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&#xff1a;字节 2026 年 IDC 招标的总需求、国内需求、当前招标进度分别是怎样的&#xff1f;此次招标呈现出怎样的特点&#xff0c;背后又有哪些原因&#xff1f;A&#xff1a;字节跳动 2026 年 IDC 招标整体规划总需求约 1.8GW&#xff0c;剔除海外需求削减的部分后&#…...