Android开发首页底部tab切换图标有动画效果

news2024/11/26 20:25:45
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);
    }

    @Override
    protected 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);
        }
    }


    @Override
    public 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() {
            @Override
            public 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());
    }

    @Override
    protected 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源码结构图:

在这里插入图片描述
有问题或者需要完整源码的私信我

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

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

相关文章

slam系列2:刚体坐标变换

线性代数的基础知识参考这篇&#xff1a;https://xin1999.blog.csdn.net/article/details/124779288 1. 刚体变换 刚体变换仅有旋转平移功能&#xff0c;矩阵模式表达为&#xff1a; a ′ R a t aRat a′Rat 齐次坐标就是在原n维坐标表示上增加了一个维度&#xff0c;使用n…

# 执行 rpm -qa | grep qq 查询软件安装情况时报错 数据库损坏 db3 error(-30974)

执行 rpm -qa | grep qq 查询软件安装情况时报错 数据库损坏 db3 error(-30974) 一、问题描述&#xff1a; 在 linux 系统上&#xff0c;使用包管理工具 rpm 查询某一个软件安装情况&#xff0c;如&#xff1a;执行 rpm -qa | grep qq 时&#xff0c;报错 数据库损坏 db3 err…

【升华】一个简单而标准的接口定义格式

一、前言 每天都在写很多接口&#xff0c;有的是有设计的接口&#xff0c;有的是无设计的接口。如果接口没有进行设计&#xff0c;也没有设计文档后期将很难扩展和维护。那么怎么简单定义一个简单而标准的Java的接口呢。下面给出格式。 二、JAVA接口设计文档 一个接口的定义一…

心觉:能让孩子卷则卷,但是度一定要把握好

Hi&#xff0c;我是心觉&#xff0c;与你一起玩转潜意识、脑波音乐和吸引力法则&#xff0c;轻松掌控自己的人生&#xff01; 挑战每日一省写作198/1000天 现在家长普遍想让孩子考个好的学校&#xff0c;上好的幼儿园、小学、初中、高中甚至大学 为了上一个好的学校&#xf…

智能电子后视镜,汽车驾驶更安全,会是一种趋势

相比于传统的后视镜&#xff0c;智能电子后视镜的确有很多的优点。在下雨天和夜晚场景&#xff0c;电子后视镜可以说是表现优秀。 我之前一直以为我们国内是有规定不能使用电子后视镜。没想到&#xff0c;偶然刷到享界S9的视频&#xff0c;这电子后视镜&#xff0c;妥妥的给安排…

QD1-P21-P22 CSS 基础语法、注释、使用方法

本节学习&#xff1a;CSS 基础语法和注释&#xff0c;以及如何使用CSS定义的样式。 本节视频 https://www.bilibili.com/video/BV1n64y1U7oj?p21 CSS 基本语法 CSS&#xff08;层叠样式表&#xff09;的基本语法相对简单&#xff0c;由选择器和一组包含在花括号 {}​ 中的声…

研发线上事故风险解读之缓存篇

专业在线打字练习平台-巧手打字通&#xff0c;只输出有价值的知识。 一 前言 本文继续基于《线上事故案例集》&#xff0c;进一步深入梳理线上事故缓存使用方面的问题点&#xff0c;重点关注缓存在使用和优化过程中可能出现的问题&#xff0c;旨在为读者提供具有实践指导意义的…

矩形函数的傅里叶变换——从一维到二维,从连续到离散

一维连续矩形函数的傅里叶变换 二维连续矩形函数的傅里叶变换 禹晶、肖创柏、廖庆敏《数字图像处理&#xff08;面向新工科的电工电子信息基础课程系列教材&#xff09;》P109 2D DFT 禹晶、肖创柏、廖庆敏《数字图像处理&#xff08;面向新工科的电工电子信息基础课程系…

java计算机毕设课设—俄罗斯方块游戏(附源码、文章、相关截图、部署视频)

这是什么系统&#xff1f; 资源获取方式再最下方 java计算机毕设课设—俄罗斯方块游戏(附源码、文章、相关截图、部署视频) 基于Java的俄罗斯方块游戏&#xff0c;以提供一种既具娱乐性又具挑战性的游戏体验。通过精心设计的游戏界面和控制功能&#xff0c;该游戏不仅能够满…

STM32G474硬件I2C之配置方法

