ColorfulNavigationBar
首先附上github專案地址;github.com/csming1995/…
之前在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上了;
各種求star~~~