先看一下马蜂窝的样式
我刚看到觉得下面的样式好神奇,自己就像动手做一做。
由于数学方面我不是很精通,我的实现方式没有复杂的公式计算,而是通过绘制+覆盖的形式。
自己写一个TabLayout过于麻烦,这里就借用了MaterialDesign 的TabLayout改动了其中的draw的代码;
这里绘制路径主要用的是贝塞尔曲线不了解的可以先去网上搜下用法
1.首先设置Paint绘制线条
int lineWidth = 8;
paint.setColor(Color.RED);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(lineWidth);
2.TabLayout中又一个方法可以计算出每个tab的边界坐标
private void calculateTabViewContentBounds(
@NonNull TabView tabView, @NonNull RectF contentBounds) {
int tabViewContentWidth = tabView.getContentWidth();
int minIndicatorWidth = (int) ViewUtils.dpToPx(getContext(), MIN_INDICATOR_WIDTH);
if (tabViewContentWidth < minIndicatorWidth) {
tabViewContentWidth = minIndicatorWidth;
}
int tabViewCenter = (tabView.getLeft() + tabView.getRight()) / 2;
int contentLeftBounds = tabViewCenter - (tabViewContentWidth / 2);
int contentRightBounds = tabViewCenter + (tabViewContentWidth / 2);
contentBounds.set(contentLeftBounds, 0, contentRightBounds, 0);
}
3.从起点开始绘制所有Tab的底部曲线
//设置本文的宽度默认为100,后期可以自己根据情况进行设置
int total = 100;
for (int i = 0; i < getTabCount(); i++) {
View tabView = getChildAt(i);
calculateTabViewContentBounds((TabView) tabView, tabViewContentBounds);
int left = (int) tabViewContentBounds.left;
int right = (int) tabViewContentBounds.right;
//底部曲线起点、终点距Tab边界的距离
smDim = (right - left - total) / 2;
//绘制第一个tab的曲线
if (i == 0) {
//移动到曲线绘制起点
mPath.moveTo(left + smDim, startY);
//开始规划路径
mPath.rQuadTo(total / 2, indicatorHeight / 2, total, 0);
} else {
int cx = smDim + (left - lastRight) / 2;
//绘制两个tab之间的曲线
mPath.rQuadTo(cx, -indicatorHeight + lineWidth, smDim + lastsmDim + (left - lastRight), 0);
//绘制tab下面的曲线
mPath.rQuadTo(total / 2, indicatorHeight / 2, total, 0);
}
//记录上次的边界坐标
lastRight = right;
lastsmDim = smDim;
}
//开始绘制路径 canvas.drawPath(mPath, paint);
这样整个tab下面的曲线就完成了,如下图所示:
4.开始绘制中遮罩层,覆盖曲线只留下当前位置tab的总宽度
blockPaint.setStyle(Paint.Style.FILL);
blockPaint.setColor(Color.parseColor("#f8f8f8"));
int dimen = (indicatorRight - indicatorLeft - total) / 2;
canvas.drawRect(0, indicatorTop, indicatorLeft + dimen, indicatorBottom, blockPaint);
canvas.drawRect(indicatorRight - dimen, indicatorTop, getWidth(), indicatorBottom, blockPaint);
根据tab的移动 动态绘制遮罩层就实现了曲线移动的视觉
最终实现结果如下图所示:
这里有一个问题就是当两个相邻tab的宽度相差比较大的时候曲线在某一点拐点比较生硬。
当然如果数学功底比较好的,可以根据坐标计算出贝塞尔曲线在某一点的坐标值,这样可能会解决上面的问题。
如果有更好的方法还请多多指教;
Demo 地址