STM32G474硬件I2C接口&#xff1a;英文Inter-integrated circuit简写为I2C。STM32G474是M4核&#xff0c;在使用硬件I2C时&#xff0c;配置方法和M3核相差较大。通过阅读参考手册和HAL&#xff0c;总算了解了其配置原理。 1、I2C工作模式 I2C标准模式&#xff1a;最高时钟频率…

使用HTML和CSS实现3D波浪动画效果

使用HTML和CSS实现3D波浪动画效果 在本篇博客中&#xff0c;将详细介绍如何使用HTML与CSS创建一个3D波浪动画效果。这个效果不仅能够在网页中创建立体感强的视觉体验&#xff0c;还能够通过悬停和聚焦实现与用户的交互。我们将逐步解析代码中的每个部分&#xff0c;帮助你掌握…

探索Theine:Python中的AI缓存新贵

文章目录 探索Theine&#xff1a;Python中的AI缓存新贵背景&#xff1a;为何选择Theine&#xff1f;Theine是什么&#xff1f;如何安装Theine&#xff1f;简单的库函数使用方法场景应用场景一&#xff1a;Web应用缓存场景二&#xff1a;分布式系统中的数据共享场景三&#xff1…

使用WordPress从零开始搭建一个本地网站实现远程访问

文章目录 前言1. 安装WordPress2. 创建WordPress数据库3. 安装相对URL插件4. 安装内网穿透发布网站4.1 命令行方式&#xff1a;4.2. 配置wordpress公网地址 5. 配置WordPress固定公网地址 前言 本文主要介绍如何在Linux Ubuntu系统上使用WordPress搭建一个本地网站&#xff0c…

C语言网络编程深入研究

网络编程是现代软件开发中的一个重要部分&#xff0c;它允许不同计算机之间相互通信和交换数据。本指南将深入探讨使用C语言进行网络编程的技术细节&#xff0c;特别是TCP/IP协议族的核心概念和技术实现。我们将通过具体的代码示例来讨论如何创建客户端和服务器程序&#xff0c…

渗透测试 之 AD域渗透 【Kerberoasting】 攻击技术讲解 对应得工具详细介绍哟~ 以及相关示例 按照步骤做你也会哟

说明 Kerberoasting 攻击发生在Kerberos协议的TGS_REP阶段&#xff0c;KDC的TGS服务返回一个由服务Hash加密的ST给客户端。由于该ST是用服务Hash进行加密的&#xff0c;因此客户端在拿到该ST后可以用于本地离线爆破。 攻击的过程 攻击者提供一个正常的域用户密码对域进行身份…

拆解学习【STC宏晶MCU-CM1020电池保护】(一)

MIJIA米家USB-C充气宝1S: 米家这款充气宝内置2串18650锂电池为电机和控制板供电。控制板采用STC宏晶MCU进行气压测量和电机控制以及压力显示&#xff0c;内部电池保护板采用创芯微CM1020进行电池保护&#xff0c;并采用捷捷微MOS管进行开关控制。 LED数码管采用贴片LED二极管…

NVM 切换Node.js版本工具

大家好我是苏麟&#xff0c;今天聊聊NVM切换版本工具。 切换 node 版本工具 &#xff1a; GitHub - nvm-sh/nvm: Node Version Manager - POSIX-compliant bash script to manage multiple active node.js versions 查看node版本 node -v 查看 nvm 版本 nvm -v 查看可安装的Nod…

JavaScript进阶笔记--深入对象-内置构造函数及案例

深入对象 创建对象三种方式 利用对象字面量new Object&#xff08;{…}&#xff09;利用构造函数 // 1. 字面量创建对象const obj1 {name: pig,age: 18};console.log(obj1); // {name: "pig", age: 18}// 2. 构造函数创建对象function Pig(name, age) {this.name…

RVIZ2可视化移动机器人模型

RVIZ2可视化移动机器人模型 上一节讲完joint和link&#xff0c;我们来把我们上面定义的简单的URDF(包含身体和雷达)用RVIZ2显示出来&#xff0c;直观的感受下&#xff0c;我们的机器人模型。 URDF可视化的步骤如下&#xff1a; 1建立机器人描述功能包 2建立urdf文件夹编写…

子组件向父组件传值$emit

点击子组件的按钮&#xff0c;将子组件的值传递给父组件&#xff0c;并进行提示。 子组件 <template><div><button click"emitIndex">clickme</button></div> </template> <script> export default {methods: {emitInde…