高仿微信底部导航栏, 简单易懂, 代码少

2,478 阅读5分钟
原文链接: blog.csdn.net

这几天在公司没什么工作,闲来没事写了一下关于微信底部渐变的导航,textview 是利用 ArgbEvaluator 实现颜色渐变的效果,图片渐变是自定义imageview 来设置透明度进行渐变的

本代码与其他实现的优越性:

  • 代码简单
  • 容易看懂,对新手来说不是问题
  • 直接可以copy到自己的项目中使用

首先看一下效果图

先了解一下ArgbEvaluator的使用,ArgbEvaluator俗称颜色计算器,举个栗子

 float percentage = (float)i/100; //这个就是根据百分比来计算出颜色
 ArgbEvaluator argb = new ArgbEvaluator();
 int  color = (int)argb.evaluate(percentage, Color.parseColor("#ffffff"),Color.parseColor("#000000"));
 findViewById(R.id.tv_simple).setBackgroundColor(color);

此栗子:当percentage为0的时候:color为纯白色,当percentage为1的时候:color为纯黑色, 当percentage从0-1变化的时候,颜色会从白色到黑色逐渐的变化

先看一自定义控件自定义imageView 不用再xml中设置src或者backgroud

setImages的时候 就会传入两张图片, 一个是正常的,一个是选中状态下的图片. 实际上就是在此imageview上面画图片
在 transformPage的时候,就会根据offset(偏移量)的大小来设置透明度,从而效果为渐变.

public class MyImageView extends ImageView {

private Paint mPaint;
private Bitmap mSelectedIcon;
private Bitmap mNormalIcon;
private Rect mSelectedRect;
private Rect mNormalRect;
private int mSelectedAlpha = 0;

public MyImageView(Context context) {
    super(context);
}

public MyImageView(Context context, AttributeSet attrs) {
    super(context, attrs);
}

public MyImageView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
}

public final void setImages(int normal, int selected) {
    this.mNormalIcon = createBitmap(normal);                            // 拿到原图
    this.mSelectedIcon = createBitmap(selected);
    int width = (int)getResources().getDimension(R.dimen.tab_image_weith);
    int heigh = (int)getResources().getDimension(R.dimen.tab_image_heigh);
    this.mNormalRect = new Rect(0, 0, width, heigh);                   //拿到画板的大小 也就是此控件的大小
    this.mSelectedRect = new Rect(0, 0, width, heigh);
    this.mPaint = new Paint();                                         // 拿到画笔
}

private Bitmap createBitmap(int resId) {
    return BitmapFactory.decodeResource(getResources(), resId);
}

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    if (this.mPaint == null) {
        return;
    }
    this.mPaint.setAlpha(255 - this.mSelectedAlpha);
    canvas.drawBitmap(this.mNormalIcon, null, this.mNormalRect, this.mPaint); //开始在画板上画原图
                                                                            // 也就是在这个控件上画bitmap
    this.mPaint.setAlpha(this.mSelectedAlpha);
    canvas.drawBitmap(this.mSelectedIcon, null, this.mSelectedRect, this.mPaint);
}

public final void changeSelectedAlpha(int alpha) {

}

/**
 * 当viewpager滑动的时候,也就是onPageScrolled调用的时候,再来调用此方法
 * @param offset  偏移量
 */
public final void transformPage(float offset) {
    this.mSelectedAlpha = (int) (255 * (1 - offset));
    invalidate();  // 此方法调用就会从新走 onDraw方法
}
}

之后我们看一下xml中,其实xml布局挺简单的,一看就懂,没错,就是上面一个ViewPgaer 下面一个LinearLayout 里面包裹着

<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="kitrobot.com.wechat_bottom_navigation.MainActivity"
android:orientation="vertical">


<android.support.v4.view.ViewPager
    android:layout_weight="1"
    android:id="@+id/vp"
    android:layout_width="match_parent"
    android:layout_height="0dp"></android.support.v4.view.ViewPager>
