Android进阶:手把手教你实现高仿微信底部导航栏动画

// tab_layout.xml

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android=“http://schemas.android.com/apk/res/android”

android:layout_width=“match_parent”

android:layout_height=“40dp”

android:gravity=“center_horizontal”

android:orientation=“vertical”>

<FrameLayout

android:layout_width=“wrap_content”

android:layout_height=“0dp”

android:layout_weight=“1”>

<ImageView

android:id=“@+id/tab_image”

android:layout_width=“wrap_content”

android:layout_height=“match_parent” />

<ImageView

android:id=“@+id/tab_image_top”

android:layout_width=“wrap_content”

android:layout_height=“match_parent” />

<TextView

android:id=“@+id/tab_title”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:textSize=“12sp” />

android:id=“@+id/tab_title"的TextView显示标题。android:id=”@+id/tab_image"的ImageView显示的是一个轮廓图片,也就是未选中时候的图片。android:id=“@+id/tab_image_top"的ImageView在android:id=”@+id/tab_image"的ImageView之上,显示的是选中时候的图片。轮廓图片和选中的图片,可以看下如下的图片例子

第一图片就是轮廓图片,第二个图片就是选中后的图片。为什么布局要这么设计呢?这当然是根据微信的动画而设计的布局(废话!),首先默认显示的是轮廓图片,当接收到一个进度值后,会让轮廓图片的轮廓变色,当进度值超过某个阈值的时候,让轮廓图片的透明度渐渐变为0(也就是完全透明,看不见),而让选中的图片的透明度渐渐变为255(也就是慢慢变清晰)。

TabView

既然知道了变色的原理,现在就来写TabView的代码吧。首先为TabView抽取自定义属性

// res/values/tabview_attrs.xml

<?xml version="1.0" encoding="utf-8"?>
  • tabColor代表变色最终显示的颜色。

  • tabImage代表默认显示的轮廓图。

  • tabSelectedImage代表选中后的图。

  • tabTitle代表要显示的标题。

然后,在TabView中加载布局,并且获取自定义属性

public TabView(Context context, @Nullable AttributeSet attrs) {

super(context, attrs);

// 加载布局

inflate(context, R.layout.tab_layout, this);

TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TabView);

for (int i = 0; i < a.getIndexCount(); i++) {

int attr = a.getIndex(i);

switch (attr) {

case R.styleable.TabView_tabColor:

// 获取标题和轮廓最终的着色

mTargetColor = a.getColor(attr, DEFAULT_TAB_TARGET_COLOR);

break;

case R.styleable.TabView_tabImage:

// 获取轮廓图

mNormalDrawable = a.getDrawable(attr);

break;

case R.styleable.TabView_tabSelectedImage:

// 获取选中图

mSelectedDrawable = a.getDrawable(attr);

break;

case R.styleable.TabView_tabTitle:

// 获取标题

mTitle = a.getString(attr);

break;

}

}

a.recycle();

}

当加载完布局后,需要为各个控件设置相应的属性

@Override

protected void onFinishInflate() {

super.onFinishInflate();

// 1.设置标题,默认着色为黑色

mTitleView = findViewById(R.id.tab_title);

mTitleView.setTextColor(DEFAULT_TAB_COLOR);

mTitleView.setText(mTitle);

// 2.设置轮廓图片,不透明,默认着色为黑色

mNormalImageView = findViewById(R.id.tab_image);

mNormalDrawable.setTint(DEFAULT_TAB_COLOR);

mNormalDrawable.setAlpha(255);

mNormalImageView.setImageDrawable(mNormalDrawable);

// 3.设置选中图片,透明,默认着色为黑色

mSelectedImageView = findViewById(R.id.tab_selected_image);

mSelectedDrawable.setAlpha(0);

mSelectedImageView.setImageDrawable(mSelectedDrawable);

}

第二步中,为轮廓图调用了Drawable.setTint()方法为轮廓着色,默认着色为黑色。

Drawable.setTint() 其实就是利用 PorterDuff.Mode.DST_IN 来进行颜色混合。

然后我还需要一个接收进度值(范围为0.f 到 1.f)的方法,从而利用这个进度值做动画

/**

  • 根据进度值进行变色和透明度处理。

  • @param percentage 进度值,取值[0, 1]。

*/

