先看一下读书APP的效果:
弹窗往下滑动时,顶部的指示条也会跟着向下曲折变成箭头形状。
剖析
话不多说,先来给指示条做个X光查看看看:
- 未滑动时指示条便是一个一般的圆角矩形
- 滑动时是一个箭头,箭头的两端是两个圆
指示条从点S
滑动到点T
过程中,圆L
和圆K
的切线相交构成箭头。箭头通过Path
把圆心L
、点T
、圆心K
衔接起来,角落处还需要处理为圆角,可以运用Paint
的setStrokeJoin()
办法,该办法设置线段衔接处的款式,取值有三个:
Paint.Join.MITER //锐角
Paint.Join.Round //圆弧
Paint.Join.BEVEL //直线
这里取Round
,该值的处理方式是以点T
为圆心、指示条高度的一半为半径画圆弧,衔接角落,如图:
至此,指示条的整体高度就确认了,便是QH
的长度,即ST+指示条高度
。
实现
首先给指示条指定一个最大可曲折的高度值bendingHeight
,当时曲折的份额为bendingRatio
。
-
onMeasure()
测量宽高:
- 当曲折份额等于0时,测量高度便是指示条高度
- 当曲折份额大于0时,测量高度便是指示条高度+曲折高度
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int hMode = MeasureSpec.getMode(heightMeasureSpec);
int hSize = MeasureSpec.getSize(heightMeasureSpec);
int height;
if (hMode == MeasureSpec.EXACTLY) {
height = hSize;
} else {
if (bendingRatio <= 0) {
height = barHeight + getPaddingTop() + getPaddingBottom();
} else {
int h = (int) (barHeight + bendingHeight * bendingRatio);
height = Math.min(h + getPaddingTop() + getPaddingBottom(), hSize);
}
}
setMeasuredDimension(width, height);
}
-
onDraw()
制作,
- 当曲折份额等于0时,制作圆角矩形即可
- 当曲折份额大于0时,先运用
Path
制作箭头,再制作两端的圆
@Override
protected void onDraw(Canvas canvas) {
float radius = barHeight / 2f;
if (bendingRatio <= 0) {
rectF.set(getPaddingLeft(), getPaddingTop(),
getWidth() - getPaddingRight(), getPaddingTop() + barHeight);
barPaint.setStyle(Paint.Style.FILL);
canvas.drawRoundRect(rectF, radius, radius, barPaint);
} else {
path.reset();
path.moveTo(getPaddingLeft() + radius, getPaddingTop() + radius);
float x = getPaddingLeft() + (getWidth() - getPaddingLeft() - getPaddingRight()) / 2f;
float y = getPaddingTop() + barHeight / 2f + bendingHeight * bendingRatio;
path.lineTo(x, y);
path.lineTo(getWidth() - getPaddingRight() - radius, getPaddingTop() + radius);
barPaint.setStyle(Paint.Style.STROKE);
canvas.drawPath(path, barPaint);
canvas.drawCircle(getPaddingLeft() + radius, getPaddingTop() + radius,
radius, circlePaint);
canvas.drawCircle(getWidth() - getPaddingRight() - radius, getPaddingTop() + radius,
radius, circlePaint);
}
}
最终只需要调用setBendingRatio()
办法实时更改曲折份额即可。
效果
到这里文章就水完了,有写的欠好的地方还请指出。 参阅衔接:SlidingIndicatorBar-项目地址