原创作者:AchillesL
若转载文章,请在明显的位置标明文章出处
1. 前言
使用微信时,我们会发现:进行页面切换时,底部标题栏的图片会发生颜色深浅的变化。
本文将介绍这种效果是如何实现的,最终效果如图1所示。
2. 知识点
ArgbEvaluator.evaluate方法:
该方法用于根据一个起始颜色值和一个结束颜色值以及一个偏移量生成一个新的颜色。
DrawableCompat.setTintList方法:
通过该方法,可以动态地给图片进行着色处理。对于具体的用法,可以参考一下文章:http://www.jianshu.com/p/6bd7dd1cd491 本文不再讲述。
3. 准备工作
我们创建一个Demo。Activity中包含一个ViewPager控件,并利用LinearLayout实现底部标题栏。
布局代码:
主界面代码:
package com.achillesl.bottombar;
import android.content.res.ColorStateList;
import android.graphics.drawable.Drawable;
import android.support.v4.content.ContextCompat;
import android.support.v4.graphics.drawable.DrawableCompat;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private ViewPager mViewPager;
private List mTipList = new ArrayList<>();
//使用List存放ImageView对象
private List mBottomImageViews = new ArrayList<>();
//使用List存放ImageView对应的图片资源
private List mBottomImageDrawables = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initTipList();
initImageViewDrawable();
// TODO: 2016/11/13 设置ViewPager的页面数
mViewPager = (ViewPager) findViewById(R.id.viewPager);
mViewPager.setAdapter(new PagerAdapter() {
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView(mTipList.get(position));
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
TextView textView = mTipList.get(position);
container.addView(textView);
return textView;
}
@Override
public int getCount() {
return 4;
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
});
}
private void initImageViewDrawable() {
mBottomImageViews.add((ImageView) findViewById(R.id.ivOne));
mBottomImageViews.add((ImageView) findViewById(R.id.ivTwo));
mBottomImageViews.add((ImageView) findViewById(R.id.ivThree));
mBottomImageViews.add((ImageView) findViewById(R.id.ivFour));
mBottomImageDrawables.add(ContextCompat.getDrawable(this,R.drawable.ic_action_alarm).mutate());
mBottomImageDrawables.add(ContextCompat.getDrawable(this,R.drawable.ic_action_amazon).mutate());
mBottomImageDrawables.add(ContextCompat.getDrawable(this,R.drawable.ic_action_anchor).mutate());
mBottomImageDrawables.add(ContextCompat.getDrawable(this,R.drawable.ic_action_android).mutate());
}
private void initTipList() {
ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams
.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
for (int i = 0; i < 4; i++) {
TextView textView = new TextView(this);
textView.setText("第" + (i + 1) + "个页面");
textView.setLayoutParams(layoutParams);
textView.setGravity(Gravity.CENTER);
mTipList.add(textView);
}
}
}
上面代码中,我们使用List统一管理图片资源、ImageView实例。
4. 颜色渐变
4.1 设置图标初始颜色
这一步,我们将设置底部标题栏图标的颜色。选择的颜色为蓝色,未选中的蓝色为灰色。
4.1.1 定义并初始化颜色
在color.xml文件中定义颜色
#3F51B5
#a4a3a3
4.1.2 在Activity中添加变量
private int mBottomColorSelect;
private int mBottomColorUnSelect;
4.1.3 设置不同图标的颜色
添加setImageViewSelect方法,代码如下:
private void setImageViewSelect(int selectIndex) {
for (int index = 0; index < mBottomImageViews.size(); index++) {
ImageView imageView = mBottomImageViews.get(index);
Drawable drawable = mBottomImageDrawables.get(index);
if (index == selectIndex) {
imageView.setImageDrawable(tintDrawable(drawable, ColorStateList.valueOf
(mBottomColorSelect)));
} else {
imageView.setImageDrawable(tintDrawable(drawable, ColorStateList.valueOf
(mBottomColorUnSelect)));
}
}
}
4.1.4 修改initImageViewDrawable方法
private void initImageViewDrawable() {
/*Add begin*/
mBottomColorSelect = ContextCompat.getColor(this, R.color.buttonSelect);
mBottomColorUnSelect = ContextCompat.getColor(this, R.color.buttonUnSelect);
/*Add end*/
mBottomImageViews.add((ImageView) findViewById(R.id.ivOne));
...
mBottomImageDrawables.add(ContextCompat.getDrawable(this,R.drawable.ic_action_android).mutate());
/*Add begin*/
setImageViewSelect(0);
/*Add end*/
}
此时,完成了底部栏图标的初始化,如图2所示。
4.2 设置ViewPager滑动监听
这时,我们需要给ViewPager添加滑动监听事件,并且可以联想到:颜色的渐变,应该与ViewPager的滑动距离有关。
因此,在监听器的onPageScrolled方法中添加changeImageViewDrawable方法,根据ViewPager的滑动偏移量,动态改变图标的颜色。
mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
changeImageViewDrawable(position,positionOffset);
}
@Override
public void onPageSelected(int position) {
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
4.2.1 编写changeImageViewDrawable方法
这一步主要用到ArgbEvaluator类的evaluate方法,该方法的用法很简单:
public Object evaluate(float fraction, Object startValue, Object endValue)
参数fraction:
指起始颜色到目标颜色的偏移值。该值我们用ViewPager的页面偏移值positionOffset传入。
参数startValue:起始颜色
参数endValue:目标颜色
changeImageViewDrawable方法的代码:
private void changeImageViewDrawable(int position, float positionOffset) {
ImageView ivFrom = null;
ImageView ivTo = null;
Drawable drawableFrom = null;
Drawable drawableTo = null;
ivFrom = mBottomImageViews.get(position);
drawableFrom = mBottomImageDrawables.get(position);
if (position != mBottomImageDrawables.size() - 1) {
ivTo = mBottomImageViews.get(position + 1);
drawableTo = mBottomImageDrawables.get(position + 1);
} else {
ivTo = null;
drawableTo = null;
}
if (ivFrom != null) {
int colorStart = (int) mArgbEvaluator.evaluate(positionOffset, mBottomColorSelect,
mBottomColorUnSelect);
Drawable drawableColorStart = tintDrawable(drawableFrom, ColorStateList.valueOf
(colorStart));
ivFrom.setImageDrawable(drawableColorStart);
}
if (ivTo != null) {
int colorStart = (int) mArgbEvaluator.evaluate(positionOffset, mBottomColorUnSelect,
mBottomColorSelect);
Drawable drawableColorEnd = tintDrawable(drawableTo, ColorStateList.valueOf
(colorStart));
ivTo.setImageDrawable(drawableColorEnd);
}
}
3 小问题优化
实现具体业务时,往往点击底部标题栏的图片时,需要切换到具体的页面。细心的同学可能会发现,若起始按钮与目标按钮相隔较远时,其他按钮图片上可能遗留“残影”。
解决这个问题很简单,只要在ViewPager页面切换完成时,再一次延时设置底部图标的颜色就可以了。
@Override
public void onPageSelected(final int position) {
handler.postDelayed(new Runnable() {
@Override
public void run() {
setImageViewSelect(position);
}
},DELAY_TIME);
}
全部代码
package com.achillesl.bottombar;
import android.animation.ArgbEvaluator;
import android.content.res.ColorStateList;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.support.v4.content.ContextCompat;
import android.support.v4.graphics.drawable.DrawableCompat;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private ViewPager mViewPager;
private List mTipList = new ArrayList<>();
//使用List存放ImageView对象
private List mBottomImageViews = new ArrayList<>();
//使用List存放ImageView对应的图片资源
private List mBottomImageDrawables = new ArrayList<>();
private ArgbEvaluator mArgbEvaluator = new ArgbEvaluator();
private int mBottomColorSelect;
private int mBottomColorUnSelect;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initTipList();
initImageViewDrawable();
// TODO: 2016/11/13 设置ViewPager的页面数
mViewPager = (ViewPager) findViewById(R.id.viewPager);
mViewPager.setAdapter(new PagerAdapter() {
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView(mTipList.get(position));
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
TextView textView = mTipList.get(position);
container.addView(textView);
return textView;
}
@Override
public int getCount() {
return 4;
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
});
mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
private final int DELAY_TIME = 100;
private Handler handler = new Handler();
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
changeImageViewDrawable(position,positionOffset);
}
@Override
public void onPageSelected(final int position) {
handler.postDelayed(new Runnable() {
@Override
public void run() {
setImageViewSelect(position);
}
},DELAY_TIME);
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
}
private void changeImageViewDrawable(int position, float positionOffset) {
ImageView ivFrom = null;
ImageView ivTo = null;
Drawable drawableFrom = null;
Drawable drawableTo = null;
ivFrom = mBottomImageViews.get(position);
drawableFrom = mBottomImageDrawables.get(position);
if (position != mBottomImageDrawables.size() - 1) {
ivTo = mBottomImageViews.get(position + 1);
drawableTo = mBottomImageDrawables.get(position + 1);
} else {
ivTo = null;
drawableTo = null;
}
if (ivFrom != null) {
int colorStart = (int) mArgbEvaluator.evaluate(positionOffset, mBottomColorSelect,
mBottomColorUnSelect);
Drawable drawableColorStart = tintDrawable(drawableFrom, ColorStateList.valueOf
(colorStart));
ivFrom.setImageDrawable(drawableColorStart);
}
if (ivTo != null) {
int colorStart = (int) mArgbEvaluator.evaluate(positionOffset, mBottomColorUnSelect,
mBottomColorSelect);
Drawable drawableColorEnd = tintDrawable(drawableTo, ColorStateList.valueOf
(colorStart));
ivTo.setImageDrawable(drawableColorEnd);
}
}
private void initImageViewDrawable() {
/*Add begin*/
mBottomColorSelect = ContextCompat.getColor(this, R.color.buttonSelect);
mBottomColorUnSelect = ContextCompat.getColor(this, R.color.buttonUnSelect);
/*Add end*/
mBottomImageViews.add((ImageView) findViewById(R.id.ivOne));
mBottomImageViews.add((ImageView) findViewById(R.id.ivTwo));
mBottomImageViews.add((ImageView) findViewById(R.id.ivThree));
mBottomImageViews.add((ImageView) findViewById(R.id.ivFour));
mBottomImageDrawables.add(ContextCompat.getDrawable(this,R.drawable.ic_action_alarm).mutate());
mBottomImageDrawables.add(ContextCompat.getDrawable(this,R.drawable.ic_action_amazon).mutate());
mBottomImageDrawables.add(ContextCompat.getDrawable(this,R.drawable.ic_action_anchor).mutate());
mBottomImageDrawables.add(ContextCompat.getDrawable(this,R.drawable.ic_action_android).mutate());
for (int i = 0; i < mBottomImageViews.size(); i++) {
ImageView imageView = mBottomImageViews.get(i);
final int index = i;
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mViewPager.setCurrentItem(index);
}
});
}
/*Add begin*/
setImageViewSelect(0);
/*Add end*/
}
private void setImageViewSelect(int selectIndex) {
for (int index = 0; index < mBottomImageViews.size(); index++) {
ImageView imageView = mBottomImageViews.get(index);
Drawable drawable = mBottomImageDrawables.get(index);
if (index == selectIndex) {
imageView.setImageDrawable(tintDrawable(drawable, ColorStateList.valueOf
(mBottomColorSelect)));
} else {
imageView.setImageDrawable(tintDrawable(drawable, ColorStateList.valueOf
(mBottomColorUnSelect)));
}
}
}
public Drawable tintDrawable(Drawable drawable, ColorStateList colors) {
final Drawable wrappedDrawable = DrawableCompat.wrap(drawable);
DrawableCompat.setTintList(wrappedDrawable, colors);
return wrappedDrawable;
}
private void initTipList() {
ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams
.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
for (int i = 0; i < 4; i++) {
TextView textView = new TextView(this);
textView.setText("第" + (i + 1) + "个页面");
textView.setLayoutParams(layoutParams);
textView.setGravity(Gravity.CENTER);
mTipList.add(textView);
}
}
}
代码地址
https://github.com/AchillesLzg/jianshu-weixinbottombar