ColorfulNavigationBar

Posted by Csming on 2019-03-16

ColorfulNavigationBar

首先附上github项目地址;https://github.com/csming1995/ColorNavigationBar

之前在github上看到了一个iOS版本的彩色的菜单栏觉得很有趣,于是模仿了一套Android版本的,并且加上了回弹的效果,让动画看起来更流畅。


这个开源库主要是出于兴趣写的,花了差不多一个下午写了一下。应该还有很多漏洞。

效果如下:

先看一下调用者所需要编写的源码;

public class MainActivity extends AppCompatActivity {

private ColorfulNavigation mColorfulNavigation;

private static final int ID_1 = 1;
private static final int ID_2 = 2;
private static final int ID_3 = 3;
private static final int ID_4 = 4;
private static final int ID_5 = 5;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

mColorfulNavigation = findViewById(R.id.colorful_navigation);
mColorfulNavigation.add(new ColorfulNavigation.Item(ID_1, R.drawable.ic_home_black_24dp, R.color.test1, "Item 1"));
mColorfulNavigation.add(new ColorfulNavigation.Item(ID_2, R.drawable.ic_home_black_24dp, R.color.test2, "Item 2"));
mColorfulNavigation.add(new ColorfulNavigation.Item(ID_3, R.drawable.ic_home_black_24dp, R.color.test3, "Item 3"));
mColorfulNavigation.add(new ColorfulNavigation.Item(ID_4, R.drawable.ic_home_black_24dp, R.color.test4, "Item 4"));
mColorfulNavigation.add(new ColorfulNavigation.Item(ID_5, R.drawable.ic_home_black_24dp, R.color.test5, "Item 5"));

mColorfulNavigation.setOnItemSelectedListener(new ColorfulNavigation.OnItemSelectedListener() {
@Override
public void onItemSelected(ColorfulNavigation.Item item) {
// Toast.makeText(MainActivity.this, "" + item.getId(), Toast.LENGTH_SHORT).show();
switch(item.getId()) {
case ID_1 :{
break;
}
case ID_2: {
break;
}
case ID_3 :{
break;
}
case ID_4: {
break;
}
case ID_5: {
break;
}
default:{
break;
}
}
}
});
}
}

这边使用的时候,在获取到ColorfulNavigation实例后,依次将菜单item的信息new出来后add到ColorfulNavigation中。这边的add方法,内部实现如下:

public void add(@NonNull Item item) {
ColorfulNavigationItem colorfulNavigationItem = new ColorfulNavigationItem(getContext());
colorfulNavigationItem.setItem(item);

LayoutParams layoutParams = new LinearLayout.LayoutParams(0, LayoutParams.MATCH_PARENT, 1f);
colorfulNavigationItem.setLayoutParams(layoutParams);
addView(colorfulNavigationItem);

mIndex = mItems.size();
item.index = mIndex;
mItems.add(item);
mColorfulNavigationItems.add(colorfulNavigationItem);

mPaint.setColor(getResources().getColor(item.color));
mRightPaint.setColor(getResources().getColor(item.color));
requestLayout();
}

先说明一下,ColorfulNavigation的是一个继承于LinearLayout的控件,并且Orientation设置为HORIZONTAL,此处创建一个ColorfulNavigationItem的实例,将其LayoutParams设置为:width=0, weight=1;于是加入到ColorfulNavigation之后会将所有的ColorfulNavigationItem作平铺处理。

动画处理

在用户点击到ColorfulNavigationItem的时候会触发动画效果,以及回调事件。

private void startAnimator(int targetIndex) {
boolean isRight = mIndex < targetIndex;
mIndex = targetIndex;
int targetLeft = mItemWidth * mIndex;
if (targetLeft != mRectF.left) {
if (mValueAnimator == null) {
mValueAnimator = new ValueAnimator();
mValueAnimatorListener = new ValueAnimatorListener();
mValueAnimator.addUpdateListener(mValueAnimatorListener);
}
mValueAnimator.setFloatValues(mRectF.left, targetLeft, targetLeft + (isRight? 20: - 20), targetLeft);
mValueAnimator.setDuration(380);
mValueAnimator.cancel();
mValueAnimator.start();
}
}

private class ValueAnimatorListener implements ValueAnimator.AnimatorUpdateListener {

@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
mRectF.left = (float) valueAnimator.getAnimatedValue();
mRectF.right = mRectF.left + mItemWidth;
mDrawIndex = (int) mRectF.left / mItemWidth;
mRightRectF.left = (mDrawIndex + 1) * mItemWidth;
mRightRectF.right = mRectF.right;
mPaint.setColor(getResources().getColor(mItems.get(mDrawIndex).getColor()));
if (mDrawIndex + 1 < mItems.size()){
mRightPaint.setColor(getResources().getColor(mItems.get(mDrawIndex + 1).getColor()));
}
invalidate();
}
}

这边为了维护一个item在navigation中滑动的效果,在ColorfulNavigation,维护了一个RectF用来绘制滑动中的item。RectF的right-left的值永远的等于该item的宽度,而left的值在起点处的item的left与目标item的left值的渐进移动中获得。item的宽度为ColorfulNavigation的总宽度除以item个数。

ok,接着为了维护在item交界处的两种颜色,这边通过下方的计算得到当前矩阵的左边界所在的位置,然后计算出当前矩阵所处在的边界位置,该边界的右边由于矩阵:mRightRectF绘制。:

mDrawIndex =  (int) mRectF.left / mItemWidth;

如果要优化的话,应该将mRectF的右边界设置为矩阵所处在的边界,以减少绘制压力。

该开源库已经上传到github上了;

https://github.com/csming1995/ColorNavigationBar

各种求star~~~