先看一下读书APP的效果:

【Android自定义View实战01】仿微信读书APP滑动指示条

弹窗往下滑动时,顶部的指示条也会跟着向下曲折变成箭头形状。

剖析

话不多说,先来给指示条做个X光查看看看:

【Android自定义View实战01】仿微信读书APP滑动指示条

  1. 未滑动时指示条便是一个一般的圆角矩形
  2. 滑动时是一个箭头,箭头的两端是两个圆

指示条从点S滑动到点T过程中,圆L圆K的切线相交构成箭头。箭头通过Path圆心L点T圆心K衔接起来,角落处还需要处理为圆角,可以运用PaintsetStrokeJoin()办法,该办法设置线段衔接处的款式,取值有三个:

Paint.Join.MITER //锐角  
Paint.Join.Round //圆弧  
Paint.Join.BEVEL //直线

这里取Round,该值的处理方式是以点T为圆心、指示条高度的一半为半径画圆弧,衔接角落,如图:

【Android自定义View实战01】仿微信读书APP滑动指示条
【Android自定义View实战01】仿微信读书APP滑动指示条
至此,指示条的整体高度就确认了,便是QH的长度,即ST+指示条高度

实现

首先给指示条指定一个最大可曲折的高度值bendingHeight,当时曲折的份额为bendingRatio

  • onMeasure()测量宽高:
  1. 当曲折份额等于0时,测量高度便是指示条高度
  2. 当曲折份额大于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()制作,
  1. 当曲折份额等于0时,制作圆角矩形即可
  2. 当曲折份额大于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()办法实时更改曲折份额即可。

效果

【Android自定义View实战01】仿微信读书APP滑动指示条

到这里文章就水完了,有写的欠好的地方还请指出。 参阅衔接:SlidingIndicatorBar-项目地址