<LinearLayout
    android:paddingTop="10dp"
    android:background="#ffffff"
    android:orientation="horizontal"
    android:id="@+id/rg"
    android:layout_width="match_parent"
    android:layout_height="60dp">
        <LinearLayout
            android:id="@+id/ll_home"
            android:layout_weight="1"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:orientation="vertical">
            <kitrobot.com.wechat_bottom_navigation.view.MyImageView
                android:layout_gravity="center"
                android:id="@+id/iv1"
                android:layout_width="30dp"
                android:layout_height="30dp"/>
            <TextView
                android:gravity="center"
                android:text="微信"
                android:button="@null"
                android:id="@+id/rb1"
                android:layout_width="match_parent"
                android:layout_height="match_parent"/>
        </LinearLayout>

        <LinearLayout
            android:id="@+id/ll_categroy"
            android:layout_weight="1"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:orientation="vertical">
            <kitrobot.com.wechat_bottom_navigation.view.MyImageView
                android:layout_gravity="center"
                android:id="@+id/iv2"
                android:layout_width="30dp"
                android:layout_height="30dp"/>
            <TextView
                android:gravity="center"
                android:text="通信录"
                android:button="@null"
                android:id="@+id/rb2"
                android:layout_width="match_parent"
                android:layout_height="match_parent"/>
        </LinearLayout>
        <LinearLayout
            android:id="@+id/ll_find"
            android:layout_weight="1"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:orientation="vertical">
            <kitrobot.com.wechat_bottom_navigation.view.MyImageView
                android:layout_gravity="center"
                android:id="@+id/iv3"
                android:layout_width="30dp"
                android:layout_height="30dp"/>
            <TextView
                android:gravity="center"
                android:text="发现"
                android:button="@null"
                android:id="@+id/rb3"
                android:layout_width="match_parent"
                android:layout_height="match_parent"/>
        </LinearLayout>
        <LinearLayout
            android:id="@+id/ll_mine"
            android:layout_weight="1"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:orientation="vertical">
            <kitrobot.com.wechat_bottom_navigation.view.MyImageView
                android:layout_gravity="center"
                android:id="@+id/iv4"
                android:layout_width="@dimen/tab_image_weith"
                android:layout_height="@dimen/tab_image_heigh"/>
            <TextView
                android:gravity="center"
                android:text="我"
                android:button="@null"
                android:id="@+id/rb4"
                android:layout_width="match_parent"
                android:layout_height="match_parent"/>
        </LinearLayout>
    </LinearLayout>

</LinearLayout>

最后看一下代码的逻辑 你会发现so简单 注释什么的都很全自己看一下绝对ok

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

private ViewPager mViewPager;
private MyImageView mIvHome; // tab 消息的imageview
private TextView mTvHome;   // tab 消息的imageview

private MyImageView mIvCategory; // tab 通讯录的imageview
private TextView mTvCategory;

private MyImageView mIvFind;  // tab 发现的imageview
private TextView mTvFind;

private MyImageView mIvMine; // tab 我的imageview
private TextView mTvMine;

private ArrayList<Fragment> mFragments;
private ArgbEvaluator mColorEvaluator;

private int mTextNormalColor;// 未选中的字体颜色
private int mTextSelectedColor;// 选中的字体颜色
private LinearLayout mLinearLayoutHome;
private LinearLayout mLinearLayoutCategory;
private LinearLayout mLinearLayoutFind;
private LinearLayout mLinearLayoutMine;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    initColor();//也就是选中未选中的textview的color
    initView();// 初始化控件
    initData(); // 初始化数据(也就是fragments)
    initSelectImage();// 初始化渐变的图片
    aboutViewpager(); // 关于viewpager
    setListener(); // viewpager设置滑动监听
}

private void initSelectImage() {
    mIvHome.setImages(R.drawable.home_normal, R.drawable.home_selected);
    mIvCategory.setImages(R.drawable.category_normal, R.drawable.category_selected);
    mIvFind.setImages(R.drawable.find_normal, R.drawable.find_selected);
    mIvMine.setImages(R.drawable.mine_normal, R.drawable.mine_selected);
}

private void initColor() {
    mTextNormalColor = getResources().getColor(R.color.main_bottom_tab_textcolor_normal);
    mTextSelectedColor = getResources().getColor(R.color.main_bottom_tab_textcolor_selected);
}