public void setXPercentage(float percentage) {

if (percentage < 0 || percentage > 1) {

return;

}

// 1. 颜色变换

int finalColor = evaluate(percentage, DEFAULT_TAB_COLOR, mTargetColor);

mTitleView.setTextColor(finalColor);

mNormalDrawable.setTint(finalColor);

// 2. 透明度变换

if (percentage >= 0.5 && percentage <= 1) {

// 原理如下

// 进度值: 0.5 ~ 1

// 透明度: 0 ~ 1

// 公式: percentage - 1 = (alpha - 1) * 0.5

int alpha = (int) Math.ceil(255 * ((percentage - 1) * 2 + 1));

mNormalDrawable.setAlpha(255 - alpha);

mSelectedDrawable.setAlpha(alpha);

} else {

mNormalDrawable.setAlpha(255);

mSelectedDrawable.setAlpha(0);

}

// 3. 更新UI

invalidateUI();

}

第一步是根据进度值来计算颜色值。在属性动画中,有一个ArgbEvaluator类,这是一个对颜色做动画的类,它里面有一个方法如下

public Object evaluate(float fraction, Object startValue, Object endValue) {

int startInt = (Integer) startValue;

float startA = ((startInt >> 24) & 0xff) / 255.0f;

float startR = ((startInt >> 16) & 0xff) / 255.0f;

float startG = ((startInt >> 8) & 0xff) / 255.0f;

float startB = ( startInt & 0xff) / 255.0f;

int endInt = (Integer) endValue;

float endA = ((endInt >> 24) & 0xff) / 255.0f;

float endR = ((endInt >> 16) & 0xff) / 255.0f;

float endG = ((endInt >> 8) & 0xff) / 255.0f;

float endB = ( endInt & 0xff) / 255.0f;

// convert from sRGB to linear

startR = (float) Math.pow(startR, 2.2);

startG = (float) Math.pow(startG, 2.2);

startB = (float) Math.pow(startB, 2.2);

endR = (float) Math.pow(endR, 2.2);

endG = (float) Math.pow(endG, 2.2);

endB = (float) Math.pow(endB, 2.2);

// compute the interpolated color in linear space

float a = startA + fraction * (endA - startA);

float r = startR + fraction * (endR - startR);

float g = startG + fraction * (endG - startG);

float b = startB + fraction * (endB - startB);

// convert back to sRGB in the [0…255] range

a = a * 255.0f;

r = (float) Math.pow(r, 1.0 / 2.2) * 255.0f;

作者2013年从java开发,转做Android开发,在小厂待过,也去过华为,OPPO等大厂待过,18年四月份进了阿里一直到现在。

参与过不少面试,也当面试官 面试过很多人。深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长,而且极易碰到天花板技术停滞不前!

我整理了一份阿里P7级别的最系统的Android开发主流技术,特别适合有3-5年以上经验的小伙伴深入学习提升。

主要包括阿里,以及字节跳动,腾讯,华为,小米,等一线互联网公司主流架构技术。如果你想深入系统学习Android开发,成为一名合格的高级工程师,可以收藏一下这些Android进阶技术选型

我搜集整理过这几年阿里,以及腾讯,字节跳动,华为,小米等公司的面试题,把面试的要求和技术点梳理成一份大而全的“ Android架构师”面试 Xmind(实际上比预期多花了不少精力),包含知识脉络 + 分支细节。

Java语言与原理;
大厂,小厂。Android面试先看你熟不熟悉Java语言

高级UI与自定义view;
自定义view,Android开发的基本功。

性能调优;
数据结构算法,设计模式。都是这里面的关键基础和重点需要熟练的。

NDK开发;
未来的方向,高薪必会。

前沿技术;
组件化,热升级,热修复,框架设计

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

我在搭建这些技术框架的时候,还整理了系统的高级进阶教程,会比自己碎片化学习效果强太多,CodeChina上可见;

当然,想要深入学习并掌握这些能力,并不简单。关于如何学习,做程序员这一行什么工作强度大家都懂,但是不管工作多忙,每周也要雷打不动的抽出 2 小时用来学习。

不出半年,你就能看出变化!
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!
ibifz0-1714764169965)]

前沿技术;
组件化,热升级,热修复,框架设计

[外链图片转存中…(img-FB512kCM-1714764169966)]

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

我在搭建这些技术框架的时候,还整理了系统的高级进阶教程,会比自己碎片化学习效果强太多,CodeChina上可见;

当然,想要深入学习并掌握这些能力,并不简单。关于如何学习,做程序员这一行什么工作强度大家都懂,但是不管工作多忙,每周也要雷打不动的抽出 2 小时用来学习。

不出半年,你就能看出变化!
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!

  • 13
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值