流暢切換的彩色選單欄:ColorfulNavigationBar

csming1995發表於2019-03-16

ColorfulNavigationBar

首先附上github專案地址;github.com/csming1995/…

之前在github上看到了一個iOS版本的彩色的選單欄覺得很有趣,於是模仿了一套Android版本的,並且加上了回彈的效果,讓動畫看起來更流暢。


這個開源庫主要是出於興趣寫的,花了差不多一個下午寫了一下。應該還有很多漏洞。

效果如下:

流暢切換的彩色選單欄:ColorfulNavigationBar

先看一下呼叫者所需要編寫的原始碼;

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上了;

github.com/csming1995/…

各種求star~~~

相關文章