private void setListener() {
    //下面的tab设置点击监听
    mLinearLayoutHome.setOnClickListener(this);
    mLinearLayoutCategory.setOnClickListener(this);
    mLinearLayoutFind.setOnClickListener(this);
    mLinearLayoutMine.setOnClickListener(this);

    mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPs) {
                setTabTextColorAndImageView(position,positionOffset);// 更改text的颜色还有图片
        }

        @Override
        public void onPageSelected(int position) {
        }

        @Override
        public void onPageScrollStateChanged(int state) {

        }
    });
}


private void setTabTextColorAndImageView(int position, float positionOffset) {
    mColorEvaluator = new ArgbEvaluator();  // 根据偏移量 来得到
    int  evaluateCurrent =(int) mColorEvaluator.evaluate(positionOffset,mTextSelectedColor , mTextNormalColor);//当前tab的颜色值
    int  evaluateThe =(int) mColorEvaluator.evaluate(positionOffset, mTextNormalColor, mTextSelectedColor);// 将要到tab的颜色值
    switch (position) {
        case 0:
            mTvHome.setTextColor(evaluateCurrent);  //设置消息的字体颜色
            mTvCategory.setTextColor(evaluateThe);  //设置通讯录的字体颜色

            mIvHome.transformPage(positionOffset);  //设置消息的图片
            mIvCategory.transformPage(1-positionOffset); //设置通讯录的图片
            break;
        case 1:
            mTvCategory.setTextColor(evaluateCurrent);
            mTvFind.setTextColor(evaluateThe);

            mIvCategory.transformPage(positionOffset);
            mIvFind.transformPage(1-positionOffset);
            break;
        case 2:
            mTvFind.setTextColor(evaluateCurrent);
            mTvMine.setTextColor(evaluateThe);

            mIvFind.transformPage(positionOffset);
            mIvMine.transformPage(1-positionOffset);
            break;

    }
}

private void initData() {
    mFragments = new ArrayList<>();
    mFragments.add(new HomeFragment());
    mFragments.add(new CategoryFragment());
    mFragments.add(new FindFragment());
    mFragments.add(new MineFragment());
}

private void aboutViewpager() {
    MyAdapter myAdapter = new MyAdapter(getSupportFragmentManager(), mFragments);// 初始化adapter
    mViewPager.setAdapter(myAdapter); // 设置adapter
}

private void initView() {
    mLinearLayoutHome = (LinearLayout) findViewById(R.id.ll_home);
    mLinearLayoutCategory = (LinearLayout) findViewById(R.id.ll_categroy);
    mLinearLayoutFind = (LinearLayout) findViewById(R.id.ll_find);
    mLinearLayoutMine = (LinearLayout) findViewById(R.id.ll_mine);
    mViewPager = (ViewPager) findViewById(R.id.vp);
    mIvHome = (MyImageView) findViewById(R.id.iv1);  // tab 微信 imageview
    mTvHome = (TextView) findViewById(R.id.rb1);  //  tab  微信 字

    mIvCategory = (MyImageView) findViewById(R.id.iv2); // tab 通信录 imageview
    mTvCategory = (TextView) findViewById(R.id.rb2);  // tab   通信录 字

    mIvFind = (MyImageView) findViewById(R.id.iv3); // tab 发现 imageview
    mTvFind = (TextView) findViewById(R.id.rb3);   //  tab  发现 字

    mIvMine = (MyImageView) findViewById(R.id.iv4);   // tab 我 imageview
    mTvMine = (TextView) findViewById(R.id.rb4);    // tab   我 字
}

@Override
public void onClick(View view) {
    switch (view.getId()) {
        case R.id.ll_home:
            mViewPager.setCurrentItem(0);
            break;
        case R.id.ll_categroy:
            mViewPager.setCurrentItem(1);
            break;
        case R.id.ll_find:
            mViewPager.setCurrentItem(2);
            break;
        case R.id.ll_mine:
            mViewPager.setCurrentItem(3);
            break;
    }
}

}

有的同学会问:为什么不用初始化tab字体的颜色和imageview的图片的,其实这个我也是最近才发现的,当界面完成的时候,viewpager会自动加载第一页而此时的ViewPager.OnPageChangeListener中的 onPageScrolled 会自动的执行一次,其他的方法不会去执行

最后献上源码位置

github:wechat-Bottom-navigation
欢迎star